text:
//////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (c) 2022, The Regents of the University of California
// 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 holder 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 HOLDER OR CONTRIBUTORS 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 "shape.h"

#include <boost/polygon/polygon.hpp>

#include "grid.h"
#include "grid_component.h"
#include "odb/db.h"
#include "techlayer.h"
#include "utl/Logger.h"

namespace pdn {

Shape::Shape(odb::dbTechLayer* layer,
             odb::dbNet* net,
             const odb::Rect& rect,
             odb::dbWireShapeType type)
    : layer_(layer),
      net_(net),
      rect_(rect),
      type_(type),
      shape_type_(SHAPE),
      obs_(rect_),
      grid_component_(nullptr)
{
}

Shape::Shape(odb::dbTechLayer* layer,
             const odb::Rect& rect,
             ShapeType shape_type)
    : layer_(layer),
      net_(nullptr),
      rect_(rect),
      type_(odb::dbWireShapeType::NONE),
      shape_type_(shape_type),
      obs_(rect_),
      grid_component_(nullptr)
{
}

Shape::~Shape()
{
}

utl::Logger* Shape::getLogger() const
{
  return grid_component_->getLogger();
}

Shape* Shape::copy() const
{
  auto* shape = new Shape(layer_, net_, rect_, type_);
  shape->shape_type_ = shape_type_;
  shape->obs_ = obs_;
  shape->iterm_connections_ = iterm_connections_;
  shape->bterm_connections_ = bterm_connections_;
  return shape;
}

void Shape::merge(Shape* shape)
{
  rect_.merge(shape->rect_);
  iterm_connections_.insert(shape->iterm_connections_.begin(),
                            shape->iterm_connections_.end());
  bterm_connections_.insert(shape->bterm_connections_.begin(),
                            shape->bterm_connections_.end());
  generateObstruction();
}

const Box Shape::rectToBox(const odb::Rect& rect)
{
  return Box(Point(rect.xMin(), rect.yMin()),
             Point(rect.xMax(), rect.yMax()));
}

const Box Shape::getRectBox() const
{
  return rectToBox(rect_);
}

const Box Shape::getObstructionBox() const
{
  return rectToBox(obs_);
}

int Shape::getNumberOfConnections() const
{
  return vias_.size() + iterm_connections_.size() + bterm_connections_.size();
}

int Shape::getNumberOfConnectionsBelow() const
{
  int connections = 0;
  for (const auto& via : vias_) {
    if (via->getUpperLayer() == layer_) {
      connections++;
    }
  }

  return connections;
}

int Shape::getNumberOfConnectionsAbove() const
{
  int connections = 0;
  for (const auto& via : vias_) {
    if (via->getLowerLayer() == layer_) {
      connections++;
    }
  }

  return connections;
}

bool Shape::isValid() const
{
  // check if shape has a valid area
  if (layer_->hasArea()) {
    if (rect_.area() < layer_->getArea()) {
      return false;
    }
  }

  return true;
}

bool Shape::isWrongWay() const
{
  if (isHorizontal()
      && layer_->getDirection() == odb::dbTechLayerDir::HORIZONTAL) {
    return true;
  }
  if (isVertical() && layer_->getDirection() == odb::dbTechLayerDir::VERTICAL) {
    return true;
  }
  return false;
}

void Shape::updateIBTermConnections(std::set<odb::Rect>& terms)
{
  std::set<odb::Rect> remove_terms;
  for (const odb::Rect& term : terms) {
    if (!rect_.overlaps(term)) {
      remove_terms.insert(term);
    }
  }
  for (const odb::Rect& term : remove_terms) {
      terms.erase(term);
  }
}

void Shape::updateTermConnections()
{
  updateIBTermConnections(iterm_connections_);
  updateIBTermConnections(bterm_connections_);
}

bool Shape::hasTermConnections() const
{
  return !bterm_connections_.empty() || !iterm_connections_.empty();
}

const odb::Rect Shape::getMinimumRect() const
{
  odb::Rect intersected_rect;
  intersected_rect.mergeInit();
  // merge all bterms
  for (const auto& bterm : bterm_connections_) {
    intersected_rect.merge(bterm);
  }

  // merge all iterms
  for (const odb::Rect& iterm : iterm_connections_) {
    intersected_rect.merge(iterm);
  }

  // merge all vias
  for (auto& via : vias_) {
    intersected_rect.merge(via->getArea());
  }

  return intersected_rect;
}

bool Shape::cut(const ShapeTree& obstructions,
                std::vector<Shape*>& replacements) const
{
  using namespace boost::polygon::operators;
  using Rectangle = boost::polygon::rectangle_data<int>;
  using Polygon90 = boost::polygon::polygon_90_with_holes_data<int>;
  using Polygon90Set = boost::polygon::polygon_90_set_data<int>;
  using Pt = Polygon90::point_type;

  const bool is_horizontal = isHorizontal();

  std::vector<Polygon90> shape_violations;
  for (auto it
       = obstructions.qbegin(bgi::intersects(getRectBox())
                             && bgi::satisfies([&](const auto& other) {
                                  const auto& other_shape = other.second;
                                  return layer_ == other_shape->getLayer()
                                         || other_shape->getLayer() == nullptr;
                                }));
       it != obstructions.qend();
       it++) {
    auto other_shape = it->second;
    odb::Rect vio_rect = other_shape->getObstruction();

    // ensure the violation overlap fully with the shape to make cut correctly
    if (is_horizontal) {
      vio_rect.set_ylo(std::min(rect_.yMin(), vio_rect.yMin()));
      vio_rect.set_yhi(std::max(rect_.yMax(), vio_rect.yMax()));
    } else {
      vio_rect.set_xlo(std::min(rect_.xMin(), vio_rect.xMin()));
      vio_rect.set_xhi(std::max(rect_.xMax(), vio_rect.xMax()));
    }
    std::array<Pt, 4> pts = {Pt(vio_rect.xMin(), vio_rect.yMin()),
                             Pt(vio_rect.xMax(), vio_rect.yMin()),
                             Pt(vio_rect.xMax(), vio_rect.yMax()),
                             Pt(vio_rect.xMin(), vio_rect.yMax())};

    Polygon90 poly;
    poly.set(pts.begin(), pts.end());

    // save violating polygon
    shape_violations.push_back(poly);
  }

  // check if violations is empty and return no new shapes
  if (shape_violations.empty()) {
    return false;
  }

  std::array<Pt, 4> pts = {Pt(rect_.xMin(), rect_.yMin()),
                           Pt(rect_.xMax(), rect_.yMin()),
                           Pt(rect_.xMax(), rect_.yMax()),
                           Pt(rect_.xMin(), rect_.yMax())};

  Polygon90 poly;
  poly.set(pts.begin(), pts.end());
  std::array<Polygon90, 1> arr{poly};

  Polygon90Set new_shape(boost::polygon::HORIZONTAL, arr.begin(), arr.end());

  // remove all violations from the shape
  for (const auto& violation : shape_violations) {
    new_shape -= violation;
  }

  std::vector<Rectangle> rects;
  new_shape.get_rectangles(rects);

  for (auto& r : rects) {
    const odb::Rect new_rect(xl(r), yl(r), xh(r), yh(r));

    // check if new shape should be accepted,
    // only shapes with the same width will be used
    bool accept = false;
    if (is_horizontal) {
      accept = rect_.dy() == new_rect.dy();
    } else {
      accept = rect_.dx() == new_rect.dx();
    }

    if (accept) {
      auto* new_shape = copy();
      new_shape->setRect(new_rect);
      new_shape->updateTermConnections();

      replacements.push_back(new_shape);
    }
  }
  return true;
}

void Shape::writeToDb(odb::dbSWire* swire,
                      bool add_pins,
                      bool make_rect_as_pin) const
{
  debugPrint(getLogger(),
             utl::PDN,
             "Shape",
             5,
             "Adding shape {} with pins {} and rect as pin {}",
             getReportText(),
             add_pins,
             make_rect_as_pin);
  odb::dbSBox::create(swire,
                      layer_,
                      rect_.xMin(),
                      rect_.yMin(),
                      rect_.xMax(),
                      rect_.yMax(),
                      type_);

  if (add_pins) {
    if (make_rect_as_pin) {
      addBPinToDb(rect_);
    }
    for (const auto& bterm : bterm_connections_) {
      addBPinToDb(bterm);
    }
  }
}

void Shape::addBPinToDb(const odb::Rect& rect) const
{
  // find existing bterm, else make it
  odb::dbBTerm* bterm = nullptr;
  if (net_->getBTermCount() == 0) {
    bterm = odb::dbBTerm::create(net_, net_->getConstName());
    bterm->setSigType(net_->getSigType());
    bterm->setIoType(odb::dbIoType::INOUT);
    bterm->setSpecial();
  } else {
    bterm = net_->get1stBTerm();
  }

  auto pins = bterm->getBPins();
  for (auto* pin : pins) {
    for (auto* box : pin->getBoxes()) {
      if (box->getTechLayer() != layer_) {
        continue;
      }
      odb::Rect box_rect;
      box->getBox(box_rect);
      if (box_rect == rect) {
        // pin already exists
        return;
      }
    }
  }

  odb::dbBPin* pin = nullptr;
  if (pins.empty()) {
    pin = odb::dbBPin::create(bterm);
    pin->setPlacementStatus(odb::dbPlacementStatus::FIRM);
  } else {
    pin = *pins.begin();
  }

  odb::dbBox::create(
      pin, layer_, rect.xMin(), rect.yMin(), rect.xMax(), rect.yMax());
}

void Shape::populateMapFromDb(odb::dbNet* net, ShapeTreeMap& map)
{
  for (auto* swire : net->getSWires()) {
    for (auto* box : swire->getWires()) {
      auto* layer = box->getTechLayer();
      if (layer == nullptr) {
        continue;
      }

      odb::Rect rect;
      box->getBox(rect);

      ShapePtr shape
          = std::make_shared<Shape>(layer, net, rect, box->getWireShapeType());
      shape->setShapeType(Shape::FIXED);
      if (box->getDirection() == odb::dbSBox::OCTILINEAR) {
        // cannot connect this this safely so make it an obstruction
        shape->setNet(nullptr);
        shape->setShapeType(Shape::OBS);
      }
      shape->generateObstruction();
      map[layer].insert({shape->getRectBox(), shape});
    }
  }
}

void Shape::generateObstruction()
{
  const int width = getWidth();
  const int length = getLength();
  const TechLayer layer(layer_);

  // first apply the spacing rules
  const int dbspacing = layer.getSpacing(width, length);
  odb::Rect spacingdb_rect;
  rect_.bloat(dbspacing, spacingdb_rect);

  // apply spacing table rules
  odb::Rect spacing_table_rect = rect_;
  const bool is_wrong_way = isWrongWay();
  for (auto* spacing_rule : layer_->getTechLayerSpacingTablePrlRules()) {
    if (spacing_rule->isWrongDirection() && !is_wrong_way) {
      continue;
    }

    const int spacing = spacing_rule->getSpacing(width, length);

    odb::Rect spacing_rule_rect = rect_;
    rect_.bloat(spacing, spacing_rule_rect);
    spacing_table_rect.merge(spacing_rule_rect);
  }

  // apply eol rules
  const bool is_horizontal = isHorizontal();
  odb::Rect eol_rect = rect_;
  for (auto* eol_rule : layer_->getTechLayerSpacingEolRules()) {
    if (width > eol_rule->getEolWidth()) {
      continue;
    }

    const int spacing = eol_rule->getEolSpace();

    odb::Rect eol_rule_rect = rect_;
    if (is_horizontal) {
      eol_rule_rect.set_xlo(eol_rule_rect.xMin() - spacing);
      eol_rule_rect.set_xhi(eol_rule_rect.xMax() + spacing);
    } else {
      eol_rule_rect.set_ylo(eol_rule_rect.yMin() - spacing);
      eol_rule_rect.set_yhi(eol_rule_rect.yMax() + spacing);
    }
    eol_rect.merge(eol_rule_rect);
  }

  // merge all to get most restrictive obstruction box
  obs_.mergeInit();
  obs_.merge(spacingdb_rect);
  obs_.merge(spacing_table_rect);
  obs_.merge(eol_rect);
}

const std::string Shape::getDisplayText() const
{
  const std::string seperator = ":";
  std::string text;

  text += net_->getName() + seperator;
  text += layer_->getName() + seperator;
  if (grid_component_ != nullptr) {
    text += GridComponent::typeToString(grid_component_->type()) + seperator;
    text += grid_component_->getGrid()->getName();
  } else {
    text += "none";
  }

  return text;
}

bool Shape::isRemovable() const
{
  if (!isModifiable()) {
    return false;
  }

  if (getNumberOfConnections() < 2) {
    // floating shape with one or zero connections
    return true;
  }

  return false;
}

bool Shape::isModifiable() const
{
  return shape_type_ == SHAPE;
}

const std::string Shape::getReportText() const
{
  std::string text = fmt::format("{} on {}",
                                 getRectText(rect_, layer_->getTech()->getLefUnits()),
                                 layer_->getName());

  if (net_ != nullptr) {
    text = net_->getName() + " " + text;
  }
  return text;
}

const std::string Shape::getRectText(const odb::Rect& rect,
                                     double dbu_to_micron)
{
  return fmt::format("({:.4f}, {:.4f}) - ({:.4f}, {:.4f})",
                     rect.xMin() / dbu_to_micron,
                     rect.yMin() / dbu_to_micron,
                     rect.xMax() / dbu_to_micron,
                     rect.yMax() / dbu_to_micron);
}

Shape* Shape::extendTo(const odb::Rect& rect,
                       const ShapeTree& obstructions) const
{
  std::unique_ptr<Shape> new_shape(copy());

  if (isHorizontal()) {
    new_shape->rect_.set_xlo(std::min(rect_.xMin(), rect.xMin()));
    new_shape->rect_.set_xhi(std::max(rect_.xMax(), rect.xMax()));
  } else if (isVertical()) {
    new_shape->rect_.set_ylo(std::min(rect_.yMin(), rect.yMin()));
    new_shape->rect_.set_yhi(std::max(rect_.yMax(), rect.yMax()));
  } else {
    return nullptr;
  }

  if (rect_ == new_shape->rect_) {
    // shape did not change
    return nullptr;
  }

  if (obstructions.qbegin(bgi::intersects(new_shape->getRectBox())
                          && bgi::satisfies([this](const auto& other) {
                               // ignore violations that results from itself
                               return other.second.get() != this;
                             }))
      != obstructions.qend()) {
    // extension not possible
    return nullptr;
  }

  return new_shape.release();
}

/////////

FollowPinShape::FollowPinShape(odb::dbTechLayer* layer,
                               odb::dbNet* net,
                               const odb::Rect& rect)
    : Shape(layer, net, rect, odb::dbWireShapeType::FOLLOWPIN)
{
}

Shape* FollowPinShape::copy() const
{
  auto* shape = new FollowPinShape(getLayer(), getNet(), getRect());
  shape->generateObstruction();
  shape->rows_ = rows_;
  return shape;
}

void FollowPinShape::merge(Shape* shape)
{
  Shape::merge(shape);

  FollowPinShape* other = dynamic_cast<FollowPinShape*>(shape);
  if (other == nullptr) {
    return;
  }

  rows_.insert(other->rows_.begin(), other->rows_.end());
}

void FollowPinShape::updateTermConnections()
{
  Shape::updateTermConnections();

  // remove rows that no longer overlap with shape

  const odb::Rect& rect = getRect();
  std::set<odb::dbRow*> remove_rows;
  for (auto* row : rows_) {
    odb::Rect row_rect;
    row->getBBox(row_rect);
    if (!rect.intersects(row_rect)) {
      remove_rows.insert(row);
    }
  }
  for (auto* row : remove_rows) {
    rows_.erase(row);
  }
}

const odb::Rect FollowPinShape::getMinimumRect() const
{
  odb::Rect min_shape = Shape::getMinimumRect();

  const odb::Rect& rect = getRect();
  // copy width back
  const bool is_horizontal = isHorizontal();
  if (is_horizontal) {
    min_shape.set_ylo(rect.yMin());
    min_shape.set_yhi(rect.yMax());
  } else {
    min_shape.set_xlo(rect.xMin());
    min_shape.set_xhi(rect.xMax());
  }

  // merge with rows to ensure proper overlap
  for (auto* row : rows_) {
    odb::Rect row_rect;
    row->getBBox(row_rect);
    if (is_horizontal) {
      min_shape.set_xlo(std::min(min_shape.xMin(), row_rect.xMin()));
      min_shape.set_xhi(std::max(min_shape.xMax(), row_rect.xMax()));
    } else {
      min_shape.set_ylo(std::min(min_shape.yMin(), row_rect.yMin()));
      min_shape.set_yhi(std::max(min_shape.yMax(), row_rect.yMax()));
    }
  }

  return min_shape;
}

bool FollowPinShape::cut(const ShapeTree& obstructions,
                         std::vector<Shape*>& replacements) const
{
  ShapeTree filtered_obstructions;

  for (const auto& [box, shape] : obstructions) {
    if (shape->shapeType() == GRID_OBS) {
      // followpins can ignore grid level obstructions
      continue;
    }
    filtered_obstructions.insert({box, shape});
  }

  return Shape::cut(filtered_obstructions, replacements);
}

}  // namespace pdn


text:
/*
==============================================================================
KratosMultiScaleApplication
A library based on:
Kratos
A General Purpose Software for Multi-Physics Finite Element Analysis
Version 1.0 (Released on march 05, 2007).

Copyright 2007
Pooyan Dadvand, Riccardo Rossi, Janosch Stascheit, Felix Nagel
pooyan@cimne.upc.edu
rrossi@cimne.upc.edu
janosch.stascheit@rub.de
nagel@sd.rub.de
- CIMNE (International Center for Numerical Methods in Engineering),
Gran Capita' s/n, 08034 Barcelona, Spain
- Ruhr-University Bochum, Institute for Structural Mechanics, Germany

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 condition:

Distribution of this code for  any  commercial purpose  is permissible
ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNERS.

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.

==============================================================================
*/
//
//   Project Name:        Kratos
//   Last Modified by:    $Author: Massimo Petracca $
//   Date:                $Date: 2013-10-03 19:37:00 $
//   Revision:            $Revision: 1.00 $
//
//

// System includes

// External includes
#include <boost/python.hpp>
#include "spaces/ublas_space.h"

// Project includes

#include "linear_solvers/linear_solver.h"
#include "add_strategies_to_python.h"

#include "custom_strategies/strategies/static_general_strategy.h"
#include "custom_strategies/strategies/static_general_strategy_krylov_newton.h"
#include "custom_strategies/strategies/arc_length_strategy.h"
#include "custom_strategies/strategies/arc_length_riks_strategy.h"
#include "custom_strategies/strategies/arc_length_diss_nrg_strategy.h"
#include "custom_strategies/strategies/displacement_control_strategy.h"

#include "custom_strategies/builder_and_solvers/static_general_builder_and_solver.h"

#include "custom_strategies/schemes/static_general_scheme.h"
#include "custom_strategies/schemes/rve_static_scheme.h"

#include "custom_strategies/convergencecriterias/residual_norm_criteria.h"
#include "custom_strategies/convergencecriterias/displacement_norm_criteria.h"
#include "custom_strategies/convergencecriterias/energy_norm_criteria.h"

namespace Kratos
{
namespace Python
{

using namespace boost::python;

typedef UblasSpace<double, CompressedMatrix, Vector>	SparseSpaceType;
typedef UblasSpace<double, Matrix, Vector>				LocalSpaceType;

void MoveMesh(Scheme< SparseSpaceType, LocalSpaceType >& dummy, ModelPart::NodesContainerType& rNodes)
{
    for (ModelPart::NodeIterator i = rNodes.begin(); i != rNodes.end(); ++i)
    {
        const array_1d<double, 3 > & disp = i->FastGetSolutionStepValue(DISPLACEMENT);
        (i)->X() = (i)->X0() + disp[0];
        (i)->Y() = (i)->Y0() + disp[1];
        (i)->Z() = (i)->Z0() + disp[2];
    }
}

void AddStrategiesToPython()
{

	typedef LinearSolver<SparseSpaceType, LocalSpaceType >							LinearSolverType;
	typedef SolvingStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType >	BaseSolvingStrategyType;
	typedef Scheme< SparseSpaceType, LocalSpaceType >								BaseSchemeType;

	typedef ConvergenceCriteria< SparseSpaceType, LocalSpaceType >					TConvergenceCriteriaType;
	typedef ConvergenceCriteria< SparseSpaceType, LocalSpaceType > ::Pointer		TConvergenceCriteriaPointer;

	typedef BuilderAndSolver< SparseSpaceType, LocalSpaceType, LinearSolverType >	BuilderAndSolverType;

	// =========================================================================================================
	//
	// Strategies
	//
	// =========================================================================================================

	class_< BaseSolvingStrategyType, boost::noncopyable > (
		"SolvingStrategyBase",
		init < ModelPart&, bool >())
        .def("Predict", &BaseSolvingStrategyType::Predict)
        .def("Solve", &BaseSolvingStrategyType::Solve)
        .def("IsConverged", &BaseSolvingStrategyType::IsConverged)
        .def("CalculateOutputData", &BaseSolvingStrategyType::CalculateOutputData)
        .def("SetEchoLevel", &BaseSolvingStrategyType::SetEchoLevel)
        .def("GetEchoLevel", &BaseSolvingStrategyType::GetEchoLevel)
        .def("SetRebuildLevel", &BaseSolvingStrategyType::SetRebuildLevel)
        .def("GetRebuildLevel", &BaseSolvingStrategyType::GetRebuildLevel)
        .def("SetMoveMeshFlag", &BaseSolvingStrategyType::SetMoveMeshFlag)
        .def("MoveMeshFlag", &BaseSolvingStrategyType::MoveMeshFlag)
        .def("MoveMesh", &BaseSolvingStrategyType::MoveMesh)
        .def("Clear", &BaseSolvingStrategyType::Clear)
        .def("Check", &BaseSolvingStrategyType::Check)
        ;

	typedef StaticGeneralStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType > StaticGeneralStrategyType;
	class_< StaticGeneralStrategyType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"StaticGeneralStrategy",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, int, bool, bool, bool>())
		.def(init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, BuilderAndSolverType::Pointer, int, bool, bool, bool >())
		.def("SetMaxIterationNumber", &StaticGeneralStrategyType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &StaticGeneralStrategyType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &StaticGeneralStrategyType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &StaticGeneralStrategyType::GetKeepSystemConstantDuringIterations)
		;

	typedef StaticGeneralStrategyKrylovNewton< SparseSpaceType, LocalSpaceType, LinearSolverType > StaticGeneralStrategyKrylovNewtonType;
	class_< StaticGeneralStrategyKrylovNewtonType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"StaticGeneralStrategyKrylovNewton",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, int, bool, bool, bool>())
		.def(init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, BuilderAndSolverType::Pointer, int, bool, bool, bool >())
		.def("SetMaxIterationNumber", &StaticGeneralStrategyKrylovNewtonType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &StaticGeneralStrategyKrylovNewtonType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &StaticGeneralStrategyKrylovNewtonType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &StaticGeneralStrategyKrylovNewtonType::GetKeepSystemConstantDuringIterations)
		;

	typedef ArcLengthStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType > ArcLengthStrategyType;
	class_< ArcLengthStrategyType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"ArcLengthStrategy",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, double, double, double, double, int, bool, bool, bool>())
		.def("SetMaxIterationNumber", &ArcLengthStrategyType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &ArcLengthStrategyType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &ArcLengthStrategyType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &ArcLengthStrategyType::GetKeepSystemConstantDuringIterations)
		.def("PrepareFirstSolve", &ArcLengthStrategyType::PrepareFirstSolve)
		;

	typedef ArcLengthRiksStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType > ArcLengthRiksStrategyType;
	class_< ArcLengthRiksStrategyType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"ArcLengthRiksStrategy",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, int, bool, bool, bool>())
		.def(init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, BuilderAndSolverType::Pointer, int, bool, bool, bool >())
		.def("SetMaxIterationNumber", &ArcLengthRiksStrategyType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &ArcLengthRiksStrategyType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &ArcLengthRiksStrategyType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &ArcLengthRiksStrategyType::GetKeepSystemConstantDuringIterations)
		.def("PrepareFirstSolve", &ArcLengthRiksStrategyType::PrepareFirstSolve)
		.def("SetLoadFactors", &ArcLengthRiksStrategyType::SetLoadFactors)
		;

	typedef ArcLengthDissNrgStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType > ArcLengthDissNrgStrategyType;
	class_< ArcLengthDissNrgStrategyType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"ArcLengthDissNrgStrategy",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, int, bool, bool, bool>())
		.def(init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, BuilderAndSolverType::Pointer, int, bool, bool, bool >())
		.def("SetMaxIterationNumber", &ArcLengthDissNrgStrategyType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &ArcLengthDissNrgStrategyType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &ArcLengthDissNrgStrategyType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &ArcLengthDissNrgStrategyType::GetKeepSystemConstantDuringIterations)
		.def("PrepareFirstSolve", &ArcLengthDissNrgStrategyType::PrepareFirstSolve)
		.def("SetLoadFactors", &ArcLengthDissNrgStrategyType::SetLoadFactors)
		;

	typedef DisplacementControlStrategy< SparseSpaceType, LocalSpaceType, LinearSolverType > DisplacementControlStrategyType;
	class_< DisplacementControlStrategyType, bases< BaseSolvingStrategyType >, boost::noncopyable >(
		"DisplacementControlStrategy",
		init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, int, bool, bool, bool, unsigned int, unsigned int, double>())
		.def(init < ModelPart&, BaseSchemeType::Pointer, LinearSolverType::Pointer, TConvergenceCriteriaType::Pointer, BuilderAndSolverType::Pointer, int, bool, bool, bool, unsigned int, unsigned int, double >())
		.def("SetMaxIterationNumber", &DisplacementControlStrategyType::SetMaxIterationNumber)
		.def("GetMaxIterationNumber", &DisplacementControlStrategyType::GetMaxIterationNumber)
		.def("SetKeepSystemConstantDuringIterations", &DisplacementControlStrategyType::SetKeepSystemConstantDuringIterations)
		.def("GetKeepSystemConstantDuringIterations", &DisplacementControlStrategyType::GetKeepSystemConstantDuringIterations)
		.def("PrepareFirstSolve", &DisplacementControlStrategyType::PrepareFirstSolve)
		.def("SetLoadFactors", &DisplacementControlStrategyType::SetLoadFactors)
		;

	// =========================================================================================================
	//
	// BuilderAndSolvers
	//
	// =========================================================================================================

	typedef StaticGeneralBuilderAndSolver< SparseSpaceType, LocalSpaceType, LinearSolverType > StaticGeneralBuilderAndSolverType;
	class_<StaticGeneralBuilderAndSolverType, bases< BuilderAndSolverType >, boost::noncopyable >(
		"StaticGeneralBuilderAndSolver",
		init<LinearSolverType::Pointer>())
		;

	// =========================================================================================================
	//
	// Schemes
	//
	// =========================================================================================================

	class_< BaseSchemeType, boost::noncopyable >
            ("Scheme", init< >())
            .def("Initialize", &BaseSchemeType::Initialize)
            .def("SchemeIsInitialized", &BaseSchemeType::SchemeIsInitialized)
            .def("ElementsAreInitialized", &BaseSchemeType::ElementsAreInitialized)
            .def("ConditionsAreInitialized", &BaseSchemeType::ConditionsAreInitialized)
            .def("InitializeElements", &BaseSchemeType::InitializeElements)
            .def("InitializeConditions", &BaseSchemeType::InitializeConditions)
            .def("InitializeSolutionStep", &BaseSchemeType::InitializeSolutionStep)
            .def("FinalizeSolutionStep", &BaseSchemeType::FinalizeSolutionStep)
            .def("InitializeNonLinIteration", &BaseSchemeType::InitializeNonLinIteration)
            .def("FinalizeNonLinIteration", &BaseSchemeType::FinalizeNonLinIteration)
            .def("Predict", &BaseSchemeType::Predict)
            .def("Update", &BaseSchemeType::Update)
            .def("CalculateOutputData", &BaseSchemeType::CalculateOutputData)
            .def("Clean", &BaseSchemeType::Clean)
            .def("Clear",&BaseSchemeType::Clear)
            .def("MoveMesh", MoveMesh)
            .def("Check", &BaseSchemeType::Check)
            ;

	typedef StaticGeneralScheme< SparseSpaceType, LocalSpaceType> StaticGeneralSchemeType;
    class_< StaticGeneralSchemeType, bases< BaseSchemeType >, boost::noncopyable >(
            "StaticGeneralScheme",
			init< >())
			;

	typedef RveStaticScheme< SparseSpaceType, LocalSpaceType> RveStaticSchemeType;
    class_< RveStaticSchemeType, bases< BaseSchemeType >, boost::noncopyable >(
            "RveStaticScheme",
			init< >())
			;

	// =========================================================================================================
	//
	// Convergence criteria
	//
	// =========================================================================================================

	typedef ConvergenceCriteria< SparseSpaceType, LocalSpaceType > ConvergenceCriteriaBaseType;
	class_< ConvergenceCriteriaBaseType, boost::noncopyable > (
		"ConvergenceCriteriaBase",
		init<>())
		.def("SetActualizeRHSFlag", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::SetActualizeRHSFlag)
		.def("GetActualizeRHSflag", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::GetActualizeRHSflag)
		.def("PreCriteria", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::PreCriteria)
		.def("PostCriteria", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::PostCriteria)
		.def("Initialize", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::Initialize)
		.def("InitializeSolutionStep", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::InitializeSolutionStep)
		.def("FinalizeSolutionStep", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::FinalizeSolutionStep)
		.def("Check", &ConvergenceCriteria<SparseSpaceType, LocalSpaceType >::Check)
		;

	typedef ResidualNormCriteria<SparseSpaceType, LocalSpaceType > ResidualNormCriteriaType;
    class_< ResidualNormCriteriaType, bases<ConvergenceCriteriaBaseType>, boost::noncopyable >(
		"ResidualNormCriteria",
		init< double, double>())
		.def(init< double, double, bool >())
		;

	typedef DisplacementNormCriteria<SparseSpaceType, LocalSpaceType > DisplacementNormCriteriaType;
    class_< DisplacementNormCriteriaType, bases<ConvergenceCriteriaBaseType>, boost::noncopyable >(
		"DisplacementNormCriteria",
		init< double, double>())
		.def(init< double, double, bool >())
		;

	typedef EnergyNormCriteria<SparseSpaceType, LocalSpaceType > EnergyNormCriteriaType;
    class_< EnergyNormCriteriaType, bases<ConvergenceCriteriaBaseType>, boost::noncopyable >(
		"EnergyNormCriteria",
		init< double, double>())
		.def(init< double, double, bool >())
		;

}

}

}

ext: cpp

max_stars_repo_name: lcirrott/Kratos

max_issues_repo_name: lcirrott/Kratos

max_forks_repo_name: lcirrott/Kratos


text:
#include <Eigen/Core>
#include <Eigen/SVD>
#include <iostream>

#define VIENNACL_WITH_OPENCL 1
#define VIENNACL_WITH_EIGEN 1

#include "viennacl/linalg/svd.hpp"
#include "viennacl/matrix.hpp"
#include "viennacl/vector.hpp"

using namespace Eigen;
using std::cout;

int main() {
  // initializers
  MatrixXf C;
  viennacl::matrix<float> vcl_C = viennacl::zero_matrix<float>(1e3, 50);
  viennacl::matrix<float> vcl_U = viennacl::zero_matrix<float>(1e3, 1e3);
  viennacl::matrix<float> vcl_V = viennacl::zero_matrix<float>(50, 50);

  // random data
  C.setRandom(1e5, 50);

  // copy eigen to viennacl
  viennacl::copy(C, vcl_C);

  // eigen SVD
  // JacobiSVD<MatrixXf> svd(C, ComputeThinU | ComputeThinV);
  //
  // std::cout << "diag" << std::endl;
  // std::cout << svd.singularValues() << std::endl;
  //
  // std::cout << "U" << std::endl;
  // std::cout << svd.matrixU() << std::endl;
  //
  // std::cout << "V" << std::endl;
  // std::cout << svd.matrixV() << std::endl;

  // viennacl svd

  viennacl::linalg::svd(vcl_C, vcl_U, vcl_V);

  viennacl::vector_base<float> D(vcl_C.handle(),
                                 std::min(vcl_C.size1(), vcl_C.size2()), 0,
                                 vcl_C.internal_size2() + 1);

  // std::cout << "diag" << std::endl;
  // std::cout << D << std::endl;
  //
  // std::cout << "U" << std::endl;
  // std::cout << vcl_U << std::endl;
  //
  // std::cout << "V" << std::endl;
  // std::cout << vcl_V << std::endl;

  std::cout << "V" << std::endl;
  return 0;
}


text:
#include <yamail/resource_pool/async/pool.hpp>

#include <benchmark/benchmark.h>

#include <boost/asio/post.hpp>

#include <array>
#include <atomic>
#include <condition_variable>
#include <iomanip>
#include <random>
#include <thread>

namespace {

using namespace yamail::resource_pool;

class benchmark_args {
public:
    constexpr benchmark_args sequences(std::size_t value) const {
        auto copy = *this;
        copy.sequences_ = value;
        return copy;
    }

    constexpr std::size_t sequences() const {
        return sequences_;
    }

    constexpr benchmark_args threads(std::size_t value) const {
        auto copy = *this;
        copy.threads_ = value;
        return copy;
    }

    constexpr std::size_t threads() const {
        return threads_;
    }

    constexpr benchmark_args resources(std::size_t value) const {
        auto copy = *this;
        copy.resources_ = value;
        return copy;
    }

    constexpr std::size_t resources() const {
        return resources_;
    }

    constexpr benchmark_args queue_size(std::size_t value) const {
        auto copy = *this;
        copy.queue_size_ = value;
        return copy;
    }

    constexpr std::size_t queue_size() const {
        return queue_size_;
    }

private:
    std::size_t sequences_ = 0;
    std::size_t threads_ = 0;
    std::size_t resources_ = 0;
    std::size_t queue_size_ = 0;
};

struct resource {
    std::int64_t value = 0;
};

struct stub_mutex {
    stub_mutex() = default;
    stub_mutex(const stub_mutex&) = delete;
    void lock() {}
    void unlock() {}
};

struct single_thread {};
struct multi_thread {};

template <class Threading>
struct context {
    boost::asio::io_context io_context;
    boost::asio::executor_work_guard<boost::asio::io_context::executor_type> guard = boost::asio::make_work_guard(io_context);
    std::conditional_t<std::is_same_v<Threading, multi_thread>, std::atomic_bool, bool> stop {false};
    time_traits::duration timeout {std::chrono::milliseconds(100)};
    std::vector<std::chrono::steady_clock::duration> durations;
    std::mutex get_next_mutex;
    std::condition_variable get_next;
    std::unique_lock<std::mutex> get_next_lock {get_next_mutex};
    std::conditional_t<std::is_same_v<Threading, multi_thread>, std::atomic<std::int64_t>, std::int64_t> ready_count {0};

    void wait_next() {
        if (--ready_count < 0) {
            get_next.wait(get_next_lock);
        }
    }

    void allow_next() {
        ++ready_count;
        if constexpr (std::is_same_v<Threading, multi_thread>) {
            get_next.notify_one();
        }
    }

    void finish() {
        stop = true;
        guard.reset();
    }
};

template <class Threading>
struct callback {
    using mutex_t = std::conditional_t<std::is_same_v<Threading, multi_thread>, std::mutex, stub_mutex>;
    using pool_t = async::pool<resource, mutex_t>;
    using handle_t = typename pool_t::handle;

    context<Threading>& ctx;
    pool_t& pool;

    void operator ()(const boost::system::error_code& ec, handle_t handle) {
        impl(ec, std::move(handle));
        if (!ctx.stop) {
            pool.get_auto_waste(ctx.io_context, *this, ctx.timeout);
        }
        ctx.allow_next();
    }

    void impl(const boost::system::error_code& ec, handle_t handle) {
        static thread_local std::minstd_rand generator(std::hash<std::thread::id>()(std::this_thread::get_id()));
        static std::uniform_real_distribution<> distrubution(0, 1);
        constexpr const double recycle_probability = 0.5;
        if (!ec) {
            if (handle.empty()) {
                handle.reset(resource {});
            }
            benchmark::DoNotOptimize(++handle->value);
            if (distrubution(generator) < recycle_probability) {
                handle.recycle();
            }
        }
    }
};

const std::array<benchmark_args, 17> benchmarks{{
    benchmark_args().sequences(1).threads(1).resources(1).queue_size(0), // 0
    benchmark_args().sequences(2).threads(1).resources(1).queue_size(1), // 1
    benchmark_args().sequences(2).threads(1).resources(2).queue_size(0), // 2
    benchmark_args().sequences(10).threads(1).resources(10).queue_size(0), // 3
    benchmark_args().sequences(10).threads(1).resources(1).queue_size(9), // 4
    benchmark_args().sequences(10).threads(1).resources(5).queue_size(5), // 5
    benchmark_args().sequences(10).threads(1).resources(9).queue_size(1), // 6
    benchmark_args().sequences(10).threads(2).resources(5).queue_size(5), // 7
    benchmark_args().sequences(100).threads(1).resources(100).queue_size(0), // 8
    benchmark_args().sequences(100).threads(1).resources(10).queue_size(90), // 9
    benchmark_args().sequences(100).threads(1).resources(50).queue_size(50), // 10
    benchmark_args().sequences(100).threads(1).resources(90).queue_size(10), // 11
    benchmark_args().sequences(100).threads(2).resources(50).queue_size(50), // 12
    benchmark_args().sequences(1000).threads(1).resources(10).queue_size(990), // 13
    benchmark_args().sequences(1000).threads(2).resources(10).queue_size(990), // 14
    benchmark_args().sequences(10000).threads(1).resources(10).queue_size(9990), // 15
    benchmark_args().sequences(10000).threads(2).resources(10).queue_size(9990), // 16
}};

void get_auto_waste_callbacks_st(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    context<single_thread> ctx;
    async::pool<resource, stub_mutex> pool(args.resources(), args.queue_size());
    callback<single_thread> cb {ctx, pool};
    for (std::size_t i = 0; i < args.sequences(); ++i) {
        pool.get_auto_waste(ctx.io_context, cb, ctx.timeout);
    }
    while (state.KeepRunning()) {
        const auto ready_count = ctx.ready_count;
        do {
            ctx.io_context.run_one();
        } while (ready_count == ctx.ready_count);
    }
    ctx.finish();
}

struct thread_context {
    context<multi_thread> impl;
    std::thread thread;

    thread_context()
        : thread([this] { this->impl.io_context.run(); }) {}
};

void get_auto_waste_callbacks_mt(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    std::vector<std::unique_ptr<thread_context>> threads;
    for (std::size_t i = 0; i < args.threads(); ++i) {
        threads.emplace_back(std::make_unique<thread_context>());
    }
    async::pool<resource> pool(args.resources(), args.queue_size());
    for (const auto& ctx : threads) {
        callback<multi_thread> cb {ctx->impl, pool};
        for (std::size_t i = 0; i < args.sequences(); ++i) {
            pool.get_auto_waste(ctx->impl.io_context, cb, ctx->impl.timeout);
        }
    }
    while (state.KeepRunning()) {
        std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->impl.wait_next(); });
    }
    std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->impl.finish(); });
    std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->thread.join(); });
}

void get_auto_waste_callbacks(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    if (args.threads() > 1) {
        get_auto_waste_callbacks_mt(state);
    } else {
        get_auto_waste_callbacks_st(state);
    }
}

void get_auto_waste_coroutines_st(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    context<single_thread> ctx;
    async::pool<resource, stub_mutex> pool(args.resources(), args.queue_size());
    for (std::size_t i = 0; i < args.sequences(); ++i) {
        boost::asio::spawn(ctx.io_context, [&] (boost::asio::yield_context yield) {
            static thread_local std::minstd_rand generator(std::hash<std::thread::id>()(std::this_thread::get_id()));
            std::uniform_real_distribution<> distrubution(0, 1);
            constexpr const double recycle_probability = 0.5;
            while (!ctx.stop) {
                boost::system::error_code ec;
                auto handle = pool.get_auto_waste(ctx.io_context, yield[ec], ctx.timeout);
                if (!ec) {
                    if (handle.empty()) {
                        handle.reset(resource {});
                    }
                    benchmark::DoNotOptimize(++handle->value);
                    if (distrubution(generator) < recycle_probability) {
                        handle.recycle();
                    }
                    ctx.allow_next();
                }
            }
        });
    }
    while (state.KeepRunning()) {
        const auto ready_count = ctx.ready_count;
        do {
            ctx.io_context.run_one();
        } while (ready_count == ctx.ready_count);
    }
    ctx.finish();
}

void get_auto_waste_coroutines_mt(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    std::vector<std::unique_ptr<thread_context>> threads;
    for (std::size_t i = 0; i < args.threads(); ++i) {
        threads.emplace_back(std::make_unique<thread_context>());
    }
    async::pool<resource> pool(args.resources(), args.queue_size());
    for (const auto& ctx : threads) {
        for (std::size_t i = 0; i < args.sequences(); ++i) {
            boost::asio::spawn(ctx->impl.io_context, [&] (boost::asio::yield_context yield) {
                static thread_local std::minstd_rand generator(std::hash<std::thread::id>()(std::this_thread::get_id()));
                std::uniform_real_distribution<> distrubution(0, 1);
                constexpr const double recycle_probability = 0.5;
                while (!ctx->impl.stop) {
                    boost::system::error_code ec;
                    auto handle = pool.get_auto_waste(ctx->impl.io_context, yield[ec], ctx->impl.timeout);
                    if (!ec) {
                        if (handle.empty()) {
                            handle.reset(resource {});
                        }
                        benchmark::DoNotOptimize(++handle->value);
                        if (distrubution(generator) < recycle_probability) {
                            handle.recycle();
                        }
                        ctx->impl.allow_next();
                    }
                }
            });
        }
    }
    while (state.KeepRunning()) {
        std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->impl.wait_next(); });
    }
    std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->impl.finish(); });
    std::for_each(threads.begin(), threads.end(), [] (const auto& ctx) { ctx->thread.join(); });
}

void get_auto_waste_coroutines(benchmark::State& state) {
    const auto& args = benchmarks[static_cast<std::size_t>(state.range(0))];
    if (args.threads() > 1) {
        get_auto_waste_coroutines_st(state);
    } else {
        get_auto_waste_coroutines_mt(state);
    }
}

void all_benchmarks(benchmark::internal::Benchmark* b) {
    for (std::size_t n = 0; n < benchmarks.size(); ++n) {
        b->Arg(static_cast<int>(n));
    }
}

}

BENCHMARK(get_auto_waste_callbacks)->Apply(all_benchmarks);
BENCHMARK(get_auto_waste_coroutines)->Apply(all_benchmarks);

BENCHMARK_MAIN();

ext: cc


text:
//
// Copyright (c) 2009, Markus Rickert
// 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.
//
// 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 HOLDER OR CONTRIBUTORS 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 <iostream>
#include <memory>
#include <stdexcept>
#include <boost/lexical_cast.hpp>
#include <rl/kin/Kinematics.h>
#include <rl/math/Unit.h>
#include <rl/plan/KdtreeNearestNeighbors.h>
#include <rl/plan/Prm.h>
#include <rl/plan/RecursiveVerifier.h>
#include <rl/plan/SimpleModel.h>
#include <rl/plan/SimpleOptimizer.h>
#include <rl/plan/UniformSampler.h>
#include <rl/sg/Model.h>

#ifdef RL_SG_BULLET
#include <rl/sg/bullet/Scene.h>
#endif // RL_SG_BULLET
#ifdef RL_SG_FCL
#include <rl/sg/fcl/Scene.h>
#endif // RL_SG_FCL
#ifdef RL_SG_ODE
#include <rl/sg/ode/Scene.h>
#endif // RL_SG_ODE
#ifdef RL_SG_PQP
#include <rl/sg/pqp/Scene.h>
#endif // RL_SG_PQP
#ifdef RL_SG_SOLID
#include <rl/sg/solid/Scene.h>
#endif // RL_SG_SOLID

int
main(int argc, char** argv)
{
	if (argc < 14)
	{
		std::cout << "Usage: rlPrmTest ENGINE SCENEFILE KINEMATICSFILE EXPECTED_NUM_VERTICES_MAX EXPECTED_NUM_EDGES_MAX X Y Z A B C START1 ... STARTn GOAL1 ... GOALn" << std::endl;
		return EXIT_FAILURE;
	}

	try
	{
		std::shared_ptr<rl::sg::Scene> scene;

#ifdef RL_SG_BULLET
		if ("bullet" == std::string(argv[1]))
		{
			scene = std::make_shared<rl::sg::bullet::Scene>();
		}
#endif // RL_SG_BULLET
#ifdef RL_SG_FCL
		if ("fcl" == std::string(argv[1]))
		{
			scene = std::make_shared<rl::sg::fcl::Scene>();
		}
#endif // RL_SG_FCL
#ifdef RL_SG_ODE
		if ("ode" == std::string(argv[1]))
		{
			scene = std::make_shared<rl::sg::ode::Scene>();
		}
#endif // RL_SG_ODE
#ifdef RL_SG_PQP
		if ("pqp" == std::string(argv[1]))
		{
			scene = std::make_shared<rl::sg::pqp::Scene>();
		}
#endif // RL_SG_PQP
#ifdef RL_SG_SOLID
		if ("solid" == std::string(argv[1]))
		{
			scene = std::make_shared<rl::sg::solid::Scene>();
		}
#endif // RL_SG_SOLID

		scene->load(argv[2]);

		std::shared_ptr<rl::kin::Kinematics> kinematics(rl::kin::Kinematics::create(argv[3]));

		rl::math::Transform world = rl::math::Transform::Identity();

		world = rl::math::AngleAxis(
			boost::lexical_cast<rl::math::Real>(argv[11]) * ::rl::math::DEG2RAD,
			::rl::math::Vector3::UnitZ()
		) * ::rl::math::AngleAxis(
			boost::lexical_cast<rl::math::Real>(argv[10]) * ::rl::math::DEG2RAD,
			::rl::math::Vector3::UnitY()
		) * ::rl::math::AngleAxis(
			boost::lexical_cast<rl::math::Real>(argv[9]) * ::rl::math::DEG2RAD,
			::rl::math::Vector3::UnitX()
		);

		world.translation().x() = boost::lexical_cast<rl::math::Real>(argv[6]);
		world.translation().y() = boost::lexical_cast<rl::math::Real>(argv[7]);
		world.translation().z() = boost::lexical_cast<rl::math::Real>(argv[8]);

		kinematics->world() = world;

		rl::plan::SimpleModel model;
		model.kin = kinematics.get();
		model.model = scene->getModel(0);
		model.scene = scene.get();

		rl::plan::KdtreeNearestNeighbors nearestNeighbors(&model);
		rl::plan::Prm planner;
		rl::plan::UniformSampler sampler;
		rl::plan::RecursiveVerifier verifier;

		sampler.seed(0);

		planner.model = &model;
		planner.setNearestNeighbors(&nearestNeighbors);
		planner.sampler = &sampler;
		planner.verifier = &verifier;

		sampler.model = &model;

		verifier.delta = 1.0f * rl::math::DEG2RAD;
		verifier.model = &model;

		rl::math::Vector start(kinematics->getDof());

		for (std::size_t i = 0; i < kinematics->getDof(); ++i)
		{
			start(i) = boost::lexical_cast<rl::math::Real>(argv[i + 12]) * rl::math::DEG2RAD;
		}

		planner.start = &start;

		rl::math::Vector goal(kinematics->getDof());

		for (std::size_t i = 0; i < kinematics->getDof(); ++i)
		{
			goal(i) = boost::lexical_cast<rl::math::Real>(argv[kinematics->getDof() + i + 12]) * rl::math::DEG2RAD;
		}

		planner.goal = &goal;

		planner.duration = std::chrono::seconds(20);

		std::cout << "construct() ... " << std::endl;;
		std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
		planner.construct(15);
		std::chrono::steady_clock::time_point stopTime = std::chrono::steady_clock::now();
		std::cout << "construct() " << std::chrono::duration_cast<std::chrono::duration<double>>(stopTime - startTime).count() * 1000 << " ms" << std::endl;

		std::cout << "solve() ... " << std::endl;;
		startTime = std::chrono::steady_clock::now();
		bool solved = planner.solve();
		stopTime = std::chrono::steady_clock::now();
		std::cout << "solve() " << (solved ? "true" : "false") << " " << std::chrono::duration_cast<std::chrono::duration<double>>(stopTime - startTime).count() * 1000 << " ms" << std::endl;

		std::cout << "NumVertices: " << planner.getNumVertices() << "  NumEdges: " << planner.getNumEdges() << std::endl;

		if (solved)
		{
			if (boost::lexical_cast<std::size_t>(argv[4]) >= planner.getNumVertices() &&
				boost::lexical_cast<std::size_t>(argv[5]) >= planner.getNumEdges())
			{
				return EXIT_SUCCESS;
			}
			else
			{
				std::cerr << "NumVertices and NumEdges are more than expected for this test case.";
				return EXIT_FAILURE;
			}
		}

		return EXIT_FAILURE;
	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << std::endl;
		return EXIT_FAILURE;
	}
}

max_stars_repo_name: Roboy/rl

max_issues_repo_name: Roboy/rl

max_forks_repo_name: Roboy/rl


text:
#include <algorithm>
#include <memory>

#include "topology_test.h"
#include "test_globals.h"

#include <dylocxx/init.h>
#include <dylocxx/unit_locality.h>
#include <dylocxx/hwinfo.h>

#include <dylocxx/utility.h>
#include <dylocxx/adapter/dart.h>
#include <dylocxx/internal/logging.h>

#include <boost/graph/graph_utility.hpp>
#include <boost/graph/depth_first_search.hpp>

namespace dyloc {
namespace test {

//TEST_F(TopologyTest, DistanceMetric) {
//  dyloc::init(&TESTENV.argc, &TESTENV.argv);
//
//  auto & topo = dyloc::team_topology();
//
//  const auto & dom_source = topo[".0.0.0.0.0.0"];
//  const auto & dom_target = topo[".0.0.0.0.0.0.0"];
//
//  auto dist_fn = [&](const auto & a,
//                     const auto & b){
//    return (7 - topo.ancestor({a.domain_tag, b.domain_tag}).level) *10; };
//
//  std::string metric_name = "user_metric";
//  topo.add_distance_metric(metric_name, dist_fn);
//
//  DYLOC_LOG_DEBUG("TopologyTest.DistanceMetric", "Metrics:");
//  auto dist_metrics = topo.list_distance_metrics();
//  DYLOC_LOG_DEBUG("TopologyTest.DistanceMetric", dist_metrics);
//
//  ASSERT_EQ(10, topo.calculate_distance(dom_source, dom_target, metric_name));
//
//  std::for_each(topo.domains().begin(),
//	        topo.domains().end(),
//		[&](const auto & target){
//    std::cout << "Distance ("<< metric_name <<") from " << dom_source.domain_tag << " to " << target.first << " >> " << std::to_string(topo.calculate_distance(dom_source,target.second, metric_name)) << std::endl;
//                 });
//
//  graphviz_out(topo.graph(), "testgraph.dot");
//
//  dyloc::finalize();
//}

TEST_F(TopologyTest, PartitionTest) {
  dyloc::init(&TESTENV.argc, &TESTENV.argv);
  auto & topo = dyloc::team_topology();

  locality_domain_dfs_output_visitor<typename topology::domain_map>
    vis(topo.domains());

  DYLOC_LOG_DEBUG("TopologyTest.PartitionTest", "total domain hierarchy:");
  graphviz_out(topo.graph(), "PartitionTest_orig.dot");
  if (dyloc::myid().id == 0) {
    topo.depth_first_search(vis);
  }
  dart_barrier(DART_TEAM_ALL);
  topo.partition_CU();
  graphviz_out(topo.graph(), "PartitionTest_changed.dot");

  dyloc::finalize();
}

//TEST_F(TopologyTest, AddandRemoveConnection) {
//  dyloc::init(&TESTENV.argc, &TESTENV.argv);
//  auto & topo = dyloc::team_topology();
//  DYLOC_LOG_DEBUG("connect()","start testing");
//  const std::string source_tag = ".0";
//  const std::string target_tag = ".0.0.0.0";
//
//  DYLOC_LOG_DEBUG("attempting to connect",source_tag, target_tag);
//  //same source/target but different types of edges
//  auto edge1 = topo.connect(source_tag, target_tag, topology::edge_properties{topology::edge_type::contains, 42});
//  auto edge2 = topo.connect(source_tag, target_tag, topology::edge_properties{topology::edge_type::logical, 43});
//  ASSERT_EQ(1, edge1.second);
//  ASSERT_EQ(1, edge2.second);
//  auto edge3 = topo.connect(source_tag, target_tag, topology::edge_properties{topology::edge_type::contains, 42});
//  ASSERT_NE(0, edge3.second);// 2 same connections? TODO!?
//  DYLOC_LOG_DEBUG("connected sucessfully","Assertion completed");
//  graphviz_out(topo.graph(), "testgraph1.dot");
//  //-> disconnect
//  topo.disconnect(edge1.first);
//  topo.disconnect(edge2.first);
//  topo.disconnect(edge3.first);
//
////ASSERT_EQ(topo,topo_cpy); would have to implement operator= (check all members for equality)
//  graphviz_out(topo.graph(), "testgraph2.dot");
//
//  dyloc::finalize();
//}

//TEST_F(TopologyTest, ExcludeDomains) {
//  dyloc::init(&TESTENV.argc, &TESTENV.argv);
//
//  auto & topo = dyloc::team_topology();
//  locality_domain_dfs_output_visitor<typename topology::domain_map>
//    vis(topo.domains());
//
//  DYLOC_LOG_DEBUG("TopologyTest.ExcludeDomains", "total domain hierarchy:");
//  if (dyloc::myid().id == 0) {
//    topo.depth_first_search(vis);
//  }
//  dart_barrier(DART_TEAM_ALL);
//
//  std::vector<std::string> excluded_domain_tags;
//  excluded_domain_tags.push_back(".0.0");
//
//  topo.exclude_domains(
//    excluded_domain_tags.begin(),
//    excluded_domain_tags.end());
//
//  if (dyloc::myid().id == 0) {
//    DYLOC_LOG_DEBUG("TopologyTest.ExcludeDomains",
//                    "domain hierarchy after excludes:");
//    topo.depth_first_search(vis);
//  }
//
//  ASSERT_EQ(0, topo.domains().count(".0.0"));
//
//  dyloc::finalize();
//}
//
//TEST_F(TopologyTest, DomainsAncestor) {
//  dyloc::init(&TESTENV.argc, &TESTENV.argv);
//
//  auto & topo = dyloc::team_topology();
//  locality_domain_dfs_output_visitor<typename topology::domain_map>
//    vis(topo.domains());
//
//  DYLOC_LOG_DEBUG("TopologyTest.DomainsAncestor", "total domain hierarchy:");
//  if (dyloc::myid().id == 0) {
//    topo.depth_first_search(vis);
//  }
//  dart_barrier(DART_TEAM_ALL);
//
//  int myid = dyloc::myid().id;
//
//  // Find ancestor domain from this vector of unit ids:
//  //
//  std::vector<dart_global_unit_t> unit_ids;
//  unit_ids.push_back(dyloc::myid());
//  for (int nd = 0; nd < std::min<int>(2, topo.domains().size()); ++nd) {
//    std::srand((nd + 1) * (myid + 1));
//    int random_unit_id = std::rand() % dyloc::num_units();
//    unit_ids.push_back(random_unit_id);
//  }
//
//  // Unit ids to domain tags:
//  //
//  std::vector<std::string> unit_domain_tags(unit_ids.size());
//  std::transform(unit_ids.begin(), unit_ids.end(),
//                 unit_domain_tags.begin(),
//                 [&](const dart_global_unit_t uid) -> std::string {
//                   auto unit_dom_tag = topo[uid].domain_tag;
//                   DYLOC_LOG_DEBUG_VAR("TopologyTest.DomainsAncestor",
//                                       unit_dom_tag);
//                   return unit_dom_tag;
//                 });
//
//  // Ancestor from unit domain tags:
//  //
//  const auto & ancestor = topo.ancestor(
//                            unit_domain_tags.begin(),
//                            unit_domain_tags.end());
//  for (const dart_global_unit_t & uid : unit_ids) {
//    ASSERT_NE(ancestor.unit_ids.end(),
//              std::find(ancestor.unit_ids.begin(),
//                        ancestor.unit_ids.end(),
//                        uid));
//  }
//  DYLOC_LOG_DEBUG_VAR("TopologyTest.DomainsAncestor", ancestor);
//
//  dyloc::finalize();
//}
//
//TEST_F(TopologyTest, ScopeDomains) {
//  dyloc::init(&TESTENV.argc, &TESTENV.argv);
//
//  auto & topo = dyloc::team_topology();
//  locality_domain_dfs_output_visitor<typename topology::domain_map>
//    vis(topo.domains());
//
//  DYLOC_LOG_DEBUG("TopologyTest.ScopeDomains", "total domain hierarchy:");
//  if (dyloc::myid().id == 0) {
//    topo.depth_first_search(vis);
//  }
//  dart_barrier(DART_TEAM_ALL);
//
//  // Tags of locality domains in CORE scope:
//  auto core_domain_tags = topo.scope_domain_tags(
//                            DYLOC_LOCALITY_SCOPE_CORE);
//  ASSERT_LT(0, core_domain_tags.size());
//  for (const auto & core_domain_tag : core_domain_tags) {
//    DYLOC_LOG_DEBUG_VAR("TopologyTest.ScopeDomains", core_domain_tag);
//    auto core_dom_it = topo.domains().find(core_domain_tag);
//    ASSERT_NE(topo.domains().end(), core_dom_it);
//    ASSERT_EQ(DYLOC_LOCALITY_SCOPE_CORE, core_dom_it->second.scope);
//  }
//
//  // Tags of locality domains in NUMA scope:
//  auto numa_domain_tags = topo.scope_domain_tags(
//                            DYLOC_LOCALITY_SCOPE_NUMA);
//  ASSERT_LT(0, numa_domain_tags.size());
//  for (const auto & numa_domain_tag : numa_domain_tags) {
//    DYLOC_LOG_DEBUG_VAR("TopologyTest.ScopeDomains", numa_domain_tag);
//    auto numa_dom_it = topo.domains().find(numa_domain_tag);
//    ASSERT_NE(topo.domains().end(), numa_dom_it);
//    ASSERT_EQ(DYLOC_LOCALITY_SCOPE_NUMA, numa_dom_it->second.scope);
//  }
//
//  dyloc::finalize();
//}

} // namespace dyloc
} // namespace test


text:
#include "CorePch.h"
#include <rtp++/rfc2326/RtspUtil.h>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/regex.hpp>
#include <cpputil/Conversion.h>

namespace rtp_plus_plus
{
namespace rfc2326
{

bool extractRtspInfo(const std::string& sRtspMessage, std::string& sRequest,
                     std::string& sRtspUri, std::string& sRtspVersion)
{
  boost::regex rtspUri_regex("(OPTIONS|DESCRIBE|SETUP|PLAY|PAUSE|TEARDOWN|GET_PARAMETER|SET_PARAMETER) (rtsp://[^ ]+) RTSP/(1.0)");

  std::istringstream istr(sRtspMessage);
  std::string sLine;
  if (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, rtspUri_regex))
    {
//      std::cout << "Matched: \"" << match[0] << " and " << match[1] << " and " << match[2] << "\n";
      sRequest = match[1];
      sRtspUri = match[2];
      sRtspVersion = match[3];
      return true;
    }
  }
  LOG(INFO) << "No match";
  return false;
}

bool getCSeq(const std::string& sRtspMessage, uint32_t& uiCSeq)
{
  boost::regex cseq_regex("(CSeq: )(\\d+)");

  std::istringstream istr(sRtspMessage);
  std::string sLine;
  while (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, cseq_regex))
    {
//      std::cout << "Matched: \"" << match[0] << " and " << match[1] << " and " << match[2] << "\n";
      bool bDummy;
      uiCSeq = convert<uint32_t>(match[2], bDummy);
      assert(bDummy);
      return true;
    }
  }
  LOG(INFO) << "No match";
  return false;
}

bool getCSeqString(const std::string& sRtspMessage, std::string& sCSeq)
{
  boost::regex cseq_regex("(CSeq: )(\\d+)");

  std::istringstream istr(sRtspMessage);
  std::string sLine;
  while (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, cseq_regex))
    {
//      std::cout << "Matched: \"" << match[0] << " and " << match[1] << " and " << match[2] << "\n";
      sCSeq = match[2];
      return true;
    }
  }
  LOG(INFO) << "No match";
  return false;
}

bool getContentLength(const std::string& sRtspMessage, uint32_t& uiContentLength)
{
  boost::regex content_length_regex("(Content-Length: )(\\d+)");
  std::istringstream istr(sRtspMessage);
  std::string sLine;
  while (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, content_length_regex))
    {
      bool bDummy;
      uiContentLength = convert<uint32_t>(match[2], bDummy);
      assert(bDummy);
      return true;
    }
  }
  return false;
}

bool getContentLengthString(const std::string& sRtspMessage, std::string& sContentLength)
{
  boost::regex content_length_regex("(Content-Length: )(\\d+)");
  std::istringstream istr(sRtspMessage);
  std::string sLine;
  while (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, content_length_regex))
    {
      sContentLength = match[2];
      return true;
    }
  }
  return false;
}

std::string getCurrentDateString()
{
  boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time();

  // Format dates and times
  boost::posix_time::time_facet* output_facet = new boost::posix_time::time_facet();

  std::stringstream ss;
  ss.imbue(std::locale(std::locale::classic(), output_facet));
  output_facet->format("%a, %d %b %Y %H:%M:%S GMT");

  ss.str("");
  ss << t;
  return ss.str();
}

bool getTransport(const std::string& sRtspMessage, Transport& transport)
{
  std::istringstream istr(sRtspMessage);
  std::string sLine;
  while (std::getline(istr, sLine))
  {
    if (boost::algorithm::starts_with(sLine, "Transport: "))
    {
      Transport t(sLine.substr(11));
      transport = t;
      return t.isValid();
    }
  }
  return false;
}

std::string createErrorResponse(ResponseCode eCode, uint32_t CSeq, const std::vector<std::string>& vSupported, const std::vector<std::string>& vUnsupported)
{
  return createErrorResponse(eCode, toString(CSeq), vSupported, vUnsupported);
}

std::string createErrorResponse(ResponseCode eCode, const std::string& CSeq, const std::vector<std::string>& vSupported, const std::vector<std::string>& vUnsupported)
{
#if 1
  std::ostringstream ostr;
  ostr << "RTSP/1.0 " << (uint32_t)eCode << " " << responseCodeString(eCode) << "\r\n";
  ostr << "CSeq: " << CSeq << "\r\n";
  ostr << "Date: " << rfc2326::getCurrentDateString() << "\r\n";

  if (!vSupported.empty())
  {
    ostr << toString(vSupported) << "\r\n";
  }

  if (!vUnsupported.empty())
  {
    ostr << toString(vUnsupported) << "\r\n";
  }

  ostr << "\r\n";
  return ostr.str();
#else
  std::string ERROR_RESPONSE="RTSP/1.0 <<Code>> <<ResponseCodeString>>\r\n"\
      "CSeq: <<CSeq>>\r\n"\
      "Date: <<Date>>\r\n\r\n";

  boost::algorithm::replace_first(ERROR_RESPONSE, "<<Code>>", ::toString((uint32_t)eCode));
  boost::algorithm::replace_first(ERROR_RESPONSE, "<<ResponseCodeString>>", responseCodeString(eCode));
  boost::algorithm::replace_first(ERROR_RESPONSE, "<<CSeq>>", CSeq);
  boost::algorithm::replace_first(ERROR_RESPONSE, "<<Date>>", rfc2326::getCurrentDateString());
  return ERROR_RESPONSE;
#endif
}

}
}


text:
#pragma once
#include <Eigen/Dense>

struct InternalBoundingBox
{
	/// The position of the box's corner that has the least coordinate value in all axes.
	Eigen::Vector3i pos;
	/// The extents of the cube.
	Eigen::Vector3i span;

	static bool IsPointInCube(const InternalBoundingBox& cube, Eigen::Vector3i point)
	{
		bool xIntersects = cube.pos.x() <= point.x() && cube.pos.x() + cube.span.x() > point.x();
		bool yIntersects = cube.pos.y() <= point.y() && cube.pos.y() + cube.span.y() > point.y();
		bool zIntersects = cube.pos.z() <= point.z() && cube.pos.z() + cube.span.z() > point.z();
		return xIntersects && yIntersects && zIntersects;
	}

	static bool CubesIntersect(const InternalBoundingBox& cube1, const InternalBoundingBox& cube2)
	{
		bool xIntersects = !(cube2.pos.x() + cube2.span.x() <= cube1.pos.x() || cube1.pos.x() + cube1.span.x() <= cube2.pos.x());
		bool yIntersects = !(cube2.pos.y() + cube2.span.y() <= cube1.pos.y() || cube1.pos.y() + cube1.span.y() <= cube2.pos.y());
		bool zIntersects = !(cube2.pos.z() + cube2.span.z() <= cube1.pos.z() || cube1.pos.z() + cube1.span.z() <= cube2.pos.z());
		return xIntersects && yIntersects && zIntersects;
	}

	static void SplitCube(const InternalBoundingBox& cube, InternalBoundingBox children[8])
	{
		Eigen::Vector3i newSpan = cube.span / 2;

		children[0].pos = { cube.pos.x(), cube.pos.y(), cube.pos.z() };
		children[0].span = newSpan;

		children[1].pos = { cube.pos.x(), cube.pos.y(), cube.pos.z() + newSpan.z() };
		children[1].span = newSpan;

		children[2].pos = { cube.pos.x(), cube.pos.y() + newSpan.y(), cube.pos.z() };
		children[2].span = newSpan;

		children[3].pos = { cube.pos.x(), cube.pos.y() + newSpan.y(), cube.pos.z() + newSpan.z() };
		children[3].span = newSpan;

		children[4].pos = { cube.pos.x() + newSpan.x(), cube.pos.y(), cube.pos.z() };
		children[4].span = newSpan;

		children[5].pos = { cube.pos.x() + newSpan.x(), cube.pos.y(), cube.pos.z() + newSpan.z() };
		children[5].span = newSpan;

		children[6].pos = { cube.pos.x() + newSpan.x(), cube.pos.y() + newSpan.y(), cube.pos.z() };
		children[6].span = newSpan;

		children[7].pos = { cube.pos.x() + newSpan.x(), cube.pos.y() + newSpan.y(), cube.pos.z() + newSpan.z() };
		children[7].span = newSpan;
	}

	friend std::ostream& operator<<(std::ostream& os, const InternalBoundingBox& cube)
	{
		os << '[' << cube.pos.x() << ", " << cube.pos.y() << ", " << cube.pos.z() << "] -> "
			<< '[' << cube.pos.x() + cube.span.x() - 1 << ", " << cube.pos.y() + cube.span.y() - 1 <<
			", " << cube.pos.z() + cube.span.z() - 1 << ']';
		return os;
	}
};

ext: hpp

max_stars_repo_name: handsomePirate/VoxelViewer

max_issues_repo_name: handsomePirate/VoxelViewer

max_forks_repo_name: handsomePirate/VoxelViewer


text:
#ifndef PYBNESIAN_FACTORS_ASSIGNMENT_HPP
#define PYBNESIAN_FACTORS_ASSIGNMENT_HPP

#include <variant>
#include <Eigen/Dense>
#include <util/hash_utils.hpp>

using Eigen::VectorXi;

namespace factors {

class AssignmentValue {
public:
    AssignmentValue() = default;
    AssignmentValue(const std::string& v) : m_value(v) {}
    AssignmentValue(double v) : m_value(v) {}
    AssignmentValue(const AssignmentValue&) = default;
    AssignmentValue(std::variant<std::string, double> v) : m_value(v) {}

    bool operator==(const std::string& other) const {
        if (const auto* v = std::get_if<std::string>(&m_value)) {
            return *v == other;
        } else {
            return false;
        }

        // The std::visit would require MacOS 10.14
        // ----------------------------------------
        // return std::visit(
        //     [&other](auto&& v) {
        //         using T = std::decay_t<decltype(v)>;
        //         if constexpr (std::is_same_v<std::string, T>)
        //             return v == other;
        //         else
        //             return false;
        //     },
        //     m_value);
    }

    bool operator!=(const std::string& other) const { return !(*this == other); }

    bool operator==(double other) const {
        if (const auto* v = std::get_if<double>(&m_value)) {
            return *v == other;
        } else {
            return false;
        }

        // The std::visit would require MacOS 10.14
        // ----------------------------------------
        // return std::visit(
        //     [other](auto&& v) {
        //         using T = std::decay_t<decltype(v)>;
        //         if constexpr (std::is_same_v<double, T>)
        //             return v == other;
        //         else
        //             return false;
        //     },
        //     m_value);
    }

    bool operator!=(double other) const { return !(*this == other); }

    bool operator==(const AssignmentValue& other) const { return m_value == other.m_value; }

    bool operator!=(const AssignmentValue& other) const { return !(*this == other); }

    size_t hash() const {
        if (const auto* v = std::get_if<double>(&m_value)) {
            std::hash<double> h;
            return h(*v);
        } else {
            std::hash<std::string> h;
            return h(*std::get_if<std::string>(&m_value));
        }

        // The std::visit would require MacOS 10.14
        // ----------------------------------------
        // return std::visit([](auto&& v) { return std::hash<std::decay_t<decltype(v)>>{}(v); }, m_value);
    }

    operator std::string() const {
        auto str = std::get_if<std::string>(&m_value);

        if (str) {
            return *str;
        } else {
            throw std::runtime_error("Assignment value is not string.");
        }
    }

    operator double() const {
        auto v = std::get_if<double>(&m_value);

        if (v) {
            return *v;
        } else {
            throw std::runtime_error("Assignment value is not double.");
        }
    }

    std::string ToString() const {
        if (const auto* v = std::get_if<double>(&m_value)) {
            return std::to_string(*v);
        } else {
            return *std::get_if<std::string>(&m_value);
        }

        // The std::visit would require MacOS 10.14
        // ----------------------------------------
        // return std::visit(
        //     [](auto&& v) {
        //         using T = std::decay_t<decltype(v)>;
        //         if constexpr (std::is_same_v<std::string, T>)
        //             return v;
        //         else if constexpr (std::is_same_v<double, T>)
        //             return std::to_string(v);
        //         else
        //             static_assert(util::always_false<T>, "Not supported type.");
        //     },
        //     m_value);
    }

    const std::variant<std::string, double>& value() const { return m_value; }

    py::object __getstate__() const {
        if (const auto* v = std::get_if<double>(&m_value)) {
            return py::cast(*v);
        } else {
            return py::cast(*std::get_if<std::string>(&m_value));
        }

        // The std::visit would require MacOS 10.14
        // ----------------------------------------
        // return py::cast(m_value);
    }

    static AssignmentValue __setstate__(py::object& o) {
        PyObject* py_ptr = o.ptr();

        if (PyFloat_Check(py_ptr)) {
            return AssignmentValue(o.cast<double>());
        } else {
            return AssignmentValue(o.cast<std::string>());
        }
    }

private:
    std::variant<std::string, double> m_value;
};

class Assignment {
public:
    using iterator = typename std::unordered_map<std::string, AssignmentValue>::iterator;
    using const_iterator = typename std::unordered_map<std::string, AssignmentValue>::const_iterator;
    using value_type = typename std::unordered_map<std::string, AssignmentValue>::value_type;
    using size_type = typename std::unordered_map<std::string, AssignmentValue>::size_type;

    Assignment() = default;
    Assignment(std::unordered_map<std::string, AssignmentValue> ass) : m_assignment(ass) {}
    Assignment(const Assignment&) = default;

    // Based on the hashing of a frozenset
    // https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation
    // https://github.com/python/cpython/blob/main/Objects/setobject.c
    size_t hash() const {
        size_t hash = 0;

        std::hash<std::string> hfunction;

        for (const auto& item : m_assignment) {
            auto partial_hash = hfunction(item.first);
            util::hash_combine(partial_hash, item.second.hash());

            hash ^= ((partial_hash ^ 89869747UL) ^ (partial_hash << 16)) * 3644798167UL;
        }

        /* Factor in the number of active entries */
        hash ^= (m_assignment.size() + 1) * 1927868237UL;
        // hash = hash * 69069U + 907133923UL;

        return hash;
    }

    const AssignmentValue& value(const std::string& var) const {
        auto it = m_assignment.find(var);

        if (it == m_assignment.end()) {
            throw std::invalid_argument("Variable " + var + " not found in the assignment.");
        }

        return it->second;
    }

    template <typename It>
    bool has_variables(It begin, It end) const {
        for (auto it = begin; it != end; ++it) {
            if (m_assignment.find(*it) == m_assignment.end()) return false;
        }

        return true;
    }

    size_t index(const std::vector<std::string>& variables,
                 const std::vector<std::vector<std::string>>& variable_values,
                 const VectorXi& strides) const {
        size_t index = 0;

        for (size_t i = 0; i < variables.size(); ++i) {
            auto it = std::find(
                variable_values[i].begin(), variable_values[i].end(), static_cast<std::string>(value(variables[i])));

            if (it == variable_values[i].end()) {
                throw std::invalid_argument("Category \"" + static_cast<std::string>(value(variables[i])) +
                                            "\" is not valid for variable " + variables[i]);
            }

            auto vindex = std::distance(variable_values[i].begin(), it);

            index += vindex * strides(i);
        }

        return index;
    }

    static Assignment from_index(int index,
                                 const std::vector<std::string>& variables,
                                 const std::vector<std::vector<std::string>>& variable_values,
                                 const VectorXi& cardinality,
                                 const VectorXi& strides) {
        std::unordered_map<std::string, AssignmentValue> map;

        for (size_t i = 0, i_end = variables.size(); i < i_end; ++i) {
            auto vindex = (index / strides(i)) % cardinality(i);

            map.insert({variables[i], variable_values[i][vindex]});
        }

        return Assignment(map);
    }

    bool empty() const noexcept { return m_assignment.empty(); }

    size_type size() const noexcept { return m_assignment.size(); }

    std::pair<iterator, bool> insert(const value_type& value) { return m_assignment.insert(value); }

    std::pair<iterator, bool> insert(value_type&& value) {
        return m_assignment.insert(std::forward<value_type>(value));
    }

    void erase(const std::string& value) { m_assignment.erase(value); }

    const_iterator begin() const noexcept { return m_assignment.begin(); }

    const_iterator cbegin() const noexcept { return m_assignment.cbegin(); }

    const_iterator end() const noexcept { return m_assignment.end(); }

    const_iterator cend() const noexcept { return m_assignment.cend(); }

    std::string ToString() const {
        if (m_assignment.empty()) {
            return "[]";
        } else {
            std::stringstream ss;
            auto begin = m_assignment.begin();
            ss << "[" << begin->first << " = " << begin->second.ToString();

            for (auto it = ++begin, end = m_assignment.end(); it != end; ++it) {
                ss << ", " << it->first << " = " << it->second.ToString();
            }

            ss << "]";

            return ss.str();
        }
    }

    bool operator==(const Assignment& other) const { return m_assignment == other.m_assignment; }

    bool operator!=(const Assignment& other) const { return m_assignment != other.m_assignment; }

    py::object __getstate__() const { return py::cast(m_assignment); }

    static Assignment __setstate__(py::object& o) {
        return Assignment(o.cast<std::unordered_map<std::string, AssignmentValue>>());
    }

private:
    std::unordered_map<std::string, AssignmentValue> m_assignment;
};

struct AssignmentHash {
    size_t operator()(const Assignment& ass) const { return ass.hash(); }
};

}  // namespace factors

namespace pybind11::detail {

template <>
struct type_caster<factors::AssignmentValue> {
public:
    /**
     * This macro establishes the name 'inty' in
     * function signatures and declares a local variable
     * 'value' of type inty
     */
    PYBIND11_TYPE_CASTER(factors::AssignmentValue, _("AssignmentValue"));

    /**
     * Conversion part 1 (Python->C++): convert a PyObject into a inty
     * instance or return false upon failure. The second argument
     * indicates whether implicit conversions should be applied.
     */
    bool load(handle src, bool) {
        PyObject* py_ptr = src.ptr();

        if (PyUnicode_Check(py_ptr)) {
            value = factors::AssignmentValue(src.cast<std::string>());
            return true;
        } else if (PyFloat_Check(py_ptr)) {
            value = factors::AssignmentValue(src.cast<double>());
            return true;
        } else if (PyLong_Check(py_ptr)) {
            value = PyLong_AsDouble(py_ptr);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Conversion part 2 (C++ -> Python): convert an inty instance into
     * a Python object. The second and third arguments are used to
     * indicate the return value policy and parent object (for
     * ``return_value_policy::reference_internal``) and are generally
     * ignored by implicit casters.
     */
    static handle cast(const factors::AssignmentValue& src, return_value_policy /* policy */, handle /* parent */) {
        if (const auto* v = std::get_if<double>(&src.value())) {
            return PyFloat_FromDouble(*v);
        } else {
            const auto* pstr = std::get_if<std::string>(&src.value());
            return py::cast(*pstr).release();
        }
    }
};

}  // namespace pybind11::detail

#endif  // PYBNESIAN_FACTORS_ASSIGNMENT_HPP

max_stars_repo_name: vishalbelsare/PyBNesian

max_issues_repo_name: vishalbelsare/PyBNesian

max_forks_repo_name: vishalbelsare/PyBNesian


text:
//#include <boost/filesystem.hpp>
#include <fstream>
#include <stdlib.h>

#include "points.h"
#include "filenames.h"
#include "cmd_flags.h"

DEFINE_string(input,kRequired,"","File with paths to point clouds");
DEFINE_bool(colours,kOptional,false,"If the point clouds have colour info or not. Default: false(no colours)");
DEFINE_string(labels,kRequired,"","File with the paths point cloud labels");
//DEFINE_string(output_path, kOptional, "./", "Where to save ocnn point clouds");

using std::cout;
using std::vector;

const vector<int> to_be_ignored={0,32,33};
const int ignore_label=-2;

int main(int argc, char* argv[]) {
  bool succ = cflags::ParseCmd(argc, argv);
  if (!succ) {
    cflags::PrintHelpInfo("nUsage: custom_points input_file label_dir [colours]");
    return 0;
  }

  Points point_cloud;
  vector<float> points, normals, features, labels;
  float x,y,z,nx,ny,nz,r,g,b,a;
  int l;
  // Set your data in points, normals, features, and labels.
  // The points must not be empty, the labels may be empty,
  // the normals & features must not be empty at the same time.
  //   points: 3 channels, x_1, y_1, z_1, ..., x_n, y_n, z_n
  //   normals: 3 channels, nx_1, ny_1, nz_1, ..., nx_n, ny_n, nz_n
  //   features (such as RGB color): k channels, r_1, g_1, b_1, ..., r_n, g_n, b_n
  //   labels: 1 channels, per-points labels

  vector <string> _all_files;
  std::ifstream f(FLAGS_input);
  string line;

  //Read point files
  if (f.good()){
      while(f>>line)
        _all_files.push_back(line);
      f.close();
  }
  else{
      std::cout<<"Input file could not be opened. Exiting..."<<std::endl;
      exit(EXIT_FAILURE);
  }
  vector <string> _all_labels;
  std::ifstream  fl(FLAGS_labels);
  if (fl.good()){
      while(fl>>line)
        _all_labels.push_back(line);
      fl.close();
  }
  else{
      std::cout<<"Label file could not be opened. Exiting..."<<std::endl;
      exit(EXIT_FAILURE);
  }

// int cnt=0;
  for (int i=0;i<_all_files.size();i++){
    points.clear();normals.clear();features.clear();labels.clear();

    std::cout<<"Processing file: "<<_all_files[i]<<std::endl;
    std::ifstream infile(_all_files[i]);
    std::ifstream lfile(_all_labels[i]);
    string out_path=_all_files[i].substr(0,_all_files[i].rfind('.'));
    if (infile.good()){
        if (_all_files[i].find(".ply",0)!= string::npos){
//            std::cout<<"ply file"<<std::endl;
            infile>>line;
            while(line.find("end_header")){
//                std::cout<<line<<std::endl;
                infile>>line;
            }
        }
        while(infile >>x>>y>>z>>nx>>ny>>nz){
             points.push_back(x);
             points.push_back(y);
             points.push_back(z);
             normals.push_back(nx);
             normals.push_back(ny);
             normals.push_back(nz);

             if (FLAGS_colours){
                 infile>>r>>g>>b>>a;
                 features.push_back(r);
                 features.push_back(g);
                 features.push_back(b);
                 features.push_back(a);
             }

            lfile>>line>>l>>line;
            labels.push_back(l);
//            std::cout<<line<<","<<l<<std::endl;
//            if (std::count(to_be_ignored.begin(), to_be_ignored.end(), l)){
//                labels.push_back(ignore_label);
////                    std::cout<<"ignore label"<<std::endl;                exit(1);
////                    cnt++;
//            }else
//                labels.push_back(l-1);

            //std::cout<<x<<" "<<y<<" "<<z<<" "<<nx<<" "<<ny<<" "<<nz<<" "<<r<<" "<<g<<" "<<b<<" "<<l<<std::endl;
            //exit(0);
        }
        point_cloud.set_points(points, normals, features, labels);
        point_cloud.write_points(out_path +  "_OCNN.points");
//        std::cout<<"# of -2: "<<cnt<<std::endl;
    }
    else{
        std::cout<<"couldnt open file "<<_all_files[i]<<std::endl;
        exit(EXIT_FAILURE);
    }
  }

std::cout<<"Done."<<std::endl;
}


text:
//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one or more
// contributor license agreements. See the NOTICE file distributed with this
// work for additional information regarding copyright ownership.  Green Enery
// Corp licenses this file to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance with the
// License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations
// under the License.
//

#include <boost/bind.hpp>

#include <opendnp3/APL/Logger.h>
#include <opendnp3/APL/Util.h>

#include "DNPConstants.h"
#include "Objects.h"
#include "ResponseContext.h"
#include "SlaveResponseTypes.h"

using namespace boost;

namespace apl
{
namespace dnp
{

ResponseContext::ResponseKey::ResponseKey() : mType(RT_STATIC), mOrder(0)
{}

ResponseContext::ResponseKey::ResponseKey(ResponseContext::RequestType aType, size_t aOrder) : mType(aType), mOrder(aOrder)
{}

// custom less than function used by STL
bool ResponseContext::ResponseKey::operator()(const ResponseContext::ResponseKey& a, const ResponseContext::ResponseKey& b) const
{
	if(a.mType < b.mType) return true;
	else if(a.mType > b.mType) return false;
	else {
		return a.mOrder < b.mOrder;
	}
}

ResponseContext::ResponseContext(Logger* apLogger, Database* apDB, SlaveResponseTypes* apRspTypes, const EventMaxConfig& arEventMaxConfig) :
	Loggable(apLogger),
	mBuffer(arEventMaxConfig),
	mMode(UNDEFINED),
	mpDB(apDB),
	mFIR(true),
	mFIN(false),
	mpRspTypes(apRspTypes),
	mLoadedEventData(false)
{}

void ResponseContext::Reset()
{
	mFIR = true;
	mLoadedEventData = false;
	mMode = UNDEFINED;
	mTempIIN.Zero();

	this->mStaticWriteMap.clear();

	this->mBinaryEvents.clear();
	this->mAnalogEvents.clear();
	this->mCounterEvents.clear();
	this->mVtoEvents.clear();

	mBuffer.Deselect();
}

void ResponseContext::ClearWritten()
{
	size_t written = mBuffer.ClearWritten();

	size_t deselected = mBuffer.Deselect();

	LOG_BLOCK(LEV_DEBUG, "Clearing written events: " << written << " deselected: " << deselected);
}

void ResponseContext::ClearAndReset()
{
	this->ClearWritten();
	this->Reset();
}

inline size_t GetEventCount(const HeaderInfo& arHeader)
{
	switch(arHeader.GetQualifier()) {
	case QC_1B_CNT:
	case QC_2B_CNT:
		return arHeader.GetCount();
	default:
		return std::numeric_limits<size_t>::max();
	}
}

IINField ResponseContext::Configure(const APDU& arRequest)
{
	this->Reset();
	mMode = SOLICITED;

	for (HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) {
		/*
		 * Handle all of the objects that only use a Group identifier.  The
		 * switch statement is responsible for selecting all of the events
		 * that are in the various queues that could be used to respond to the
		 * arRequest message.  Then a separate handler will loop through and
		 * cherry pick the events that will make it into the response.
		 *
		 * For this first switch statement set, use "continue" rather than
		 * "break" so that control loops back around to the for loop.
		 */
		switch (hdr->GetGroup()) {
			/* Virtual Terminal Objects */
		case 113:
			this->SelectVtoEvents(PC_ALL_EVENTS, Group113Var0::Inst(), GetEventCount(hdr.info()));
			continue;
		default:
			/*
			 * Note: the next switch statement's default statement will
			 * catch unknown object types.
			 */
			break;
		}

		/* Handle all of the objects that have a Group/Variation tuple */
		switch (MACRO_DNP_RADIX(hdr->GetGroup(), hdr->GetVariation())) {

		case(MACRO_DNP_RADIX(1, 0)):
			this->RecordStaticObjects<BinaryInfo>(mpRspTypes->mpStaticBinary, hdr);
			break;
		case(MACRO_DNP_RADIX(1, 2)):
			this->RecordStaticObjects<BinaryInfo>(Group1Var2::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(10, 0)):
			this->RecordStaticObjects<ControlStatusInfo>(mpRspTypes->mpStaticControlStatus, hdr);
			break;
		case(MACRO_DNP_RADIX(10, 2)):
			this->RecordStaticObjects<ControlStatusInfo>(Group10Var2::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 0)):
			this->RecordStaticObjects<CounterInfo>(mpRspTypes->mpStaticCounter, hdr);
			break;
		case(MACRO_DNP_RADIX(20, 1)):
			this->RecordStaticObjects<CounterInfo>(Group20Var1::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 2)):
			this->RecordStaticObjects<CounterInfo>(Group20Var2::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 3)):
			this->RecordStaticObjects<CounterInfo>(Group20Var3::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 4)):
			this->RecordStaticObjects<CounterInfo>(Group20Var4::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 5)):
			this->RecordStaticObjects<CounterInfo>(Group20Var5::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 6)):
			this->RecordStaticObjects<CounterInfo>(Group20Var6::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 7)):
			this->RecordStaticObjects<CounterInfo>(Group20Var7::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(20, 8)):
			this->RecordStaticObjects<CounterInfo>(Group20Var8::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 0)):
			this->RecordStaticObjects<AnalogInfo>(mpRspTypes->mpStaticAnalog, hdr);
			break;
		case(MACRO_DNP_RADIX(30, 1)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var1::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 2)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var2::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 3)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var3::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 4)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var4::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 5)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var5::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(30, 6)):
			this->RecordStaticObjects<AnalogInfo>(Group30Var6::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(40, 0)):
			this->RecordStaticObjects<SetpointStatusInfo>(mpRspTypes->mpStaticSetpointStatus, hdr);
			break;
		case(MACRO_DNP_RADIX(40, 1)):
			this->RecordStaticObjects<SetpointStatusInfo>(Group40Var1::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(40, 2)):
			this->RecordStaticObjects<SetpointStatusInfo>(Group40Var2::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(40, 3)):
			this->RecordStaticObjects<SetpointStatusInfo>(Group40Var3::Inst(), hdr);
			break;
		case(MACRO_DNP_RADIX(40, 4)):
			this->RecordStaticObjects<SetpointStatusInfo>(Group40Var4::Inst(), hdr);
			break;

			// event objects
		case(MACRO_DNP_RADIX(2, 0)):
			this->SelectEvents(PC_ALL_EVENTS, mpRspTypes->mpEventBinary, mBinaryEvents, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(22, 0)):
			this->SelectEvents(PC_ALL_EVENTS, mpRspTypes->mpEventCounter, mCounterEvents, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(32, 0)):
			this->SelectEvents(PC_ALL_EVENTS, mpRspTypes->mpEventAnalog, mAnalogEvents, GetEventCount(hdr.info()));
			break;

			//specific objects
		case(MACRO_DNP_RADIX(2, 1)):
			this->SelectEvents(PC_ALL_EVENTS, Group2Var1::Inst(), mBinaryEvents, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(2, 2)):
			this->SelectEvents(PC_ALL_EVENTS, Group2Var2::Inst(), mBinaryEvents, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(2, 3)):
			this->SelectEvents(PC_ALL_EVENTS, Group2Var3::Inst(), mBinaryEvents, GetEventCount(hdr.info()));
			break;

			// Class Objects
		case(MACRO_DNP_RADIX(60, 1)):
			this->RecordStaticObjects<BinaryInfo>(mpRspTypes->mpStaticBinary, hdr);
			this->RecordStaticObjects<AnalogInfo>(mpRspTypes->mpStaticAnalog, hdr);
			this->RecordStaticObjects<CounterInfo>(mpRspTypes->mpStaticCounter, hdr);
			this->RecordStaticObjects<ControlStatusInfo>(mpRspTypes->mpStaticControlStatus, hdr);
			this->RecordStaticObjects<SetpointStatusInfo>(mpRspTypes->mpStaticSetpointStatus, hdr);
			break;
		case(MACRO_DNP_RADIX(60, 2)):
			this->SelectEvents(PC_CLASS_1, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(60, 3)):
			this->SelectEvents(PC_CLASS_2, GetEventCount(hdr.info()));
			break;
		case(MACRO_DNP_RADIX(60, 4)):
			this->SelectEvents(PC_CLASS_3, GetEventCount(hdr.info()));
			break;
		default:
			LOG_BLOCK(LEV_WARNING, "READ for obj " << hdr->GetGroup() << " var " << hdr->GetVariation() << " not supported.");
			this->mTempIIN.SetFuncNotSupported(true);
			break;
		}
	}

	return mTempIIN;
}

void ResponseContext::SelectEvents(PointClass aClass, size_t aNum)
{
	size_t remain = aNum;

	if (mBuffer.IsOverflow()) {
		mTempIIN.SetEventBufferOverflow(true);
	}

	remain -= this->SelectEvents(aClass, mpRspTypes->mpEventBinary, mBinaryEvents, remain);
	remain -= this->SelectEvents(aClass, mpRspTypes->mpEventAnalog, mAnalogEvents, remain);
	remain -= this->SelectEvents(aClass, mpRspTypes->mpEventCounter, mCounterEvents, remain);
	remain -= this->SelectVtoEvents(aClass, mpRspTypes->mpEventVto, remain);
}

size_t ResponseContext::SelectVtoEvents(PointClass aClass, const SizeByVariationObject* apObj, size_t aNum)
{
	// only select as many messages we are likley to be able to send
	// TODO: remove MAX_VTO_EVENTS once eventbuffer is fixed so selecting/adding/deselecting events keeps same size
	const size_t MAX_VTO_EVENTS = 7;

	size_t selectable = apl::Min<size_t>(aNum, MAX_VTO_EVENTS);
	size_t num = mBuffer.Select(BT_VTO, aClass, selectable);

	LOG_BLOCK(LEV_INTERPRET, "Selected: " << num << " vto events");

	if (num > 0) {
		VtoEventRequest r(apObj, aNum);
		this->mVtoEvents.push_back(r);
	}

	return num;
}

void ResponseContext::LoadResponse(APDU& arAPDU)
{
	//delay the setting of FIR/FIN until we know if it will be multifragmented or not
	arAPDU.Set(FC_RESPONSE);

	bool wrote_all = this->LoadEventData(arAPDU);

	if(wrote_all) wrote_all = LoadStaticData(arAPDU);

	FinalizeResponse(arAPDU, wrote_all);
}

bool ResponseContext::SelectUnsol(ClassMask m)
{
	if(m.class1) this->SelectEvents(PC_CLASS_1);
	if(m.class2) this->SelectEvents(PC_CLASS_2);
	if(m.class3) this->SelectEvents(PC_CLASS_3);

	return mBuffer.NumSelected() > 0;
}

bool ResponseContext::HasEvents(ClassMask m)
{
	if(m.class1 && mBuffer.HasClassData(PC_CLASS_1)) return true;
	if(m.class2 && mBuffer.HasClassData(PC_CLASS_2)) return true;
	if(m.class3 && mBuffer.HasClassData(PC_CLASS_3)) return true;

	return false;
}

void ResponseContext::LoadUnsol(APDU& arAPDU, const IINField& arIIN, ClassMask m)
{
	this->SelectUnsol(m);

	arAPDU.Set(FC_UNSOLICITED_RESPONSE, true, true, true, true);
	this->LoadEventData(arAPDU);
}

bool ResponseContext::LoadEventData(APDU& arAPDU)
{
	if (!this->LoadEvents<Binary>(arAPDU, mBinaryEvents)) return false;
	if (!this->LoadEvents<Analog>(arAPDU, mAnalogEvents)) return false;
	if (!this->LoadEvents<Counter>(arAPDU, mCounterEvents)) return false;
	if (!this->LoadVtoEvents(arAPDU)) return false;

	return true;
}

bool ResponseContext::LoadVtoEvents(APDU& arAPDU)
{
	VtoDataEventIter itr;
	mBuffer.Begin(itr);
	size_t remain = mBuffer.NumSelected(BT_VTO);

	while (this->mVtoEvents.size() > 0) {
		/* Get the number of events requested */
		VtoEventRequest& r = this->mVtoEvents.front();

		if (r.count > remain) {
			r.count = remain;
		}

		size_t written = this->IterateIndexed(r, itr, arAPDU);
		remain -= written;

		if (written > 0) {
			/* At least one event was loaded */
			this->mLoadedEventData = true;
		}

		if (written == r.count) {
			/* all events were written, finished with request */
			this->mVtoEvents.pop_front();
		} else {
			/* more event data remains in the queue */
			r.count -= written;
			return false;
		}
	}

	return true;	// the queue has been exhausted on this iteration
}

size_t ResponseContext::IterateIndexed(VtoEventRequest& arRequest, VtoDataEventIter& arIter, APDU& arAPDU)
{
	for (size_t i = 0; i < arRequest.count; ++i) {
		IndexedWriteIterator itr = arAPDU.WriteIndexed(
		                                   arRequest.pObj,
		                                   arIter->mValue.GetSize(),
		                                   arIter->mIndex
		                           );

		/*
		 * Check to see if the APDU fragment has enough room for the
		 * data segment.  If the fragment is full, return out of this
		 * function and let the fragment send.
		 */
		if (itr.IsEnd()) {
			return i;
		}

		/* Set the object index */
		itr.SetIndex(arIter->mIndex);

		/* Write the data to the APDU message */
		arRequest.pObj->Write(
		        *itr,
		        arIter->mValue.GetSize(),
		        arIter->mValue.mpData
		);

		/* Mark the data segment as being written */
		arIter->mWritten = true;

		/* Move to the next data segment in the reader buffer */
		++arIter;
	}

	return arRequest.count; // all requested events were written
}

bool ResponseContext::IsEmpty()
{
	return this->IsStaticEmpty() && this->IsEventEmpty();
}

bool ResponseContext::IsStaticEmpty()
{
	return this->mStaticWriteMap.empty();
}

bool ResponseContext::IsEventEmpty()
{
	// are there unwritten events in the selection buffer?
	return mBuffer.NumSelected() == 0;
}

void ResponseContext::FinalizeResponse(APDU& arAPDU, bool aFIN)
{
	mFIN = aFIN;
	bool confirm = !aFIN || this->mLoadedEventData;
	arAPDU.SetControl(mFIR, mFIN, confirm);
	mFIR = false;
	this->mLoadedEventData = false;
}

bool ResponseContext::LoadStaticData(APDU& arAPDU)
{
	while(!this->mStaticWriteMap.empty()) {

		WriteMap::iterator i = this->mStaticWriteMap.begin();

		if(i->second(arAPDU)) {
			this->mStaticWriteMap.erase(i);
		} else return false;
	}

	return true;
}

}
}

/* vim: set ts=4 sw=4: */