<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstddef>
#include <cstring>
#include <memory>

#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/io_export.hpp"

namespace caf::io::network {

/// A container that does not call constructors and destructors for its values.
class CAF_IO_EXPORT receive_buffer {
public:
  using value_type = char;
  using size_type = size_t;
  using difference_type = std::ptrdiff_t;
  using reference = value_type&;
  using const_reference = const value_type&;
  using pointer = value_type*;
  using const_pointer = std::pointer_traits<pointer>::rebind<const value_type>;
  using iterator = pointer;
  using const_iterator = const_pointer;
  using reverse_iterator = std::reverse_iterator<iterator>;
  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  using buffer_ptr
    = std::unique_ptr<value_type[], std::default_delete<value_type[]>>;

  /// Create an empty container.
  receive_buffer() noexcept;

  /// Create an empty container of size `count`. Data in the storage is not
  /// initialized.
  receive_buffer(size_t count);

  /// Move constructor.
  receive_buffer(receive_buffer&& other) noexcept;

  /// Copy constructor.
  receive_buffer(const receive_buffer& other);

  /// Move assignment operator.
  receive_buffer& operator=(receive_buffer&& other) noexcept;

  /// Copy assignment operator.
  receive_buffer& operator=(const receive_buffer& other);

  /// Returns a pointer to the underlying buffer.
  pointer data() noexcept {
    return buffer_.get();
  }

  /// Returns a const pointer to the data.
  const_pointer data() const noexcept {
    return buffer_.get();
  }

  /// Returns the number of stored elements.
  size_type size() const noexcept {
    return size_;
  }

  /// Returns the number of elements that the container has allocated space for.
  size_type capacity() const noexcept {
    return capacity_;
  }

  /// Returns the maximum possible number of elements the container
  /// could theoretically hold.
  size_type max_size() const noexcept {
    return std::numeric_limits<size_t>::max();
  }

  /// Resize the container to `new_size`. While this may increase its storage,
  /// no storage will be released.
  void resize(size_type new_size);

  /// Set the size of the storage to `new_size`. If `new_size` is smaller than
  /// the current capacity nothing happens. If `new_size` is larger than the
  /// current capacity all iterators are invalidated.
  void reserve(size_type new_size);

  /// Shrink the container to its current size.
  void shrink_to_fit();

  /// Check if the container is empty.
  bool empty() const noexcept {
    return size_ == 0;
  }

  /// Clears the content of the container and releases the allocated storage.
  void clear();

  /// Swap contents with `other` receive buffer.
  void swap(receive_buffer& other) noexcept;

  /// Returns an iterator to the beginning.
  iterator begin() noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  iterator end() noexcept {
    return buffer_.get() + size_;
  }

  /// Returns an iterator to the beginning.
  const_iterator begin() const noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  const_iterator end() const noexcept {
    return buffer_.get() + size_;
  }

  /// Returns an iterator to the beginning.
  const_iterator cbegin() const noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  const_iterator cend() const noexcept {
    return buffer_.get() + size_;
  }

  /// Returns jan iterator to the reverse beginning.
  reverse_iterator rbegin() noexcept {
    return reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  reverse_iterator rend() noexcept {
    return reverse_iterator{buffer_.get()};
  }

  /// Returns an iterator to the reverse beginning.
  const_reverse_iterator rbegin() const noexcept {
    return const_reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  const_reverse_iterator rend() const noexcept {
    return const_reverse_iterator{buffer_.get()};
  }

  /// Returns an iterator to the reverse beginning.
  const_reverse_iterator crbegin() const noexcept {
    return const_reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  const_reverse_iterator crend() const noexcept {
    return const_reverse_iterator{buffer_.get()};
  }

  /// Insert `value` before `pos`.
  iterator insert(iterator pos, value_type value);

  /// Insert `value` before `pos`.
  template <class InputIterator>
  iterator insert(iterator pos, InputIterator first, InputIterator last) {
    auto n = std::distance(first, last);
    if (n == 0)
      return pos;
    auto offset = static_cast<size_t>(std::distance(begin(), pos));
    auto old_size = size_;
    resize(old_size + static_cast<size_t>(n));
    pos = begin() + offset;
    if (offset != old_size) {
      memmove(pos + n, pos, old_size - offset);
    }
    return std::copy(first, last, pos);
  }

  /// Append `value`.
  void push_back(value_type value);

private:
  // Increse the buffer capacity, maintaining its data. May invalidate
  // iterators.
  void increase_by(size_t bytes);

  // Reduce the buffer capacity, maintaining its data. May invalidate iterators.
  void shrink_by(size_t bytes);

  buffer_ptr buffer_;
  size_type capacity_;
  size_type size_;
};

} // namespace caf::io::network
<commit_msg>Add missing include<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstddef>
#include <cstring>
#include <limits>
#include <memory>

#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/io_export.hpp"

namespace caf::io::network {

/// A container that does not call constructors and destructors for its values.
class CAF_IO_EXPORT receive_buffer {
public:
  using value_type = char;
  using size_type = size_t;
  using difference_type = std::ptrdiff_t;
  using reference = value_type&;
  using const_reference = const value_type&;
  using pointer = value_type*;
  using const_pointer = std::pointer_traits<pointer>::rebind<const value_type>;
  using iterator = pointer;
  using const_iterator = const_pointer;
  using reverse_iterator = std::reverse_iterator<iterator>;
  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  using buffer_ptr
    = std::unique_ptr<value_type[], std::default_delete<value_type[]>>;

  /// Create an empty container.
  receive_buffer() noexcept;

  /// Create an empty container of size `count`. Data in the storage is not
  /// initialized.
  receive_buffer(size_t count);

  /// Move constructor.
  receive_buffer(receive_buffer&& other) noexcept;

  /// Copy constructor.
  receive_buffer(const receive_buffer& other);

  /// Move assignment operator.
  receive_buffer& operator=(receive_buffer&& other) noexcept;

  /// Copy assignment operator.
  receive_buffer& operator=(const receive_buffer& other);

  /// Returns a pointer to the underlying buffer.
  pointer data() noexcept {
    return buffer_.get();
  }

  /// Returns a const pointer to the data.
  const_pointer data() const noexcept {
    return buffer_.get();
  }

  /// Returns the number of stored elements.
  size_type size() const noexcept {
    return size_;
  }

  /// Returns the number of elements that the container has allocated space for.
  size_type capacity() const noexcept {
    return capacity_;
  }

  /// Returns the maximum possible number of elements the container
  /// could theoretically hold.
  size_type max_size() const noexcept {
    return std::numeric_limits<size_t>::max();
  }

  /// Resize the container to `new_size`. While this may increase its storage,
  /// no storage will be released.
  void resize(size_type new_size);

  /// Set the size of the storage to `new_size`. If `new_size` is smaller than
  /// the current capacity nothing happens. If `new_size` is larger than the
  /// current capacity all iterators are invalidated.
  void reserve(size_type new_size);

  /// Shrink the container to its current size.
  void shrink_to_fit();

  /// Check if the container is empty.
  bool empty() const noexcept {
    return size_ == 0;
  }

  /// Clears the content of the container and releases the allocated storage.
  void clear();

  /// Swap contents with `other` receive buffer.
  void swap(receive_buffer& other) noexcept;

  /// Returns an iterator to the beginning.
  iterator begin() noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  iterator end() noexcept {
    return buffer_.get() + size_;
  }

  /// Returns an iterator to the beginning.
  const_iterator begin() const noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  const_iterator end() const noexcept {
    return buffer_.get() + size_;
  }

  /// Returns an iterator to the beginning.
  const_iterator cbegin() const noexcept {
    return buffer_.get();
  }

  /// Returns an iterator to the end.
  const_iterator cend() const noexcept {
    return buffer_.get() + size_;
  }

  /// Returns jan iterator to the reverse beginning.
  reverse_iterator rbegin() noexcept {
    return reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  reverse_iterator rend() noexcept {
    return reverse_iterator{buffer_.get()};
  }

  /// Returns an iterator to the reverse beginning.
  const_reverse_iterator rbegin() const noexcept {
    return const_reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  const_reverse_iterator rend() const noexcept {
    return const_reverse_iterator{buffer_.get()};
  }

  /// Returns an iterator to the reverse beginning.
  const_reverse_iterator crbegin() const noexcept {
    return const_reverse_iterator{buffer_.get() + size_};
  }

  /// Returns an iterator to the reverse end of the data.
  const_reverse_iterator crend() const noexcept {
    return const_reverse_iterator{buffer_.get()};
  }

  /// Insert `value` before `pos`.
  iterator insert(iterator pos, value_type value);

  /// Insert `value` before `pos`.
  template <class InputIterator>
  iterator insert(iterator pos, InputIterator first, InputIterator last) {
    auto n = std::distance(first, last);
    if (n == 0)
      return pos;
    auto offset = static_cast<size_t>(std::distance(begin(), pos));
    auto old_size = size_;
    resize(old_size + static_cast<size_t>(n));
    pos = begin() + offset;
    if (offset != old_size) {
      memmove(pos + n, pos, old_size - offset);
    }
    return std::copy(first, last, pos);
  }

  /// Append `value`.
  void push_back(value_type value);

private:
  // Increse the buffer capacity, maintaining its data. May invalidate
  // iterators.
  void increase_by(size_t bytes);

  // Reduce the buffer capacity, maintaining its data. May invalidate iterators.
  void shrink_by(size_t bytes);

  buffer_ptr buffer_;
  size_type capacity_;
  size_type size_;
};

} // namespace caf::io::network
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-443271.
//
// This file is part of the GLVis visualization tool and library. For more
// information and source code availability see https://glvis.org.
//
// GLVis is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "visual.hpp"
#include "palettes.hpp"
#include "stream_reader.hpp"
#include <SDL2/SDL_hints.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>

std::string plot_caption;
std::string extra_caption; // used in extern context
mfem::GeometryRefiner GLVisGeometryRefiner; // used in extern context

static VisualizationSceneScalarData * vs = nullptr;

namespace js
{

using namespace mfem;

// Replace a given VectorFiniteElement-based grid function (e.g. from a Nedelec
// or Raviart-Thomas space) with a discontinuous piece-wise polynomial Cartesian
// product vector grid function of the same order.
GridFunction *ProjectVectorFEGridFunction(GridFunction *gf)
{
   if ((gf->VectorDim() == 3) && (gf->FESpace()->GetVDim() == 1))
   {
      int p = gf->FESpace()->GetOrder(0);
      cout << "Switching to order " << p
           << " discontinuous vector grid function..." << endl;
      int dim = gf->FESpace()->GetMesh()->Dimension();
      FiniteElementCollection *d_fec = new L2_FECollection(p, dim, 1);
      FiniteElementSpace *d_fespace =
         new FiniteElementSpace(gf->FESpace()->GetMesh(), d_fec, 3);
      GridFunction *d_gf = new GridFunction(d_fespace);
      d_gf->MakeOwner(d_fec);
      gf->ProjectVectorFieldOn(*d_gf);
      delete gf;
      return d_gf;
   }
   return gf;
}

bool startVisualization(const std::string input, const std::string data_type,
                        int w, int h)
{
   std::stringstream ss(input);

   // 0 - scalar data, 1 - vector data, 2 - mesh only, (-1) - unknown
   const int field_type = ReadStream(ss, data_type);

   // reset antialiasing
   GetAppWindow()->getRenderer().setAntialiasing(0);

   std::string line;
   while (ss >> line)
   {
      if (line == "keys")
      {
         std::cout << "parsing 'keys'" << std::endl;
         ss >> stream_state.keys;
      }
      else
      {
         std::cout << "unknown line '" << line << "'" << std::endl;
      }
   }

   if (field_type < 0 || field_type > 2)
   {
      return false;
   }

   if (InitVisualization("glvis", 0, 0, w, h))
   {
      return false;
   }

   delete vs;
   vs = nullptr;

   double mesh_range = -1.0;
   if (field_type == 0 || field_type == 2)
   {
      if (stream_state.grid_f)
      {
         stream_state.grid_f->GetNodalValues(stream_state.sol);
      }
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         VisualizationSceneSolution * vss;
         if (stream_state.normals.Size() > 0)
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol,
                                                      &stream_state.normals);
         }
         else
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol);
         }
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(*stream_state.grid_f);
         }
         if (field_type == 2)
         {
            vs->OrthogonalProjection = 1;
            vs->SetLight(0);
            vs->Zoom(1.8);
            // Use the 'bone' palette when visualizing a 2D mesh only (otherwise
            // the 'jet-like' palette is used in 2D, see vssolution.cpp).
            paletteSet(4);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         VisualizationSceneSolution3d * vss;
         vs = vss = new VisualizationSceneSolution3d(*stream_state.mesh,
                                                     stream_state.sol);
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(stream_state.grid_f);
         }
         if (field_type == 2)
         {
            if (stream_state.mesh->Dimension() == 3)
            {
               // Use the 'white' palette when visualizing a 3D volume mesh only
               // paletteSet(4);
               paletteSet(11);
               vss->SetLightMatIdx(4);
            }
            else
            {
               // Use the 'bone' palette when visualizing a surface mesh only
               // (the same as when visualizing a 2D mesh only)
               paletteSet(4);
            }
            // Otherwise, the 'vivid' palette is used in 3D see vssolution3d.cpp

            vss->ToggleDrawAxes();
            vss->ToggleDrawMesh();
         }
      }
      if (field_type == 2)
      {
         if (stream_state.grid_f)
         {
            mesh_range = stream_state.grid_f->Max() + 1.0;
         }
         else
         {
            mesh_range = stream_state.sol.Max() + 1.0;
         }
      }
   }
   else if (field_type == 1)
   {
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         if (stream_state.grid_f)
         {
            vs = new VisualizationSceneVector(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector(*stream_state.mesh, stream_state.solu,
                                              stream_state.solv);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         if (stream_state.grid_f)
         {
            stream_state.grid_f = ProjectVectorFEGridFunction(stream_state.grid_f);
            vs = new VisualizationSceneVector3d(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector3d(*stream_state.mesh, stream_state.solu,
                                                stream_state.solv, stream_state.solw);
         }
      }
   }

   if (vs)
   {
      // increase the refinement factors if visualizing a GridFunction
      if (stream_state.grid_f)
      {
         vs->AutoRefine();
         vs->SetShading(2, true);
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
         vs->SetAutoscale(0);
      }
      if (stream_state.mesh->SpaceDimension() == 2 && field_type == 2)
      {
         SetVisualizationScene(vs, 2);
      }
      else
      {
         SetVisualizationScene(vs, 3);
      }
   }

   CallKeySequence(stream_state.keys.c_str());

   SendExposeEvent();
   return true;
}

int updateVisualization(std::string data_type, std::string stream)
{
   std::stringstream ss(stream);

   if (data_type != "solution")
   {
      std::cerr << "unsupported data type '" << data_type << "' for stream update" <<
                std::endl;
      return 1;
   }

   auto * new_m = new Mesh(ss, 1, 0, stream_state.fix_elem_orient);
   auto * new_g = new GridFunction(new_m, ss);
   double mesh_range = -1.0;

   if (new_m->SpaceDimension() == stream_state.mesh->SpaceDimension() &&
       new_g->VectorDim() == stream_state.grid_f->VectorDim())
   {
      if (new_m->SpaceDimension() == 2)
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution *vss =
               dynamic_cast<VisualizationSceneSolution *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            VisualizationSceneVector *vsv =
               dynamic_cast<VisualizationSceneVector *>(vs);
            vsv->NewMeshAndSolution(*new_g);
         }
      }
      else
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution3d *vss =
               dynamic_cast<VisualizationSceneSolution3d *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            new_g = ProjectVectorFEGridFunction(new_g);
            VisualizationSceneVector3d *vss =
               dynamic_cast<VisualizationSceneVector3d *>(vs);
            vss->NewMeshAndSolution(new_m, new_g);
         }
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
      }

      delete stream_state.grid_f;
      stream_state.grid_f = new_g;
      delete stream_state.mesh;
      stream_state.mesh = new_m;

      SendExposeEvent();
      return 0;
   }
   else
   {
      cout << "Stream: field type does not match!" << endl;
      delete new_g;
      delete new_m;
      return 1;
   }
}

void iterVisualization()
{
   GetAppWindow()->mainIter();
}

void setCanvasId(const std::string & id)
{
   std::cout << "glvis: setting canvas id to " << id << std::endl;
   GetAppWindow()->setCanvasId(id);
}

void disableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_DISABLE);
   SDL_EventState(SDL_KEYUP, SDL_DISABLE);
}

void enableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
   SDL_EventState(SDL_KEYUP, SDL_ENABLE);
}

void setKeyboardListeningElementId(const std::string & id)
{
   SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, id.c_str());
}

void setupResizeEventCallback(const std::string & id)
{
   // typedef EM_BOOL (*em_ui_callback_func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
   std::cout << "glvis: adding resize callback for " << id << std::endl;
   auto err = emscripten_set_resize_callback(id.c_str(), nullptr,
                                             true, [](int eventType, const EmscriptenUiEvent *uiEvent,
                                                      void *userData) -> EM_BOOL
   {
      std::cout << "got resize event" << std::endl;
      return true;
   });
   // TODO: macro to wrap this
   if (err != EMSCRIPTEN_RESULT_SUCCESS)
   {
      std::cerr << "error (emscripten_set_resize_callback): " << err << std::endl;
   }
}

std::string getHelpString()
{
   VisualizationSceneScalarData* vss
      = dynamic_cast<VisualizationSceneScalarData*>(GetVisualizationScene());
   return vss->GetHelpString();
}
} // namespace js

namespace em = emscripten;
EMSCRIPTEN_BINDINGS(js_funcs)
{
   em::function("startVisualization", &js::startVisualization);
   em::function("updateVisualization", &js::updateVisualization);
   em::function("iterVisualization", &js::iterVisualization);
   em::function("sendExposeEvent", &SendExposeEvent);
   em::function("disableKeyHanding", &js::disableKeyHandling);
   em::function("enableKeyHandling", &js::enableKeyHandling);
   em::function("setKeyboardListeningElementId",
                js::setKeyboardListeningElementId);
   em::function("getTextureMode", &GetUseTexture);
   em::function("setTextureMode", &SetUseTexture);
   em::function("resizeWindow", &ResizeWindow);
   em::function("setCanvasId", &js::setCanvasId);
   em::function("setupResizeEventCallback", &js::setupResizeEventCallback);
   em::function("getHelpString", &js::getHelpString);
}
<commit_msg>Parse the valuerange command in JS streams<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-443271.
//
// This file is part of the GLVis visualization tool and library. For more
// information and source code availability see https://glvis.org.
//
// GLVis is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "visual.hpp"
#include "palettes.hpp"
#include "stream_reader.hpp"
#include <SDL2/SDL_hints.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>

std::string plot_caption;
std::string extra_caption; // used in extern context
mfem::GeometryRefiner GLVisGeometryRefiner; // used in extern context

static VisualizationSceneScalarData * vs = nullptr;

namespace js
{

using namespace mfem;

// Replace a given VectorFiniteElement-based grid function (e.g. from a Nedelec
// or Raviart-Thomas space) with a discontinuous piece-wise polynomial Cartesian
// product vector grid function of the same order.
GridFunction *ProjectVectorFEGridFunction(GridFunction *gf)
{
   if ((gf->VectorDim() == 3) && (gf->FESpace()->GetVDim() == 1))
   {
      int p = gf->FESpace()->GetOrder(0);
      cout << "Switching to order " << p
           << " discontinuous vector grid function..." << endl;
      int dim = gf->FESpace()->GetMesh()->Dimension();
      FiniteElementCollection *d_fec = new L2_FECollection(p, dim, 1);
      FiniteElementSpace *d_fespace =
         new FiniteElementSpace(gf->FESpace()->GetMesh(), d_fec, 3);
      GridFunction *d_gf = new GridFunction(d_fespace);
      d_gf->MakeOwner(d_fec);
      gf->ProjectVectorFieldOn(*d_gf);
      delete gf;
      return d_gf;
   }
   return gf;
}

bool startVisualization(const std::string input, const std::string data_type,
                        int w, int h)
{
   std::stringstream ss(input);

   // 0 - scalar data, 1 - vector data, 2 - mesh only, (-1) - unknown
   const int field_type = ReadStream(ss, data_type);

   // reset antialiasing
   GetAppWindow()->getRenderer().setAntialiasing(0);

   std::string line;
   double minv = 0.0, maxv = 0.0;
   while (ss >> line)
   {
      if (line == "keys")
      {
         std::cout << "parsing 'keys'" << std::endl;
         ss >> stream_state.keys;
      }
      else if (line == "valuerange")
      {
         std::cout << "parsing 'valuerange'" << std::endl;
         ss >> minv >> maxv;
      }
      else
      {
         std::cout << "unknown line '" << line << "'" << std::endl;
      }
   }

   if (field_type < 0 || field_type > 2)
   {
      return false;
   }

   if (InitVisualization("glvis", 0, 0, w, h))
   {
      return false;
   }

   delete vs;
   vs = nullptr;

   double mesh_range = -1.0;
   if (field_type == 0 || field_type == 2)
   {
      if (stream_state.grid_f)
      {
         stream_state.grid_f->GetNodalValues(stream_state.sol);
      }
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         VisualizationSceneSolution * vss;
         if (stream_state.normals.Size() > 0)
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol,
                                                      &stream_state.normals);
         }
         else
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol);
         }
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(*stream_state.grid_f);
         }
         if (field_type == 2)
         {
            vs->OrthogonalProjection = 1;
            vs->SetLight(0);
            vs->Zoom(1.8);
            // Use the 'bone' palette when visualizing a 2D mesh only (otherwise
            // the 'jet-like' palette is used in 2D, see vssolution.cpp).
            paletteSet(4);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         VisualizationSceneSolution3d * vss;
         vs = vss = new VisualizationSceneSolution3d(*stream_state.mesh,
                                                     stream_state.sol);
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(stream_state.grid_f);
         }
         if (field_type == 2)
         {
            if (stream_state.mesh->Dimension() == 3)
            {
               // Use the 'white' palette when visualizing a 3D volume mesh only
               // paletteSet(4);
               paletteSet(11);
               vss->SetLightMatIdx(4);
            }
            else
            {
               // Use the 'bone' palette when visualizing a surface mesh only
               // (the same as when visualizing a 2D mesh only)
               paletteSet(4);
            }
            // Otherwise, the 'vivid' palette is used in 3D see vssolution3d.cpp

            vss->ToggleDrawAxes();
            vss->ToggleDrawMesh();
         }
      }
      if (field_type == 2)
      {
         if (stream_state.grid_f)
         {
            mesh_range = stream_state.grid_f->Max() + 1.0;
         }
         else
         {
            mesh_range = stream_state.sol.Max() + 1.0;
         }
      }
   }
   else if (field_type == 1)
   {
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         if (stream_state.grid_f)
         {
            vs = new VisualizationSceneVector(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector(*stream_state.mesh, stream_state.solu,
                                              stream_state.solv);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         if (stream_state.grid_f)
         {
            stream_state.grid_f = ProjectVectorFEGridFunction(stream_state.grid_f);
            vs = new VisualizationSceneVector3d(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector3d(*stream_state.mesh, stream_state.solu,
                                                stream_state.solv, stream_state.solw);
         }
      }
   }

   if (vs)
   {
      // increase the refinement factors if visualizing a GridFunction
      if (stream_state.grid_f)
      {
         vs->AutoRefine();
         vs->SetShading(2, true);
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
         vs->SetAutoscale(0);
      }
      if (stream_state.mesh->SpaceDimension() == 2 && field_type == 2)
      {
         SetVisualizationScene(vs, 2);
      }
      else
      {
         SetVisualizationScene(vs, 3);
      }
   }

   CallKeySequence(stream_state.keys.c_str());

   if (minv || maxv)
   {
      vs->SetValueRange(minv, maxv);
   }

   SendExposeEvent();
   return true;
}

int updateVisualization(std::string data_type, std::string stream)
{
   std::stringstream ss(stream);

   if (data_type != "solution")
   {
      std::cerr << "unsupported data type '" << data_type << "' for stream update" <<
                std::endl;
      return 1;
   }

   auto * new_m = new Mesh(ss, 1, 0, stream_state.fix_elem_orient);
   auto * new_g = new GridFunction(new_m, ss);
   double mesh_range = -1.0;

   if (new_m->SpaceDimension() == stream_state.mesh->SpaceDimension() &&
       new_g->VectorDim() == stream_state.grid_f->VectorDim())
   {
      if (new_m->SpaceDimension() == 2)
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution *vss =
               dynamic_cast<VisualizationSceneSolution *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            VisualizationSceneVector *vsv =
               dynamic_cast<VisualizationSceneVector *>(vs);
            vsv->NewMeshAndSolution(*new_g);
         }
      }
      else
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution3d *vss =
               dynamic_cast<VisualizationSceneSolution3d *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            new_g = ProjectVectorFEGridFunction(new_g);
            VisualizationSceneVector3d *vss =
               dynamic_cast<VisualizationSceneVector3d *>(vs);
            vss->NewMeshAndSolution(new_m, new_g);
         }
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
      }

      delete stream_state.grid_f;
      stream_state.grid_f = new_g;
      delete stream_state.mesh;
      stream_state.mesh = new_m;

      SendExposeEvent();
      return 0;
   }
   else
   {
      cout << "Stream: field type does not match!" << endl;
      delete new_g;
      delete new_m;
      return 1;
   }
}

void iterVisualization()
{
   GetAppWindow()->mainIter();
}

void setCanvasId(const std::string & id)
{
   std::cout << "glvis: setting canvas id to " << id << std::endl;
   GetAppWindow()->setCanvasId(id);
}

void disableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_DISABLE);
   SDL_EventState(SDL_KEYUP, SDL_DISABLE);
}

void enableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
   SDL_EventState(SDL_KEYUP, SDL_ENABLE);
}

void setKeyboardListeningElementId(const std::string & id)
{
   SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, id.c_str());
}

void setupResizeEventCallback(const std::string & id)
{
   // typedef EM_BOOL (*em_ui_callback_func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
   std::cout << "glvis: adding resize callback for " << id << std::endl;
   auto err = emscripten_set_resize_callback(id.c_str(), nullptr,
                                             true, [](int eventType, const EmscriptenUiEvent *uiEvent,
                                                      void *userData) -> EM_BOOL
   {
      std::cout << "got resize event" << std::endl;
      return true;
   });
   // TODO: macro to wrap this
   if (err != EMSCRIPTEN_RESULT_SUCCESS)
   {
      std::cerr << "error (emscripten_set_resize_callback): " << err << std::endl;
   }
}

std::string getHelpString()
{
   VisualizationSceneScalarData* vss
      = dynamic_cast<VisualizationSceneScalarData*>(GetVisualizationScene());
   return vss->GetHelpString();
}
} // namespace js

namespace em = emscripten;
EMSCRIPTEN_BINDINGS(js_funcs)
{
   em::function("startVisualization", &js::startVisualization);
   em::function("updateVisualization", &js::updateVisualization);
   em::function("iterVisualization", &js::iterVisualization);
   em::function("sendExposeEvent", &SendExposeEvent);
   em::function("disableKeyHanding", &js::disableKeyHandling);
   em::function("enableKeyHandling", &js::enableKeyHandling);
   em::function("setKeyboardListeningElementId",
                js::setKeyboardListeningElementId);
   em::function("getTextureMode", &GetUseTexture);
   em::function("setTextureMode", &SetUseTexture);
   em::function("resizeWindow", &ResizeWindow);
   em::function("setCanvasId", &js::setCanvasId);
   em::function("setupResizeEventCallback", &js::setupResizeEventCallback);
   em::function("getHelpString", &js::getHelpString);
}
<|endoftext|>


<commit_before>/* +---------------------------------------------------------------------------+
   |                 The Mobile Robot Programming Toolkit (MRPT)               |
   |                                                                           |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2013, Individual contributors, see AUTHORS file        |
   | Copyright (c) 2005-2013, MAPIR group, University of Malaga                |
   | Copyright (c) 2012-2013, University of Almeria                            |
   | All rights reserved.                                                      |
   |                                                                           |
   | Redistribution and use in source and binary forms, with or without        |
   | modification, are permitted provided that the following conditions are    |
   | met:                                                                      |
   |    * Redistributions of source code must retain the above copyright       |
   |      notice, this list of conditions and the following disclaimer.        |
   |    * Redistributions in binary form must reproduce the above copyright    |
   |      notice, this list of conditions and the following disclaimer in the  |
   |      documentation and/or other materials provided with the distribution. |
   |    * Neither the name of the copyright holders nor the                    |
   |      names of its contributors may be used to endorse or promote products |
   |      derived from this software without specific prior written permission.|
   |                                                                           |
   | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       |
   | 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
   | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR|
   | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE |
   | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL|
   | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR|
   |  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)       |
   | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       |
   | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  |
   | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           |
   | POSSIBILITY OF SUCH DAMAGE.                                               |
   +---------------------------------------------------------------------------+ */

#include <mrpt/base.h>  // Precompiled headers

#include <mrpt/utils/CDebugOutputCapable.h>
#include <mrpt/system/memory.h>

#ifdef MRPT_OS_WINDOWS
	#define WIN32_LEAN_AND_MEAN
	#include <windows.h>
#endif

#include <cstdarg>
#include <iostream>

using namespace mrpt::utils;
using namespace mrpt::system;

/*---------------------------------------------------------------
					printf_debug
 ---------------------------------------------------------------*/
void CDebugOutputCapable::printf_debug( const char *fmt, ... )
{
	if (!fmt) return;

	int   result = -1, length = 1024;
	std::vector<char> buffer;
	while (result == -1)
	{
		buffer.resize(length + 10);

		va_list args;  // This must be done WITHIN the loop
		va_start(args,fmt);
		result = os::vsnprintf(&buffer[0], length, fmt, args);
		va_end(args);

		// Truncated?
		if (result>=length) result=-1;
		length*=2;
	}

	// Output:
	std::cout << &buffer[0];

#ifdef MRPT_OS_WINDOWS
	OutputDebugStringA(&buffer[0]);
#endif
}
<commit_msg>CDebugOutputCapable: enable Output to MSVC out window only when compiling in MSVC<commit_after>/* +---------------------------------------------------------------------------+
   |                 The Mobile Robot Programming Toolkit (MRPT)               |
   |                                                                           |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2013, Individual contributors, see AUTHORS file        |
   | Copyright (c) 2005-2013, MAPIR group, University of Malaga                |
   | Copyright (c) 2012-2013, University of Almeria                            |
   | All rights reserved.                                                      |
   |                                                                           |
   | Redistribution and use in source and binary forms, with or without        |
   | modification, are permitted provided that the following conditions are    |
   | met:                                                                      |
   |    * Redistributions of source code must retain the above copyright       |
   |      notice, this list of conditions and the following disclaimer.        |
   |    * Redistributions in binary form must reproduce the above copyright    |
   |      notice, this list of conditions and the following disclaimer in the  |
   |      documentation and/or other materials provided with the distribution. |
   |    * Neither the name of the copyright holders nor the                    |
   |      names of its contributors may be used to endorse or promote products |
   |      derived from this software without specific prior written permission.|
   |                                                                           |
   | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       |
   | 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
   | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR|
   | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE |
   | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL|
   | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR|
   |  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)       |
   | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       |
   | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  |
   | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           |
   | POSSIBILITY OF SUCH DAMAGE.                                               |
   +---------------------------------------------------------------------------+ */

#include <mrpt/base.h>  // Precompiled headers

#include <mrpt/utils/CDebugOutputCapable.h>
#include <mrpt/system/memory.h>

#ifdef MRPT_OS_WINDOWS
	#define WIN32_LEAN_AND_MEAN
	#include <windows.h>
#endif

#include <cstdarg>
#include <iostream>

using namespace mrpt::utils;
using namespace mrpt::system;

/*---------------------------------------------------------------
					printf_debug
 ---------------------------------------------------------------*/
void CDebugOutputCapable::printf_debug( const char *fmt, ... )
{
	if (!fmt) return;

	int   result = -1, length = 1024;
	std::vector<char> buffer;
	while (result == -1)
	{
		buffer.resize(length + 10);

		va_list args;  // This must be done WITHIN the loop
		va_start(args,fmt);
		result = os::vsnprintf(&buffer[0], length, fmt, args);
		va_end(args);

		// Truncated?
		if (result>=length) result=-1;
		length*=2;
	}

	// Output:
	std::cout << &buffer[0];

#ifdef _MSC_VER
	OutputDebugStringA(&buffer[0]);
#endif
}
<|endoftext|>


<commit_before>//
// LookupTable takes PolyData as input
//
#ifndef __vlLookupTable_h
#define __vlLookupTable_h

#include "Object.hh"
#include "RGBArray.hh"

class vlLookupTable : public vlObject
{
public:
  vlLookupTable();
  int Initialize(const int sz=256, const int ext=256);
  int GetTableSize();
  void Build();

  vlSetVector2Macro(TableRange,float);
  vlGetVectorMacro(TableRange,float);

  vlSetVector2Macro(HueRange,float);
  vlGetVectorMacro(HueRange,float);

  vlSetVector2Macro(SaturationRange,float);
  vlGetVectorMacro(SaturationRange,float);

  vlSetVector2Macro(ValueRange,float);
  vlGetVectorMacro(ValueRange,float);

  vlRGBColor &MapValue(float v);
  void SetTableValue (int indx, vlRGBColor &rgb_c);
  vlRGBColor &GetTableValue (int);

protected:
  vlRGBArray Table;
  float TableRange[2];
  float HueRange[2];
  float SaturationRange[2];
  float ValueRange[2];

};

#endif

<commit_msg>ENH: Removed interface using RGBColor.<commit_after>//
// LookupTable takes PolyData as input
//
#ifndef __vlLookupTable_h
#define __vlLookupTable_h

#include "Object.hh"
#include "RGBArray.hh"

class vlLookupTable : public vlObject
{
public:
  vlLookupTable();
  int Initialize(const int sz=256, const int ext=256);
  int GetTableSize();
  void Build();

  vlSetVector2Macro(TableRange,float);
  vlGetVectorMacro(TableRange,float);

  vlSetVector2Macro(HueRange,float);
  vlGetVectorMacro(HueRange,float);

  vlSetVector2Macro(SaturationRange,float);
  vlGetVectorMacro(SaturationRange,float);

  vlSetVector2Macro(ValueRange,float);
  vlGetVectorMacro(ValueRange,float);

  float *MapValue(float v);
  void SetTableValue (int indx, float rgb[3]);
  float *GetTableValue (int);

protected:
  vlRGBArray Table;
  float TableRange[2];
  float HueRange[2];
  float SaturationRange[2];
  float ValueRange[2];

};

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#include <cassert>
#include <cstdlib>
#include <uavcan/global_data_type_registry.hpp>
#include <uavcan/internal/debug.hpp>

namespace uavcan
{

const GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind) const
{
    switch (kind)
    {
    case DataTypeKindMessage: return &msgs_;
    case DataTypeKindService: return &srvs_;
    default:
        assert(0);
        return NULL;
    }
}

GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind)
{
    switch (kind)
    {
    case DataTypeKindMessage: return &msgs_;
    case DataTypeKindService: return &srvs_;
    default:
        assert(0);
        return NULL;
    }
}

GlobalDataTypeRegistry::RegistResult GlobalDataTypeRegistry::remove(Entry* dtd)
{
    if (!dtd)
    {
        assert(0);
        return RegistResultInvalidParams;
    }
    if (isFrozen())
        return RegistResultFrozen;

    List* list = selectList(dtd->descriptor.getKind());
    if (!list)
        return RegistResultInvalidParams;

    list->remove(dtd);       // If this call came from regist<>(), that would be enough
    Entry* p = list->get();  // But anyway
    while (p)
    {
        Entry* const next = p->getNextListNode();
        if (p->descriptor.match(dtd->descriptor.getKind(), dtd->descriptor.getFullName()))
            list->remove(p);
        p = next;
    }
    return RegistResultOk;
}

GlobalDataTypeRegistry::RegistResult GlobalDataTypeRegistry::registImpl(Entry* dtd)
{
    if (!dtd || (dtd->descriptor.getID() > DataTypeID::Max))
    {
        assert(0);
        return RegistResultInvalidParams;
    }
    if (isFrozen())
        return RegistResultFrozen;

    List* list = selectList(dtd->descriptor.getKind());
    if (!list)
        return RegistResultInvalidParams;

    {   // Collision check
        Entry* p = list->get();
        while (p)
        {
            if (p->descriptor.getID() == dtd->descriptor.getID()) // ID collision
                return RegistResultCollision;
            if (!std::strcmp(p->descriptor.getFullName(), dtd->descriptor.getFullName())) // Name collision
                return RegistResultCollision;
            p = p->getNextListNode();
        }
    }
    list->insertBefore(dtd, EntryInsertionComparator(dtd));

#if UAVCAN_DEBUG
    {   // Order check
        Entry* p = list->get();
        int id = -1;
        while (p)
        {
            if (id >= p->descriptor.getID().get())
            {
                assert(0);
                std::abort();
            }
            id = p->descriptor.getID().get();
            p = p->getNextListNode();
        }
    }
#endif
    return RegistResultOk;
}

GlobalDataTypeRegistry& GlobalDataTypeRegistry::instance()
{
    static GlobalDataTypeRegistry inst;
    return inst;
}

void GlobalDataTypeRegistry::freeze()
{
    if (!frozen_)
    {
        frozen_ = true;
        UAVCAN_TRACE("GlobalDataTypeRegistry", "Frozen");
    }
}

const DataTypeDescriptor* GlobalDataTypeRegistry::find(DataTypeKind kind, const char* name) const
{
    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return NULL;
    }
    Entry* p = list->get();
    while (p)
    {
        if (p->descriptor.match(kind, name))
            return &p->descriptor;
        p = p->getNextListNode();
    }
    return NULL;
}

DataTypeSignature GlobalDataTypeRegistry::computeAggregateSignature(DataTypeKind kind,
                                                                    DataTypeIDMask& inout_id_mask) const
{
    assert(isFrozen());  // Computing the signature if the registry is not frozen is pointless

    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return DataTypeSignature();
    }

    int prev_dtid = -1;
    DataTypeSignature signature;
    bool signature_initialized = false;
    Entry* p = list->get();
    while (p)
    {
        const DataTypeDescriptor& desc = p->descriptor;
        const int dtid = desc.getID().get();

        if (inout_id_mask[dtid])
        {
            if (signature_initialized)
                signature.extend(desc.getSignature());
            else
                signature = DataTypeSignature(desc.getSignature());
            signature_initialized = true;
        }

        assert(prev_dtid < dtid);  // Making sure that list is ordered properly
        prev_dtid++;
        while (prev_dtid < dtid)
            inout_id_mask[prev_dtid++] = false; // Erasing bits for missing types
        assert(prev_dtid == dtid);

        p = p->getNextListNode();
    }
    prev_dtid++;
    while (prev_dtid <= DataTypeID::Max)
        inout_id_mask[prev_dtid++] = false;

    return signature;
}

void GlobalDataTypeRegistry::getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const
{
    mask.reset();
    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return;
    }
    Entry* p = list->get();
    while (p)
    {
        assert(p->descriptor.getKind() == kind);
        mask[p->descriptor.getID().get()] = true;
        p = p->getNextListNode();
    }
}

}
<commit_msg>Added logging for GDTR<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#include <cassert>
#include <cstdlib>
#include <uavcan/global_data_type_registry.hpp>
#include <uavcan/internal/debug.hpp>

namespace uavcan
{

const GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind) const
{
    switch (kind)
    {
    case DataTypeKindMessage: return &msgs_;
    case DataTypeKindService: return &srvs_;
    default:
        assert(0);
        return NULL;
    }
}

GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind)
{
    switch (kind)
    {
    case DataTypeKindMessage: return &msgs_;
    case DataTypeKindService: return &srvs_;
    default:
        assert(0);
        return NULL;
    }
}

GlobalDataTypeRegistry::RegistResult GlobalDataTypeRegistry::remove(Entry* dtd)
{
    if (!dtd)
    {
        assert(0);
        return RegistResultInvalidParams;
    }
    if (isFrozen())
        return RegistResultFrozen;

    List* list = selectList(dtd->descriptor.getKind());
    if (!list)
        return RegistResultInvalidParams;

    list->remove(dtd);       // If this call came from regist<>(), that would be enough
    Entry* p = list->get();  // But anyway
    while (p)
    {
        Entry* const next = p->getNextListNode();
        if (p->descriptor.match(dtd->descriptor.getKind(), dtd->descriptor.getFullName()))
            list->remove(p);
        p = next;
    }
    return RegistResultOk;
}

GlobalDataTypeRegistry::RegistResult GlobalDataTypeRegistry::registImpl(Entry* dtd)
{
    if (!dtd || (dtd->descriptor.getID() > DataTypeID::Max))
    {
        assert(0);
        return RegistResultInvalidParams;
    }
    if (isFrozen())
        return RegistResultFrozen;

    List* list = selectList(dtd->descriptor.getKind());
    if (!list)
        return RegistResultInvalidParams;

    {   // Collision check
        Entry* p = list->get();
        while (p)
        {
            if (p->descriptor.getID() == dtd->descriptor.getID()) // ID collision
                return RegistResultCollision;
            if (!std::strcmp(p->descriptor.getFullName(), dtd->descriptor.getFullName())) // Name collision
                return RegistResultCollision;
            p = p->getNextListNode();
        }
    }
    list->insertBefore(dtd, EntryInsertionComparator(dtd));

#if UAVCAN_DEBUG
    {   // Order check
        Entry* p = list->get();
        int id = -1;
        while (p)
        {
            if (id >= p->descriptor.getID().get())
            {
                assert(0);
                std::abort();
            }
            id = p->descriptor.getID().get();
            p = p->getNextListNode();
        }
    }
#endif
    return RegistResultOk;
}

GlobalDataTypeRegistry& GlobalDataTypeRegistry::instance()
{
    static GlobalDataTypeRegistry inst;
    return inst;
}

void GlobalDataTypeRegistry::freeze()
{
    if (!frozen_)
    {
        frozen_ = true;
        UAVCAN_TRACE("GlobalDataTypeRegistry", "Frozen; num msgs: %u, num srvs: %u",
                     getNumMessageTypes(), getNumServiceTypes());
    }
}

const DataTypeDescriptor* GlobalDataTypeRegistry::find(DataTypeKind kind, const char* name) const
{
    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return NULL;
    }
    Entry* p = list->get();
    while (p)
    {
        if (p->descriptor.match(kind, name))
            return &p->descriptor;
        p = p->getNextListNode();
    }
    return NULL;
}

DataTypeSignature GlobalDataTypeRegistry::computeAggregateSignature(DataTypeKind kind,
                                                                    DataTypeIDMask& inout_id_mask) const
{
    assert(isFrozen());  // Computing the signature if the registry is not frozen is pointless

    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return DataTypeSignature();
    }

    int prev_dtid = -1;
    DataTypeSignature signature;
    bool signature_initialized = false;
    Entry* p = list->get();
    while (p)
    {
        const DataTypeDescriptor& desc = p->descriptor;
        const int dtid = desc.getID().get();

        if (inout_id_mask[dtid])
        {
            if (signature_initialized)
                signature.extend(desc.getSignature());
            else
                signature = DataTypeSignature(desc.getSignature());
            signature_initialized = true;
        }

        assert(prev_dtid < dtid);  // Making sure that list is ordered properly
        prev_dtid++;
        while (prev_dtid < dtid)
            inout_id_mask[prev_dtid++] = false; // Erasing bits for missing types
        assert(prev_dtid == dtid);

        p = p->getNextListNode();
    }
    prev_dtid++;
    while (prev_dtid <= DataTypeID::Max)
        inout_id_mask[prev_dtid++] = false;

    return signature;
}

void GlobalDataTypeRegistry::getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const
{
    mask.reset();
    const List* list = selectList(kind);
    if (!list)
    {
        assert(0);
        return;
    }
    Entry* p = list->get();
    while (p)
    {
        assert(p->descriptor.getKind() == kind);
        mask[p->descriptor.getID().get()] = true;
        p = p->getNextListNode();
    }
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Jake Horsfield
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef INI_PARSER_H
#define INI_PARSER_H

#include <map>
#include <string>
#include <vector>
#include <utility>
#include <fstream>
#include <stdexcept>

/*
 * Adds support for functions not available in minGW.
 * http://pastebin.com/KMTd7Xtk#
 */
#ifdef __MINGW32__
namespace std
{
    template <class T> std::string to_string(T val)
    {
        std::stringstream ss;
        ss << val;
        return ss.str();
    }

    int stoi(const std::string& str)
    {
        std::stringstream ss;
        int ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    long stol(const std::string& str)
    {
        std::stringstream ss;
        long ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    float stof(const std::string& str)
    {
        std::stringstream ss;
        float ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    double stod(const std::string& str)
    {
        std::stringstream ss;
        double ret;
        ss << str;
        ss >> ret;
        return ret;
    }
}
#endif // __MINGW32__

class ini_parser
{
    public:
        ini_parser(const std::string& filename)
            : filename(filename)
            , current_section("")
        {
            parse(filename);
        }

        void create_property(const std::string& name, const std::string& value, const std::string& section = "")
        {
            if (name.empty() || value.empty())
            {
                throw std::runtime_error("when creating a property, the name or value cannot be empty");
            }

            if (section.empty())
            {
                create_property_no_section(name, value);
            }
            else
            {
                create_property_in_section(name, value, section);
            }
        }

        /* Writes a new line at the bottom of the file, followed by the start of the section. */
        void create_section(const std::string& name)
        {
            if (name.empty())
            {
                throw std::runtime_error("when creating section, its name cannot be empty");
            }

            std::string line = "\n[" + name + "]";
            input.push_back(line);
            write_input_to_file();
        }

        int get_int(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stoi(sections.at(section).at(name));
        }

        /*
         * The legal values for bools are BOOL_TRUE and BOOL_FALSE.
         * Anything other than these values are illegal.
         */
        bool get_bool(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);

            std::string value = sections.at(section).at(name);
            if (value == BOOL_TRUE)
            {
                return true;
            }
            else if (value == BOOL_FALSE)
            {
                return false;
            }
            else
            {
                throw std::runtime_error("unable to cast to bool");
            }
        }

        long get_long(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stol(sections.at(section).at(name));
        }

        float get_float(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stof(sections.at(section).at(name));
        }

        double get_double(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stod(sections.at(section).at(name));
        }

        std::string get_string(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return sections.at(section).at(name);
        }

        void set_value(const std::string& name, int value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, bool value, const std::string& section = "")
        {
            set_value(name, (value ? BOOL_TRUE : BOOL_FALSE), section);
        }

        void set_value(const std::string& name, long value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, float value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, double value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, const std::string& value, const std::string& section = "")
        {
            ensure_property_exists(section, name);
            sections[section][name] = value;

            bool replaced = false;
            std::string current_section = "";

            /*
             * Note that references to "current_section" refer to the local
             * variable defined above, not the member variable.
             */
            for (int i = 0; i < input.size(); ++i)
            {
                std::string& line = input[i];
                if (is_section_start_line(line))
                {
                    current_section = extract_section_name(line);
                }
                else if (is_assignment_line(line))
                {
                    std::string key = extract_key(line);
                    if (key == name && current_section == section)
                    {
                        line = key;
                        line += "=";
                        line += value;
                        replaced = true;
                    }
                }
            }

            if (replaced)
            {
                write_input_to_file();
            }
            else
            {
                throw std::runtime_error("property does not exist so cannot change its value");
            }
        }

    private:
        void create_property_no_section(const std::string& name, const std::string& value)
        {
            std::string line = name + "=" + value;

            input.insert(input.begin(), line);
            write_input_to_file();

            sections[""][name] = value;
        }

        void create_property_in_section(const std::string& name, const std::string& value, const std::string& section)
        {
            std::string line = name + "=" + value;
            std::string tmp_current_section = "";

            for (auto it = input.begin(); it != input.end(); ++it)
            {
                if (is_section_start_line(*it))
                {
                    tmp_current_section = extract_section_name(*it);

                    if (tmp_current_section == section)
                    {
                        input.insert(it + 1, line);
                        write_input_to_file();
                        sections[section][name] = value;
                        return;
                    }
                }
            }

            /* Section was not found. */
            throw std::runtime_error("unable to create property in section");
        }

        void write_input_to_file()
        {
            std::fstream file(filename);
            for (const std::string& line : input)
            {
                file << line << std::endl;
            }
            file.close();
        }

        void parse(const std::string& filename)
        {
            std::fstream file;
            file.open(filename);
            if (!file.is_open())
            {
                std::printf("error: could not open \"%s\". terminated parsing.\n", filename.c_str());
                file.close();
                return;
            }

            std::string line;
            while (std::getline(file, line))
            {
                input.push_back(line);

                if (is_comment_line(line))
                {
                    continue;
                }
                else if (is_section_start_line(line))
                {
                    start_section(line);
                }
                else if (is_assignment_line(line))
                {
                    handle_assignment(line);
                }
            }
        }

        void start_section(const std::string& line)
        {
            current_section = extract_section_name(line);
        }

        std::string extract_section_name(const std::string& line) const
        {
            std::string name;

            for (int i = 1; line[i] != ']'; ++i)
            {
                name += line[i];
            }

            return name;
        }

        void handle_assignment(const std::string& line)
        {
            std::string key = extract_key(line);
            std::string value = extract_value(line);

            sections[current_section][key] = value;
        }

        std::string extract_key(const std::string& line) const
        {
            std::string key;

            for (int i = 0; line[i] != '='; ++i)
            {
                key += line[i];
            }

            return key;
        }

        std::string extract_value(const std::string& line) const
        {
            std::string value;

            int equals_pos;
            for (equals_pos = 0; line[equals_pos] != '='; ++equals_pos)
            {
                /* Skip to equals sign. */
            }

            /* Get everything from the character following the equals sign to the end of the line. */
            for (int i = equals_pos + 1; i < line.length(); ++i)
            {
                value += line[i];
            }

            return value;
        }

        /*
         * A line is a comment if the first character is a semi-colon.
         */
        bool is_comment_line(const std::string& line) const
        {
            return (line.length() > 0) && (line[0] == ';');
        }

        /*
         * A line is the start of a section if the first character is an open
         * bracket and the last character is a closing bracket.
         */
        bool is_section_start_line(const std::string& line) const
        {
            return (line.length() > 0) && (line[0] == '[') && (line[line.length() - 1] == ']');
        }

        /*
         * A line contains an assignment if it contains an equals sign and
         * there is text before and after this equals sign.
         */
        bool is_assignment_line(const std::string& line) const
        {
            std::size_t equals_pos = line.find("=");
            return (equals_pos != std::string::npos) && (equals_pos != 0) && (equals_pos != line.length() - 1);
        }

        void ensure_property_exists(const std::string& section, const std::string& name) const
        {
            if (section != "" && sections.find(section) == sections.end())
            {
                throw std::runtime_error("section does not exist");
            }

            if (sections.at(section).find(name) == sections.at(section).end())
            {
                throw std::runtime_error("property does not exist");
            }
        }

    private:
        const std::string filename;
        std::vector<std::string> input;

        typedef std::map<std::string, std::string> properties;
        std::map<std::string, properties> sections;

        std::string current_section;

        static constexpr const char* BOOL_TRUE = "TRUE";
        static constexpr const char* BOOL_FALSE = "FALSE";
};

#endif
<commit_msg>Accidently deleted the sstream include<commit_after>/*
 * Copyright (c) 2014 Jake Horsfield
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef INI_PARSER_H
#define INI_PARSER_H

#include <map>
#include <string>
#include <vector>
#include <utility>
#include <sstream>
#include <fstream>
#include <stdexcept>

/*
 * Adds support for functions not available in minGW.
 * http://pastebin.com/KMTd7Xtk#
 */
#ifdef __MINGW32__
namespace std
{
    template <class T> std::string to_string(T val)
    {
        std::stringstream ss;
        ss << val;
        return ss.str();
    }

    int stoi(const std::string& str)
    {
        std::stringstream ss;
        int ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    long stol(const std::string& str)
    {
        std::stringstream ss;
        long ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    float stof(const std::string& str)
    {
        std::stringstream ss;
        float ret;
        ss << str;
        ss >> ret;
        return ret;
    }

    double stod(const std::string& str)
    {
        std::stringstream ss;
        double ret;
        ss << str;
        ss >> ret;
        return ret;
    }
}
#endif // __MINGW32__

class ini_parser
{
    public:
        ini_parser(const std::string& filename)
            : filename(filename)
            , current_section("")
        {
            parse(filename);
        }

        void create_property(const std::string& name, const std::string& value, const std::string& section = "")
        {
            if (name.empty() || value.empty())
            {
                throw std::runtime_error("when creating a property, the name or value cannot be empty");
            }

            if (section.empty())
            {
                create_property_no_section(name, value);
            }
            else
            {
                create_property_in_section(name, value, section);
            }
        }

        /* Writes a new line at the bottom of the file, followed by the start of the section. */
        void create_section(const std::string& name)
        {
            if (name.empty())
            {
                throw std::runtime_error("when creating section, its name cannot be empty");
            }

            std::string line = "\n[" + name + "]";
            input.push_back(line);
            write_input_to_file();
        }

        int get_int(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stoi(sections.at(section).at(name));
        }

        /*
         * The legal values for bools are BOOL_TRUE and BOOL_FALSE.
         * Anything other than these values are illegal.
         */
        bool get_bool(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);

            std::string value = sections.at(section).at(name);
            if (value == BOOL_TRUE)
            {
                return true;
            }
            else if (value == BOOL_FALSE)
            {
                return false;
            }
            else
            {
                throw std::runtime_error("unable to cast to bool");
            }
        }

        long get_long(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stol(sections.at(section).at(name));
        }

        float get_float(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stof(sections.at(section).at(name));
        }

        double get_double(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return std::stod(sections.at(section).at(name));
        }

        std::string get_string(const std::string& name, const std::string& section = "") const
        {
            ensure_property_exists(section, name);
            return sections.at(section).at(name);
        }

        void set_value(const std::string& name, int value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, bool value, const std::string& section = "")
        {
            set_value(name, (value ? BOOL_TRUE : BOOL_FALSE), section);
        }

        void set_value(const std::string& name, long value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, float value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, double value, const std::string& section = "")
        {
            set_value(name, std::to_string(value), section);
        }

        void set_value(const std::string& name, const std::string& value, const std::string& section = "")
        {
            ensure_property_exists(section, name);
            sections[section][name] = value;

            bool replaced = false;
            std::string current_section = "";

            /*
             * Note that references to "current_section" refer to the local
             * variable defined above, not the member variable.
             */
            for (int i = 0; i < input.size(); ++i)
            {
                std::string& line = input[i];
                if (is_section_start_line(line))
                {
                    current_section = extract_section_name(line);
                }
                else if (is_assignment_line(line))
                {
                    std::string key = extract_key(line);
                    if (key == name && current_section == section)
                    {
                        line = key;
                        line += "=";
                        line += value;
                        replaced = true;
                    }
                }
            }

            if (replaced)
            {
                write_input_to_file();
            }
            else
            {
                throw std::runtime_error("property does not exist so cannot change its value");
            }
        }

    private:
        void create_property_no_section(const std::string& name, const std::string& value)
        {
            std::string line = name + "=" + value;

            input.insert(input.begin(), line);
            write_input_to_file();

            sections[""][name] = value;
        }

        void create_property_in_section(const std::string& name, const std::string& value, const std::string& section)
        {
            std::string line = name + "=" + value;
            std::string tmp_current_section = "";

            for (auto it = input.begin(); it != input.end(); ++it)
            {
                if (is_section_start_line(*it))
                {
                    tmp_current_section = extract_section_name(*it);

                    if (tmp_current_section == section)
                    {
                        input.insert(it + 1, line);
                        write_input_to_file();
                        sections[section][name] = value;
                        return;
                    }
                }
            }

            /* Section was not found. */
            throw std::runtime_error("unable to create property in section");
        }

        void write_input_to_file()
        {
            std::fstream file(filename);
            for (const std::string& line : input)
            {
                file << line << std::endl;
            }
            file.close();
        }

        void parse(const std::string& filename)
        {
            std::fstream file;
            file.open(filename);
            if (!file.is_open())
            {
                std::printf("error: could not open \"%s\". terminated parsing.\n", filename.c_str());
                file.close();
                return;
            }

            std::string line;
            while (std::getline(file, line))
            {
                input.push_back(line);

                if (is_comment_line(line))
                {
                    continue;
                }
                else if (is_section_start_line(line))
                {
                    start_section(line);
                }
                else if (is_assignment_line(line))
                {
                    handle_assignment(line);
                }
            }
        }

        void start_section(const std::string& line)
        {
            current_section = extract_section_name(line);
        }

        std::string extract_section_name(const std::string& line) const
        {
            std::string name;

            for (int i = 1; line[i] != ']'; ++i)
            {
                name += line[i];
            }

            return name;
        }

        void handle_assignment(const std::string& line)
        {
            std::string key = extract_key(line);
            std::string value = extract_value(line);

            sections[current_section][key] = value;
        }

        std::string extract_key(const std::string& line) const
        {
            std::string key;

            for (int i = 0; line[i] != '='; ++i)
            {
                key += line[i];
            }

            return key;
        }

        std::string extract_value(const std::string& line) const
        {
            std::string value;

            int equals_pos;
            for (equals_pos = 0; line[equals_pos] != '='; ++equals_pos)
            {
                /* Skip to equals sign. */
            }

            /* Get everything from the character following the equals sign to the end of the line. */
            for (int i = equals_pos + 1; i < line.length(); ++i)
            {
                value += line[i];
            }

            return value;
        }

        /*
         * A line is a comment if the first character is a semi-colon.
         */
        bool is_comment_line(const std::string& line) const
        {
            return (line.length() > 0) && (line[0] == ';');
        }

        /*
         * A line is the start of a section if the first character is an open
         * bracket and the last character is a closing bracket.
         */
        bool is_section_start_line(const std::string& line) const
        {
            return (line.length() > 0) && (line[0] == '[') && (line[line.length() - 1] == ']');
        }

        /*
         * A line contains an assignment if it contains an equals sign and
         * there is text before and after this equals sign.
         */
        bool is_assignment_line(const std::string& line) const
        {
            std::size_t equals_pos = line.find("=");
            return (equals_pos != std::string::npos) && (equals_pos != 0) && (equals_pos != line.length() - 1);
        }

        void ensure_property_exists(const std::string& section, const std::string& name) const
        {
            if (section != "" && sections.find(section) == sections.end())
            {
                throw std::runtime_error("section does not exist");
            }

            if (sections.at(section).find(name) == sections.at(section).end())
            {
                throw std::runtime_error("property does not exist");
            }
        }

    private:
        const std::string filename;
        std::vector<std::string> input;

        typedef std::map<std::string, std::string> properties;
        std::map<std::string, properties> sections;

        std::string current_section;

        static constexpr const char* BOOL_TRUE = "TRUE";
        static constexpr const char* BOOL_FALSE = "FALSE";
};

#endif
<|endoftext|>


<commit_before><commit_msg>Extract the group token conversion loop out into a separate class.<commit_after><|endoftext|>


<commit_before><commit_msg>Planning: add weight_end_dx on piecewise_jerk_speed<commit_after><|endoftext|>


<commit_before><commit_msg>fix coverity#1187656<commit_after><|endoftext|>