<commit_before>#ifndef ARABICA_XSLT_STYLESHEET_HPP
#define ARABICA_XSLT_STYLESHEET_HPP

#include <vector>
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
#include <XPath/XPath.hpp>

#include "xslt_execution_context.hpp"
#include "xslt_template.hpp"
#include "xslt_top_level_param.hpp"

namespace Arabica
{
namespace XSLT
{

class Stylesheet
{
  typedef Arabica::XPath::BoolValue<std::string, Arabica::default_string_adaptor<std::string> > BoolValue;
  typedef Arabica::XPath::NumericValue<std::string, Arabica::default_string_adaptor<std::string> > NumericValue;
  typedef Arabica::XPath::StringValue<std::string, Arabica::default_string_adaptor<std::string> > StringValue;
  typedef Arabica::XPath::XPathValuePtr<std::string> ValuePtr;

public:
  Stylesheet() :
      output_(new StreamSink(std::cout)),
      error_output_(&std::cerr)
  {
    push_import_precedence();
  } // Stylesheet

  ~Stylesheet()
  {
  } // ~Stylesheet

  void set_parameter(const std::string& name, bool value)
  {
    set_parameter(name, ValuePtr(new BoolValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, double value)
  {
    set_parameter(name, ValuePtr(new NumericValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, const char* value)
  {
    set_parameter(name, ValuePtr(new StringValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, const std::string& value)
  {
    set_parameter(name, ValuePtr(new StringValue(value)));
  } // set_parameter

  void set_output(Sink& sink)
  {
    output_.reset(sink);
  } // set_output

  void set_error_output(std::ostream& os)
  {
    error_output_ = &os;
  } // set_error_output

  void execute(DOM::Node<std::string>& initialNode) const
  {
    Arabica::XPath::NodeSet<std::string> ns;
    ns.push_back(initialNode);

    ExecutionContext context(*this, output_.get(), *error_output_);

    // set up variables and so forth
    for(boost::ptr_vector<TopLevelParam>::const_iterator pi = params_.begin(), pe = params_.end(); pi != pe; ++pi)
      pi->declare(context);
    for(boost::ptr_vector<Item>::const_iterator ci = items_.begin(), ce = items_.end(); ci != ce; ++ci)
      ci->execute(initialNode, context);
    context.freezeTopLevel();

    // go!
    output_.get().asOutput().start_document(output_settings_);
    applyTemplates(ns, context, std::pair<std::string, std::string>("", ""));
    output_.get().asOutput().end_document();
  } // execute

  ////////////////////////////////////////
  void add_template(Template* templat)
  {
    typedef std::vector<Arabica::XPath::MatchExpr<std::string> > MatchExprList;
    typedef MatchExprList::const_iterator MatchIterator;

    all_templates_.push_back(templat);

    for(MatchIterator e = templat->compiled_matches().begin(), ee = templat->compiled_matches().end(); e != ee; ++e)
      templates_.back()[templat->mode()].push_back(MatchTemplate(*e, templat));

    if(!templat->has_name())
      return;

    if(named_templates_.find(templat->name()) != named_templates_.end())
    {
      std::cerr << "Template named '";
      if(!templat->name().first.empty())
        std::cerr << "{" << templat->name().first << "}";
      std::cerr << templat->name().second << "' already defined" << std::endl;
      return;
    }

    named_templates_[templat->name()] = templat;
  } // add_template

  void push_import_precedence()
  {
    templates_.push_back(ModeTemplates());
  } // push_import_precedence

  void add_item(Item* item)
  {
    items_.push_back(item);
  } // add_item

  void output_settings(const Output::Settings& settings)
  {
    output_settings_ = settings;
  } // output_settings

  void prepare()
  {
    for(TemplateStack::iterator ts = templates_.begin(), tse = templates_.end(); ts != tse; ++ts)
      for(ModeTemplates::iterator ms = ts->begin(), mse = ts->end(); ms != mse; ++ms)
      {
        MatchTemplates& matches = ms->second;
        std::reverse(matches.begin(), matches.end());
        std::stable_sort(matches.begin(), matches.end());
      } // for ...
  } // prepare

  ////////////////////////////////////////
  void applyTemplates(const Arabica::XPath::NodeSet<std::string>& nodes, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    // entirely simple so far
    StackFrame frame(context);
    LastFrame last(context, nodes.size());
    int p = 1;
    for(Arabica::XPath::NodeSet<std::string>::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n)
    {
      context.setPosition(*n, p++);
      doApplyTemplates(*n, context, mode, 0);
    }
  } // applyTemplates

  void applyTemplates(const DOM::NodeList<std::string>& nodes, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    // entirely simple so far
    StackFrame frame(context);
    LastFrame last(context, (size_t)nodes.getLength());
    for(int i = 0, ie = nodes.getLength(); i != ie; ++i)
    {
      context.setPosition(nodes.item(i), i+1);
      doApplyTemplates(nodes.item(i), context, mode, 0);
    }
  } // applyTemplates

  void applyTemplates(const DOM::Node<std::string>& node, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    StackFrame frame(context);
    LastFrame last(context, -1);
    context.setPosition(node, 1);
    doApplyTemplates(node, context, mode, 0);
  } // applyTemplates

  void callTemplate(const std::pair<std::string, std::string>& name, const DOM::Node<std::string>& node, ExecutionContext& context) const
  {
    StackFrame frame(context);

    NamedTemplates::const_iterator t = named_templates_.find(name);
    if(t == named_templates_.end())
    {
      std::cerr << "No template named '";
      if(!name.first.empty())
        std::cerr << "{" << name.first << "}";
      std::cerr << name.second << "'.  I should be a compile time-error!" << std::endl;
      return;
    }

    t->second->execute(node, context);
  } // callTemplate

  void applyImports(const DOM::Node<std::string>& node, ExecutionContext& context) const
  {
    StackFrame frame(context);

    doApplyTemplates(node, context, current_mode_, current_generation_+1);
  } // applyImports

private:
  void doApplyTemplates(const DOM::Node<std::string>& node,
                        ExecutionContext& context,
                        const std::pair<std::string, std::string>& mode,
                        int generation) const
  {
    current_mode_ = mode;
    current_generation_ = generation;

    for(TemplateStack::const_iterator ts = templates_.begin()+generation, tse = templates_.end(); ts != tse; ++ts)
    {
      ModeTemplates::const_iterator mt = ts->find(mode);
      if(mt != ts->end())
      {
        const MatchTemplates& templates = mt->second;
	      for(MatchTemplates::const_iterator t = templates.begin(), te = templates.end(); t != te; ++t)
	        if(t->match().evaluate(node, context.xpathContext()))
	        {
	          t->action()->execute(node, context);
	          return;
	        } // if ...
      } // if ...
      ++current_generation_;
    } // for ...
    defaultAction(node, context, mode);
  } // doApplyTemplates

  void defaultAction(const DOM::Node<std::string>& node,
                     ExecutionContext& context,
                     const std::pair<std::string, std::string>& mode) const
  {
    switch(node.getNodeType())
    {
      case DOM::Node<std::string>::DOCUMENT_NODE:
      case DOM::Node<std::string>::DOCUMENT_FRAGMENT_NODE:
      case DOM::Node<std::string>::ELEMENT_NODE:
        applyTemplates(node.getChildNodes(), context, mode);
        break;
      case DOM::Node<std::string>::ATTRIBUTE_NODE:
      case DOM::Node<std::string>::TEXT_NODE:
      case DOM::Node<std::string>::CDATA_SECTION_NODE:
        {
          const std::string& ch = node.getNodeValue();
          for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i)
            if(!Arabica::XML::is_space(*i))
            {
              context.sink().characters(ch);
              return;
            } // if ...
        }
        break;
      default:
        ;// nothing!
    } // switch
  } // defaultAction

  void set_parameter(const std::string& name, ValuePtr value)
  {
    params_.push_back(new TopLevelParam("", name, value));
  } // set_parameter

  void set_parameter(const std::string& namespace_uri, const std::string& name, ValuePtr value)
  {
    params_.push_back(new TopLevelParam(namespace_uri, name, value));
  } // set_parameter

private:
  class MatchTemplate
  {
  public:
    MatchTemplate(const Arabica::XPath::MatchExpr<std::string>& matchExpr, Template* templat) :
      match_(matchExpr),
      template_(templat)
    {
    } // MatchTemplate
    MatchTemplate(const MatchTemplate& rhs) :
      match_(rhs.match_),
      template_(rhs.template_)
    {
    } // MatchTemplate

    const Arabica::XPath::MatchExpr<std::string>& match() const { return match_; }
    Template* action() const { return template_; }

    bool operator<(const MatchTemplate& rhs) const
    {
      // high priority first!
      return match_.priority() > rhs.match_.priority();
    } // operator<
  private:
    Arabica::XPath::MatchExpr<std::string> match_;
    Template* template_;
  }; // struct MatchTemplate

  typedef boost::ptr_vector<Template> TemplateList;
  typedef std::vector<MatchTemplate> MatchTemplates;
  typedef std::map<std::pair<std::string, std::string>, MatchTemplates> ModeTemplates;
  typedef std::vector<ModeTemplates> TemplateStack;
  typedef std::map<std::pair<std::string, std::string>, Template*> NamedTemplates;

  TemplateList all_templates_;
  NamedTemplates named_templates_;
  TemplateStack templates_;
  boost::ptr_vector<Item> items_;
  boost::ptr_vector<TopLevelParam> params_;

  mutable std::pair<std::string, std::string> current_mode_;
  mutable int current_generation_;

  Output::Settings output_settings_;
  SinkHolder output_;
  mutable std::ostream* error_output_;
}; // class Stylesheet

} // namespace XSLT
} // namespace Arabica

#endif // ARABICA_XSLT_STYLESHEET_HPP

<commit_msg>xsl:call-template throws if it can't find a matching template<commit_after>#ifndef ARABICA_XSLT_STYLESHEET_HPP
#define ARABICA_XSLT_STYLESHEET_HPP

#include <vector>
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
#include <XPath/XPath.hpp>

#include "xslt_execution_context.hpp"
#include "xslt_template.hpp"
#include "xslt_top_level_param.hpp"

namespace Arabica
{
namespace XSLT
{

class Stylesheet
{
  typedef Arabica::XPath::BoolValue<std::string, Arabica::default_string_adaptor<std::string> > BoolValue;
  typedef Arabica::XPath::NumericValue<std::string, Arabica::default_string_adaptor<std::string> > NumericValue;
  typedef Arabica::XPath::StringValue<std::string, Arabica::default_string_adaptor<std::string> > StringValue;
  typedef Arabica::XPath::XPathValuePtr<std::string> ValuePtr;

public:
  Stylesheet() :
      output_(new StreamSink(std::cout)),
      error_output_(&std::cerr)
  {
    push_import_precedence();
  } // Stylesheet

  ~Stylesheet()
  {
  } // ~Stylesheet

  void set_parameter(const std::string& name, bool value)
  {
    set_parameter(name, ValuePtr(new BoolValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, double value)
  {
    set_parameter(name, ValuePtr(new NumericValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, const char* value)
  {
    set_parameter(name, ValuePtr(new StringValue(value)));
  } // set_parameter
  void set_parameter(const std::string& name, const std::string& value)
  {
    set_parameter(name, ValuePtr(new StringValue(value)));
  } // set_parameter

  void set_output(Sink& sink)
  {
    output_.reset(sink);
  } // set_output

  void set_error_output(std::ostream& os)
  {
    error_output_ = &os;
  } // set_error_output

  void execute(DOM::Node<std::string>& initialNode) const
  {
    Arabica::XPath::NodeSet<std::string> ns;
    ns.push_back(initialNode);

    ExecutionContext context(*this, output_.get(), *error_output_);

    // set up variables and so forth
    for(boost::ptr_vector<TopLevelParam>::const_iterator pi = params_.begin(), pe = params_.end(); pi != pe; ++pi)
      pi->declare(context);
    for(boost::ptr_vector<Item>::const_iterator ci = items_.begin(), ce = items_.end(); ci != ce; ++ci)
      ci->execute(initialNode, context);
    context.freezeTopLevel();

    // go!
    output_.get().asOutput().start_document(output_settings_);
    applyTemplates(ns, context, std::pair<std::string, std::string>("", ""));
    output_.get().asOutput().end_document();
  } // execute

  ////////////////////////////////////////
  void add_template(Template* templat)
  {
    typedef std::vector<Arabica::XPath::MatchExpr<std::string> > MatchExprList;
    typedef MatchExprList::const_iterator MatchIterator;

    all_templates_.push_back(templat);

    for(MatchIterator e = templat->compiled_matches().begin(), ee = templat->compiled_matches().end(); e != ee; ++e)
      templates_.back()[templat->mode()].push_back(MatchTemplate(*e, templat));

    if(!templat->has_name())
      return;

    if(named_templates_.find(templat->name()) != named_templates_.end())
    {
      std::cerr << "Template named '";
      if(!templat->name().first.empty())
        std::cerr << "{" << templat->name().first << "}";
      std::cerr << templat->name().second << "' already defined" << std::endl;
      return;
    }

    named_templates_[templat->name()] = templat;
  } // add_template

  void push_import_precedence()
  {
    templates_.push_back(ModeTemplates());
  } // push_import_precedence

  void add_item(Item* item)
  {
    items_.push_back(item);
  } // add_item

  void output_settings(const Output::Settings& settings)
  {
    output_settings_ = settings;
  } // output_settings

  void prepare()
  {
    for(TemplateStack::iterator ts = templates_.begin(), tse = templates_.end(); ts != tse; ++ts)
      for(ModeTemplates::iterator ms = ts->begin(), mse = ts->end(); ms != mse; ++ms)
      {
        MatchTemplates& matches = ms->second;
        std::reverse(matches.begin(), matches.end());
        std::stable_sort(matches.begin(), matches.end());
      } // for ...
  } // prepare

  ////////////////////////////////////////
  void applyTemplates(const Arabica::XPath::NodeSet<std::string>& nodes, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    // entirely simple so far
    StackFrame frame(context);
    LastFrame last(context, nodes.size());
    int p = 1;
    for(Arabica::XPath::NodeSet<std::string>::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n)
    {
      context.setPosition(*n, p++);
      doApplyTemplates(*n, context, mode, 0);
    }
  } // applyTemplates

  void applyTemplates(const DOM::NodeList<std::string>& nodes, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    // entirely simple so far
    StackFrame frame(context);
    LastFrame last(context, (size_t)nodes.getLength());
    for(int i = 0, ie = nodes.getLength(); i != ie; ++i)
    {
      context.setPosition(nodes.item(i), i+1);
      doApplyTemplates(nodes.item(i), context, mode, 0);
    }
  } // applyTemplates

  void applyTemplates(const DOM::Node<std::string>& node, ExecutionContext& context, const std::pair<std::string, std::string>& mode) const
  {
    StackFrame frame(context);
    LastFrame last(context, -1);
    context.setPosition(node, 1);
    doApplyTemplates(node, context, mode, 0);
  } // applyTemplates

  void callTemplate(const std::pair<std::string, std::string>& name, const DOM::Node<std::string>& node, ExecutionContext& context) const
  {
    StackFrame frame(context);

    NamedTemplates::const_iterator t = named_templates_.find(name);
    if(t == named_templates_.end())
    {
      std::cerr << "No template named '";
      if(!name.first.empty())
        std::cerr << "{" << name.first << "}";
      std::cerr << name.second << "'.  I should be a compile-time error!" << std::endl;
      throw SAX::SAXException("No template named {" + name.first + "}" + name.second + ".  I should be a compile-time error.  Sorry!");
      return;
    }

    t->second->execute(node, context);
  } // callTemplate

  void applyImports(const DOM::Node<std::string>& node, ExecutionContext& context) const
  {
    StackFrame frame(context);

    doApplyTemplates(node, context, current_mode_, current_generation_+1);
  } // applyImports

private:
  void doApplyTemplates(const DOM::Node<std::string>& node,
                        ExecutionContext& context,
                        const std::pair<std::string, std::string>& mode,
                        int generation) const
  {
    current_mode_ = mode;
    current_generation_ = generation;

    for(TemplateStack::const_iterator ts = templates_.begin()+generation, tse = templates_.end(); ts != tse; ++ts)
    {
      ModeTemplates::const_iterator mt = ts->find(mode);
      if(mt != ts->end())
      {
        const MatchTemplates& templates = mt->second;
	      for(MatchTemplates::const_iterator t = templates.begin(), te = templates.end(); t != te; ++t)
	        if(t->match().evaluate(node, context.xpathContext()))
	        {
	          t->action()->execute(node, context);
	          return;
	        } // if ...
      } // if ...
      ++current_generation_;
    } // for ...
    defaultAction(node, context, mode);
  } // doApplyTemplates

  void defaultAction(const DOM::Node<std::string>& node,
                     ExecutionContext& context,
                     const std::pair<std::string, std::string>& mode) const
  {
    switch(node.getNodeType())
    {
      case DOM::Node<std::string>::DOCUMENT_NODE:
      case DOM::Node<std::string>::DOCUMENT_FRAGMENT_NODE:
      case DOM::Node<std::string>::ELEMENT_NODE:
        applyTemplates(node.getChildNodes(), context, mode);
        break;
      case DOM::Node<std::string>::ATTRIBUTE_NODE:
      case DOM::Node<std::string>::TEXT_NODE:
      case DOM::Node<std::string>::CDATA_SECTION_NODE:
        {
          const std::string& ch = node.getNodeValue();
          for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i)
            if(!Arabica::XML::is_space(*i))
            {
              context.sink().characters(ch);
              return;
            } // if ...
        }
        break;
      default:
        ;// nothing!
    } // switch
  } // defaultAction

  void set_parameter(const std::string& name, ValuePtr value)
  {
    params_.push_back(new TopLevelParam("", name, value));
  } // set_parameter

  void set_parameter(const std::string& namespace_uri, const std::string& name, ValuePtr value)
  {
    params_.push_back(new TopLevelParam(namespace_uri, name, value));
  } // set_parameter

private:
  class MatchTemplate
  {
  public:
    MatchTemplate(const Arabica::XPath::MatchExpr<std::string>& matchExpr, Template* templat) :
      match_(matchExpr),
      template_(templat)
    {
    } // MatchTemplate
    MatchTemplate(const MatchTemplate& rhs) :
      match_(rhs.match_),
      template_(rhs.template_)
    {
    } // MatchTemplate

    const Arabica::XPath::MatchExpr<std::string>& match() const { return match_; }
    Template* action() const { return template_; }

    bool operator<(const MatchTemplate& rhs) const
    {
      // high priority first!
      return match_.priority() > rhs.match_.priority();
    } // operator<
  private:
    Arabica::XPath::MatchExpr<std::string> match_;
    Template* template_;
  }; // struct MatchTemplate

  typedef boost::ptr_vector<Template> TemplateList;
  typedef std::vector<MatchTemplate> MatchTemplates;
  typedef std::map<std::pair<std::string, std::string>, MatchTemplates> ModeTemplates;
  typedef std::vector<ModeTemplates> TemplateStack;
  typedef std::map<std::pair<std::string, std::string>, Template*> NamedTemplates;

  TemplateList all_templates_;
  NamedTemplates named_templates_;
  TemplateStack templates_;
  boost::ptr_vector<Item> items_;
  boost::ptr_vector<TopLevelParam> params_;

  mutable std::pair<std::string, std::string> current_mode_;
  mutable int current_generation_;

  Output::Settings output_settings_;
  SinkHolder output_;
  mutable std::ostream* error_output_;
}; // class Stylesheet

} // namespace XSLT
} // namespace Arabica

#endif // ARABICA_XSLT_STYLESHEET_HPP

<|endoftext|>


<commit_before>#ifndef ALEPH_GEOMETRY_CECH_COMPLEX_HH__
#define ALEPH_GEOMETRY_CECH_COMPLEX_HH__

#include <aleph/math/Combinations.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/external/Miniball.hpp>

#include <numeric>
#include <vector>

#include <cmath>

namespace aleph
{

namespace geometry
{

template <class Container> auto buildCechComplex( const Container& container, typename Container::ElementType r ) -> topology::SimplicialComplex< topology::Simplex<typename Container::ElementType, typename Container::IndexType> >
{
  using ElementType       = typename Container::ElementType;
  using IndexType         = typename Container::IndexType;
  using Simplex           = topology::Simplex<ElementType, IndexType>;
  using SimplicialComplex = topology::SimplicialComplex<Simplex>;

  // Set up vertices for a combinatorial search over *all* potential
  // simplices.
  std::vector<IndexType> vertices( container.size() );
  std::iota( vertices.begin(), vertices.end(),
             IndexType(0) );

  std::vector<Simplex> simplices;

  // Add 0-skeleton ----------------------------------------------------

  for( auto&& vertex : vertices )
    simplices.push_back( Simplex( vertex ) );

  // Add 1-skeleton ----------------------------------------------------
  //
  // We could obtain this faster by using nearest-neighbour queries, but
  // let's remain in the same domain and calculate the complex similarly
  // in *every* dimension.

  auto D               = container.dimension();
  auto n               = container.size();
  auto R               = r * r;
  using DifferenceType = typename decltype(vertices)::difference_type;
  using Iterator       = typename decltype(vertices)::const_iterator;

  for( unsigned d = 2; d <= n; d++ )
  {
    auto previous_n = simplices.size();

    math::for_each_combination( vertices.begin(), vertices.begin() + DifferenceType(d), vertices.end(),
      [&container, &simplices, &D, &R] ( Iterator first, Iterator last )
      {
        std::vector< std::vector<ElementType> > points;
        for( Iterator it = first; it != last; ++it )
          points.push_back( container[ *it ] );

        using PointIterator      = typename decltype(points)::const_iterator;
        using CoordinateIterator = typename std::vector<ElementType>::const_iterator;
        using Miniball           = Miniball::Miniball< Miniball::CoordAccessor<PointIterator, CoordinateIterator> >;

        Miniball mb( static_cast<int>(D), points.begin(), points.end() );
        if( mb.squared_radius() <= R )
        {
          Simplex s( first, last, ElementType( std::sqrt( mb.squared_radius() ) ) );
          simplices.push_back( s );
        }

        return false;
      }
    );

    // Check whether we can stop adding simplices. If no additional
    // simplices have been created during the last iteration, there
    // is no need to continue the iteration.
    auto current_n = simplices.size();
    if( previous_n == current_n )
      break;
  }

  SimplicialComplex K( simplices.begin(), simplices.end() );
  K.sort( topology::filtrations::Data<Simplex>() );

  return K;
}

} // namespace geometry

} // namespace aleph

#endif
<commit_msg>Fixed weight assignment<commit_after>#ifndef ALEPH_GEOMETRY_CECH_COMPLEX_HH__
#define ALEPH_GEOMETRY_CECH_COMPLEX_HH__

#include <aleph/math/Combinations.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/external/Miniball.hpp>

#include <numeric>
#include <vector>

#include <cmath>

namespace aleph
{

namespace geometry
{

template <class Container> auto buildCechComplex( const Container& container, typename Container::ElementType r ) -> topology::SimplicialComplex< topology::Simplex<typename Container::ElementType, typename Container::IndexType> >
{
  using ElementType       = typename Container::ElementType;
  using IndexType         = typename Container::IndexType;
  using Simplex           = topology::Simplex<ElementType, IndexType>;
  using SimplicialComplex = topology::SimplicialComplex<Simplex>;

  // Set up vertices for a combinatorial search over *all* potential
  // simplices.
  std::vector<IndexType> vertices( container.size() );
  std::iota( vertices.begin(), vertices.end(),
             IndexType(0) );

  std::vector<Simplex> simplices;

  // Add 0-skeleton ----------------------------------------------------

  for( auto&& vertex : vertices )
    simplices.push_back( Simplex( vertex ) );

  // Add 1-skeleton ----------------------------------------------------
  //
  // We could obtain this faster by using nearest-neighbour queries, but
  // let's remain in the same domain and calculate the complex similarly
  // in *every* dimension.

  auto D               = container.dimension();
  auto n               = container.size();
  auto R               = r * r;
  using DifferenceType = typename decltype(vertices)::difference_type;
  using Iterator       = typename decltype(vertices)::const_iterator;

  for( unsigned d = 2; d <= n; d++ )
  {
    auto previous_n = simplices.size();

    math::for_each_combination( vertices.begin(), vertices.begin() + DifferenceType(d), vertices.end(),
      [&container, &simplices, &D, &R] ( Iterator first, Iterator last )
      {
        std::vector< std::vector<ElementType> > points;
        for( Iterator it = first; it != last; ++it )
          points.push_back( container[ *it ] );

        using PointIterator      = typename decltype(points)::const_iterator;
        using CoordinateIterator = typename std::vector<ElementType>::const_iterator;
        using Miniball           = Miniball::Miniball< Miniball::CoordAccessor<PointIterator, CoordinateIterator> >;

        Miniball mb( static_cast<int>(D), points.begin(), points.end() );
        if( mb.squared_radius() <= R )
        {
          Simplex s( first, last, ElementType( 2 * std::sqrt( mb.squared_radius() ) ) );
          simplices.push_back( s );
        }

        return false;
      }
    );

    // Check whether we can stop adding simplices. If no additional
    // simplices have been created during the last iteration, there
    // is no need to continue the iteration.
    auto current_n = simplices.size();
    if( previous_n == current_n )
      break;
  }

  SimplicialComplex K( simplices.begin(), simplices.end() );
  K.sort( topology::filtrations::Data<Simplex>() );

  return K;
}

} // namespace geometry

} // namespace aleph

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "etl/expr/base_temporary_expr.hpp"

namespace etl {

/*!
 * \brief A transposition expression.
 * \tparam A The transposed type
 */
template <typename A, typename Impl>
struct dyn_pool_3d_expr : base_temporary_expr_un<dyn_pool_3d_expr<A, Impl>, A> {
    using value_type = value_t<A>;                           ///< The type of value of the expression
    using this_type  = dyn_pool_3d_expr<A, Impl>;            ///< The type of this expression
    using base_type  = base_temporary_expr_un<this_type, A>; ///< The base type
    using sub_traits = decay_traits<A>;                      ///< The traits of the sub type

    static constexpr auto storage_order = sub_traits::storage_order; ///< The sub storage order

    const size_t c1; ///< The pooling ratio for the first dimension
    const size_t c2; ///< The pooling ratio for the second dimension
    const size_t c2; ///< The pooling ratio for the third dimension
    const size_t s1; ///< The stride for the first dimension
    const size_t s2; ///< The stride for the second dimension
    const size_t s3; ///< The stride for the third dimension
    const size_t p1; ///< The padding for the first dimension
    const size_t p2; ///< The padding for the second dimension
    const size_t p3; ///< The padding for the third dimension

    /*!
     * \brief Construct a new expression
     * \param a The sub expression
     */
    explicit dyn_pool_3d_expr(A a, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) : base_type(a), c1(c1), c2(c2), c3(c3), s1(s1), s2(s2), s3(s3), p1(p1), p2(p2), p3(p3) {
        //Nothing else to init
    }

    // Assignment functions

    /*!
     * \brief Assign to a matrix of the same storage order
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_to(L&& lhs)  const {
        static_assert(all_etl_expr<A, L>::value, "pool_2d only supported for ETL expressions");
        static_assert(etl::dimensions<A>() == etl::dimensions<L>(), "pool_2d must be applied on matrices of same dimensionality");

        auto& a = this->a();

        standard_evaluator::pre_assign_rhs(a);
        standard_evaluator::pre_assign_lhs(lhs);

        Impl::template apply<>(
            make_temporary(a),
            std::forward<L>(lhs),
            c1, c2, c3, s1, s2, s3, p1, p2, p3);
    }

    /*!
     * \brief Add to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_add_to(L&& lhs)  const {
        std_add_evaluate(*this, lhs);
    }

    /*!
     * \brief Sub from the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_sub_to(L&& lhs)  const {
        std_sub_evaluate(*this, lhs);
    }

    /*!
     * \brief Multiply the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mul_to(L&& lhs)  const {
        std_mul_evaluate(*this, lhs);
    }

    /*!
     * \brief Divide the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_div_to(L&& lhs)  const {
        std_div_evaluate(*this, lhs);
    }

    /*!
     * \brief Modulo the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mod_to(L&& lhs)  const {
        std_mod_evaluate(*this, lhs);
    }
};

/*!
 * \brief Traits for a transpose expression
 * \tparam A The transposed sub type
 */
template <typename A, typename Impl>
struct etl_traits<etl::dyn_pool_3d_expr<A, Impl>> {
    using expr_t     = etl::dyn_pool_3d_expr<A, Impl>; ///< The expression type
    using sub_expr_t = std::decay_t<A>;                ///< The sub expression type
    using sub_traits = etl_traits<sub_expr_t>;         ///< The sub traits
    using value_type = value_t<A>;                     ///< The value type of the expression

    static constexpr size_t D = sub_traits::dimensions(); ///< The number of dimensions of this expressions

    static constexpr bool is_etl                  = true;                      ///< Indicates if the type is an ETL expression
    static constexpr bool is_transformer          = false;                     ///< Indicates if the type is a transformer
    static constexpr bool is_view                 = false;                     ///< Indicates if the type is a view
    static constexpr bool is_magic_view           = false;                     ///< Indicates if the type is a magic view
    static constexpr bool is_fast                 = false;                     ///< Indicates if the expression is fast
    static constexpr bool is_linear               = true;                      ///< Indicates if the expression is linear
    static constexpr bool is_thread_safe          = true;                      ///< Indicates if the expression is thread safe
    static constexpr bool is_value                = false;                     ///< Indicates if the expression is of value type
    static constexpr bool is_direct               = true;                      ///< Indicates if the expression has direct memory access
    static constexpr bool is_generator            = false;                     ///< Indicates if the expression is a generator
    static constexpr bool is_padded               = false;                     ///< Indicates if the expression is padded
    static constexpr bool is_aligned              = true;                      ///< Indicates if the expression is padded
    static constexpr bool is_gpu                  = false;                     ///< Indicates if the expression can be done on GPU
    static constexpr bool needs_evaluator_visitor = true;                      ///< Indicates if the expression needs a evaluator visitor
    static constexpr order storage_order          = sub_traits::storage_order; ///< The expression's storage order

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    using vectorizable = std::true_type;

    /*!
     * \brief Returns the dth dimension of the expression
     * \param e The sub expression
     * \param d The dimension to get
     * \return the dth dimension of the expression
     */
    static size_t dim(const expr_t& e, size_t d) {
        if (d == D - 3) {
            return (etl::dim(e._a, d) - e.c1 + 2 * e.p1) / e.s1 + 1;
        } else if (d == D - 2) {
            return (etl::dim(e._a, d) - e.c2 + 2 * e.p2) / e.s2 + 1;
        } else if (d == D - 1){
            return (etl::dim(e._a, d) - e.c3 + 2 * e.p3) / e.s3 + 1;
        } else {
            return etl::dim(e._a, d);
        }
    }
/*!
     * \brief Returns the size of the expression
     * \param e The sub expression
     * \return the size of the expression
     */
    static size_t size(const expr_t& e) {
        size_t acc = 1;
        for (size_t i = 0; i < D; ++i) {
            acc *= dim(e, i);
        }
        return acc;
    }

    /*!
     * \brief Returns the number of dimensions of the expression
     * \return the number of dimensions of the expression
     */
    static constexpr size_t dimensions() {
        return D;
    }
};

} //end of namespace etl
<commit_msg>Fix field<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "etl/expr/base_temporary_expr.hpp"

namespace etl {

/*!
 * \brief A transposition expression.
 * \tparam A The transposed type
 */
template <typename A, typename Impl>
struct dyn_pool_3d_expr : base_temporary_expr_un<dyn_pool_3d_expr<A, Impl>, A> {
    using value_type = value_t<A>;                           ///< The type of value of the expression
    using this_type  = dyn_pool_3d_expr<A, Impl>;            ///< The type of this expression
    using base_type  = base_temporary_expr_un<this_type, A>; ///< The base type
    using sub_traits = decay_traits<A>;                      ///< The traits of the sub type

    static constexpr auto storage_order = sub_traits::storage_order; ///< The sub storage order

    const size_t c1; ///< The pooling ratio for the first dimension
    const size_t c2; ///< The pooling ratio for the second dimension
    const size_t c3; ///< The pooling ratio for the third dimension
    const size_t s1; ///< The stride for the first dimension
    const size_t s2; ///< The stride for the second dimension
    const size_t s3; ///< The stride for the third dimension
    const size_t p1; ///< The padding for the first dimension
    const size_t p2; ///< The padding for the second dimension
    const size_t p3; ///< The padding for the third dimension

    /*!
     * \brief Construct a new expression
     * \param a The sub expression
     */
    explicit dyn_pool_3d_expr(A a, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) : base_type(a), c1(c1), c2(c2), c3(c3), s1(s1), s2(s2), s3(s3), p1(p1), p2(p2), p3(p3) {
        //Nothing else to init
    }

    // Assignment functions

    /*!
     * \brief Assign to a matrix of the same storage order
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_to(L&& lhs)  const {
        static_assert(all_etl_expr<A, L>::value, "pool_2d only supported for ETL expressions");
        static_assert(etl::dimensions<A>() == etl::dimensions<L>(), "pool_2d must be applied on matrices of same dimensionality");

        auto& a = this->a();

        standard_evaluator::pre_assign_rhs(a);
        standard_evaluator::pre_assign_lhs(lhs);

        Impl::template apply<>(
            make_temporary(a),
            std::forward<L>(lhs),
            c1, c2, c3, s1, s2, s3, p1, p2, p3);
    }

    /*!
     * \brief Add to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_add_to(L&& lhs)  const {
        std_add_evaluate(*this, lhs);
    }

    /*!
     * \brief Sub from the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_sub_to(L&& lhs)  const {
        std_sub_evaluate(*this, lhs);
    }

    /*!
     * \brief Multiply the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mul_to(L&& lhs)  const {
        std_mul_evaluate(*this, lhs);
    }

    /*!
     * \brief Divide the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_div_to(L&& lhs)  const {
        std_div_evaluate(*this, lhs);
    }

    /*!
     * \brief Modulo the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mod_to(L&& lhs)  const {
        std_mod_evaluate(*this, lhs);
    }
};

/*!
 * \brief Traits for a transpose expression
 * \tparam A The transposed sub type
 */
template <typename A, typename Impl>
struct etl_traits<etl::dyn_pool_3d_expr<A, Impl>> {
    using expr_t     = etl::dyn_pool_3d_expr<A, Impl>; ///< The expression type
    using sub_expr_t = std::decay_t<A>;                ///< The sub expression type
    using sub_traits = etl_traits<sub_expr_t>;         ///< The sub traits
    using value_type = value_t<A>;                     ///< The value type of the expression

    static constexpr size_t D = sub_traits::dimensions(); ///< The number of dimensions of this expressions

    static constexpr bool is_etl                  = true;                      ///< Indicates if the type is an ETL expression
    static constexpr bool is_transformer          = false;                     ///< Indicates if the type is a transformer
    static constexpr bool is_view                 = false;                     ///< Indicates if the type is a view
    static constexpr bool is_magic_view           = false;                     ///< Indicates if the type is a magic view
    static constexpr bool is_fast                 = false;                     ///< Indicates if the expression is fast
    static constexpr bool is_linear               = true;                      ///< Indicates if the expression is linear
    static constexpr bool is_thread_safe          = true;                      ///< Indicates if the expression is thread safe
    static constexpr bool is_value                = false;                     ///< Indicates if the expression is of value type
    static constexpr bool is_direct               = true;                      ///< Indicates if the expression has direct memory access
    static constexpr bool is_generator            = false;                     ///< Indicates if the expression is a generator
    static constexpr bool is_padded               = false;                     ///< Indicates if the expression is padded
    static constexpr bool is_aligned              = true;                      ///< Indicates if the expression is padded
    static constexpr bool is_gpu                  = false;                     ///< Indicates if the expression can be done on GPU
    static constexpr bool needs_evaluator_visitor = true;                      ///< Indicates if the expression needs a evaluator visitor
    static constexpr order storage_order          = sub_traits::storage_order; ///< The expression's storage order

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    using vectorizable = std::true_type;

    /*!
     * \brief Returns the dth dimension of the expression
     * \param e The sub expression
     * \param d The dimension to get
     * \return the dth dimension of the expression
     */
    static size_t dim(const expr_t& e, size_t d) {
        if (d == D - 3) {
            return (etl::dim(e._a, d) - e.c1 + 2 * e.p1) / e.s1 + 1;
        } else if (d == D - 2) {
            return (etl::dim(e._a, d) - e.c2 + 2 * e.p2) / e.s2 + 1;
        } else if (d == D - 1){
            return (etl::dim(e._a, d) - e.c3 + 2 * e.p3) / e.s3 + 1;
        } else {
            return etl::dim(e._a, d);
        }
    }
/*!
     * \brief Returns the size of the expression
     * \param e The sub expression
     * \return the size of the expression
     */
    static size_t size(const expr_t& e) {
        size_t acc = 1;
        for (size_t i = 0; i < D; ++i) {
            acc *= dim(e, i);
        }
        return acc;
    }

    /*!
     * \brief Returns the number of dimensions of the expression
     * \return the number of dimensions of the expression
     */
    static constexpr size_t dimensions() {
        return D;
    }
};

} //end of namespace etl
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 author 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 OWNER 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.

*/

#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD

#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include "libtorrent/allocator.hpp"
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_array.hpp>
#include <list>
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
#include <boost/pool/pool.hpp>
#endif
#include "libtorrent/session_settings.hpp"

namespace libtorrent
{
	struct cached_piece_info
	{
		int piece;
		std::vector<bool> blocks;
		ptime last_use;
		enum kind_t { read_cache = 0, write_cache = 1 };
		kind_t kind;
	};

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
			, check_fastresume
			, check_files
			, save_resume_data
			, rename_file
			, abort_thread
			, clear_read_cache
			, abort_torrent
			, update_settings
			, read_and_hash
		};

		action_t action;

		char* buffer;
		int buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage and rename_file. On errors, this is set
		// to the error message
		std::string str;

		// on error, this is set to the path of the
		// file the disk operation failed on
		std::string error_file;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		boost::shared_ptr<entry> resume_data;

		// the error code from the file operation
		error_code error;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	struct cache_status
	{
		cache_status()
			: blocks_written(0)
			, writes(0)
			, blocks_read(0)
			, blocks_read_hit(0)
			, reads(0)
			, cache_size(0)
			, read_cache_size(0)
			, total_used_buffers(0)
		{}

		// the number of 16kB blocks written
		size_type blocks_written;
		// the number of write operations used
		size_type writes;
		// (blocks_written - writes) / blocks_written represents the
		// "cache hit" ratio in the write cache
		// the number of blocks read

		// the number of blocks passed back to the bittorrent engine
		size_type blocks_read;
		// the number of blocks that was just copied from the read cache
		size_type blocks_read_hit;
		// the number of read operations used
		size_type reads;

		// the number of blocks in the cache (both read and write)
		int cache_size;

		// the number of blocks in the cache used for read cache
		int read_cache_size;

		// the total number of blocks that are currently in use
		// this includes send and receive buffers
		mutable int total_used_buffers;
	};

	struct disk_buffer_pool : boost::noncopyable
	{
		disk_buffer_pool(int block_size);
#ifdef TORRENT_DEBUG
		~disk_buffer_pool();
#endif

#ifdef TORRENT_DEBUG
		bool is_disk_buffer(char* buffer
			, boost::mutex::scoped_lock& l) const;
		bool is_disk_buffer(char* buffer) const;
#endif

		char* allocate_buffer(char const* category);
		void free_buffer(char* buf);

		char* allocate_buffers(int blocks, char const* category);
		void free_buffers(char* buf, int blocks);

		int block_size() const { return m_block_size; }

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		void release_memory();

		int in_use() const { return m_in_use; }

	protected:

		// number of bytes per block. The BitTorrent
		// protocol defines the block size to 16 KiB.
		const int m_block_size;

		// number of disk buffers currently allocated
		int m_in_use;

		session_settings m_settings;

	private:

		// this only protects the pool allocator
		typedef boost::mutex mutex_t;
		mutable mutex_t m_pool_mutex;
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
		// memory pool for read and write operations
		// and disk cache
		boost::pool<page_aligned_allocator> m_pool;
#endif

#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
		int m_allocations;
#endif
#ifdef TORRENT_DISK_STATS
	protected:
		void disk_buffer_pool::rename_buffer(char* buf, char const* category);
		std::map<std::string, int> m_categories;
		std::map<char*, std::string> m_buf_to_category;
		std::ofstream m_log;
	private:
#endif
#ifdef TORRENT_DEBUG
		int m_magic;
#endif
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : disk_buffer_pool
	{
		disk_io_thread(io_service& ios, int block_size = 16 * 1024);
		~disk_io_thread();

		void join();

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void get_cache_info(sha1_hash const& ih
			, std::vector<cached_piece_info>& ret) const;

		cache_status status() const;

		void operator()();

#ifdef TORRENT_DEBUG
		void check_invariant() const;
#endif

#ifdef TORRENT_DISK_STATS
		std::ofstream m_disk_access_log;
#endif

		struct cached_piece_entry
		{
			int piece;
			// storage this piece belongs to
			boost::intrusive_ptr<piece_manager> storage;
			// the last time a block was writting to this piece
			ptime last_use;
			// the number of blocks in the cache for this piece
			int num_blocks;
			// the pointers to the block data
			boost::shared_array<char*> blocks;
		};

		typedef boost::recursive_mutex mutex_t;
		typedef std::list<cached_piece_entry> cache_t;

	private:

		bool test_error(disk_io_job& j);
		void post_callback(boost::function<void(int, disk_io_job const&)> const& handler
			, disk_io_job const& j, int ret);

		// cache operations
		cache_t::iterator find_cached_piece(
			cache_t& cache, disk_io_job const& j
			, mutex_t::scoped_lock& l);
		int copy_from_piece(cache_t::iterator p, bool& hit
			, disk_io_job const& j, mutex_t::scoped_lock& l);

		// write cache operations
		void flush_cache_blocks(mutex_t::scoped_lock& l, int blocks);
		void flush_expired_pieces();
		void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
		int flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
			, mutex_t::scoped_lock& l);
		void flush_range(cache_t::iterator i, int start, int end, mutex_t::scoped_lock& l);
		void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);

		// read cache operations
		int clear_oldest_read_piece(cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int read_into_piece(cached_piece_entry& p, int start_block
			, int options, mutex_t::scoped_lock& l);
		int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
		int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
		int free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
		bool make_room(int num_blocks
			, cache_t::iterator ignore
			, bool flush_write_cache
			, mutex_t::scoped_lock& l);
		int try_read_from_cache(disk_io_job const& j);
		int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);

		// this mutex only protects m_jobs, m_queue_buffer_size
		// and m_abort
		mutable mutex_t m_queue_mutex;
		boost::condition m_signal;
		bool m_abort;
		bool m_waiting_to_shutdown;
		std::list<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		ptime m_last_file_check;

		// this protects the piece cache and related members
		mutable mutex_t m_piece_mutex;
		// write cache
		cache_t m_pieces;

		// read cache
		cache_t m_read_pieces;

		// total number of blocks in use by both the read
		// and the write cache. This is not supposed to
		// exceed m_cache_size
		cache_status m_cache_stats;

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif

		io_service& m_ios;

		// this keeps the io_service::run() call blocked from
		// returning. When shutting down, it's possible that
		// the event queue is drained before the disk_io_thread
		// has posted its last callback. When this happens, the
		// io_service will have a pending callback from the
		// disk_io_thread, but the event loop is not running.
		// this means that the event is destructed after the
		// disk_io_thread. If the event refers to a disk buffer
		// it will try to free it, but the buffer pool won't
		// exist anymore, and crash. This prevents that.
		boost::optional<asio::io_service::work> m_work;

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

#endif

<commit_msg>fixed syntax error<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 author 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 OWNER 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.

*/

#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD

#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include "libtorrent/allocator.hpp"
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_array.hpp>
#include <list>
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
#include <boost/pool/pool.hpp>
#endif
#include "libtorrent/session_settings.hpp"

namespace libtorrent
{
	struct cached_piece_info
	{
		int piece;
		std::vector<bool> blocks;
		ptime last_use;
		enum kind_t { read_cache = 0, write_cache = 1 };
		kind_t kind;
	};

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
			, check_fastresume
			, check_files
			, save_resume_data
			, rename_file
			, abort_thread
			, clear_read_cache
			, abort_torrent
			, update_settings
			, read_and_hash
		};

		action_t action;

		char* buffer;
		int buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage and rename_file. On errors, this is set
		// to the error message
		std::string str;

		// on error, this is set to the path of the
		// file the disk operation failed on
		std::string error_file;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		boost::shared_ptr<entry> resume_data;

		// the error code from the file operation
		error_code error;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	struct cache_status
	{
		cache_status()
			: blocks_written(0)
			, writes(0)
			, blocks_read(0)
			, blocks_read_hit(0)
			, reads(0)
			, cache_size(0)
			, read_cache_size(0)
			, total_used_buffers(0)
		{}

		// the number of 16kB blocks written
		size_type blocks_written;
		// the number of write operations used
		size_type writes;
		// (blocks_written - writes) / blocks_written represents the
		// "cache hit" ratio in the write cache
		// the number of blocks read

		// the number of blocks passed back to the bittorrent engine
		size_type blocks_read;
		// the number of blocks that was just copied from the read cache
		size_type blocks_read_hit;
		// the number of read operations used
		size_type reads;

		// the number of blocks in the cache (both read and write)
		int cache_size;

		// the number of blocks in the cache used for read cache
		int read_cache_size;

		// the total number of blocks that are currently in use
		// this includes send and receive buffers
		mutable int total_used_buffers;
	};

	struct disk_buffer_pool : boost::noncopyable
	{
		disk_buffer_pool(int block_size);
#ifdef TORRENT_DEBUG
		~disk_buffer_pool();
#endif

#ifdef TORRENT_DEBUG
		bool is_disk_buffer(char* buffer
			, boost::mutex::scoped_lock& l) const;
		bool is_disk_buffer(char* buffer) const;
#endif

		char* allocate_buffer(char const* category);
		void free_buffer(char* buf);

		char* allocate_buffers(int blocks, char const* category);
		void free_buffers(char* buf, int blocks);

		int block_size() const { return m_block_size; }

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		void release_memory();

		int in_use() const { return m_in_use; }

	protected:

		// number of bytes per block. The BitTorrent
		// protocol defines the block size to 16 KiB.
		const int m_block_size;

		// number of disk buffers currently allocated
		int m_in_use;

		session_settings m_settings;

	private:

		// this only protects the pool allocator
		typedef boost::mutex mutex_t;
		mutable mutex_t m_pool_mutex;
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
		// memory pool for read and write operations
		// and disk cache
		boost::pool<page_aligned_allocator> m_pool;
#endif

#if defined TORRENT_DISK_STATS || defined TORRENT_STATS
		int m_allocations;
#endif
#ifdef TORRENT_DISK_STATS
	protected:
		void rename_buffer(char* buf, char const* category);
		std::map<std::string, int> m_categories;
		std::map<char*, std::string> m_buf_to_category;
		std::ofstream m_log;
	private:
#endif
#ifdef TORRENT_DEBUG
		int m_magic;
#endif
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : disk_buffer_pool
	{
		disk_io_thread(io_service& ios, int block_size = 16 * 1024);
		~disk_io_thread();

		void join();

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void get_cache_info(sha1_hash const& ih
			, std::vector<cached_piece_info>& ret) const;

		cache_status status() const;

		void operator()();

#ifdef TORRENT_DEBUG
		void check_invariant() const;
#endif

#ifdef TORRENT_DISK_STATS
		std::ofstream m_disk_access_log;
#endif

		struct cached_piece_entry
		{
			int piece;
			// storage this piece belongs to
			boost::intrusive_ptr<piece_manager> storage;
			// the last time a block was writting to this piece
			ptime last_use;
			// the number of blocks in the cache for this piece
			int num_blocks;
			// the pointers to the block data
			boost::shared_array<char*> blocks;
		};

		typedef boost::recursive_mutex mutex_t;
		typedef std::list<cached_piece_entry> cache_t;

	private:

		bool test_error(disk_io_job& j);
		void post_callback(boost::function<void(int, disk_io_job const&)> const& handler
			, disk_io_job const& j, int ret);

		// cache operations
		cache_t::iterator find_cached_piece(
			cache_t& cache, disk_io_job const& j
			, mutex_t::scoped_lock& l);
		int copy_from_piece(cache_t::iterator p, bool& hit
			, disk_io_job const& j, mutex_t::scoped_lock& l);

		// write cache operations
		void flush_cache_blocks(mutex_t::scoped_lock& l, int blocks);
		void flush_expired_pieces();
		void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
		int flush_contiguous_blocks(disk_io_thread::cache_t::iterator e
			, mutex_t::scoped_lock& l);
		void flush_range(cache_t::iterator i, int start, int end, mutex_t::scoped_lock& l);
		void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);

		// read cache operations
		int clear_oldest_read_piece(cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int read_into_piece(cached_piece_entry& p, int start_block
			, int options, mutex_t::scoped_lock& l);
		int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
		int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
		int free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
		bool make_room(int num_blocks
			, cache_t::iterator ignore
			, bool flush_write_cache
			, mutex_t::scoped_lock& l);
		int try_read_from_cache(disk_io_job const& j);
		int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);

		// this mutex only protects m_jobs, m_queue_buffer_size
		// and m_abort
		mutable mutex_t m_queue_mutex;
		boost::condition m_signal;
		bool m_abort;
		bool m_waiting_to_shutdown;
		std::list<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		ptime m_last_file_check;

		// this protects the piece cache and related members
		mutable mutex_t m_piece_mutex;
		// write cache
		cache_t m_pieces;

		// read cache
		cache_t m_read_pieces;

		// total number of blocks in use by both the read
		// and the write cache. This is not supposed to
		// exceed m_cache_size
		cache_status m_cache_stats;

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif

		io_service& m_ios;

		// this keeps the io_service::run() call blocked from
		// returning. When shutting down, it's possible that
		// the event queue is drained before the disk_io_thread
		// has posted its last callback. When this happens, the
		// io_service will have a pending callback from the
		// disk_io_thread, but the event loop is not running.
		// this means that the event is destructed after the
		// disk_io_thread. If the event refers to a disk buffer
		// it will try to free it, but the buffer pool won't
		// exist anymore, and crash. This prevents that.
		boost::optional<asio::io_service::work> m_work;

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

#endif

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#ifndef MARKERS_SYMBOLIZER_HPP
#define MARKERS_SYMBOLIZER_HPP

namespace mapnik {

   struct MAPNIK_DECL markers_symbolizer
   {
     public:
      markers_symbolizer()
         : allow_overlap_(false) {}
     private:
      bool allow_overlap_;

   };
}

#endif // MARKERS_SYMBOLIZER_HPP
<commit_msg>expose get/set for allow_overlap in MarkersSymbolizer<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#ifndef MARKERS_SYMBOLIZER_HPP
#define MARKERS_SYMBOLIZER_HPP

namespace mapnik {

   struct MAPNIK_DECL markers_symbolizer
   {
    public:
      markers_symbolizer()
         : allow_overlap_(false) {}

    void set_allow_overlap(bool overlap)
    {
        allow_overlap_ = overlap;
    }
    float get_allow_overlap() const
    {
        return allow_overlap_;
    }
    private:
      bool allow_overlap_;

   };
}

#endif // MARKERS_SYMBOLIZER_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_ANALYZE_HPP
#define TAO_PEGTL_CONTRIB_ANALYZE_HPP

#include <cassert>
#include <cstddef>
#include <iostream>
#include <map>
#include <set>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

#include "../config.hpp"
#include "../traits.hpp"
#include "../visit.hpp"
#include "../visit_rt.hpp"

#include "analyze_traits.hpp"

#include "../internal/demangle.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      enum class analyze_type : std::uint8_t
      {
         any,  // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules.
         opt,  // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules.
         seq,  // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules.
         sor   // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules.
      };

      template< typename T >
      struct analyze_type_traits;

      template<>
      struct analyze_type_traits< bytes< 1 > >
      {
         static constexpr analyze_type value = analyze_type::any;
      };

      template< typename... Rules >
      struct analyze_type_traits< opt< Rules... > >
      {
         static constexpr analyze_type value = analyze_type::opt;
      };

      template< typename... Rules >
      struct analyze_type_traits< seq< Rules... > >
      {
         static constexpr analyze_type value = analyze_type::seq;
      };

      template< typename... Rules >
      struct analyze_type_traits< sor< Rules... > >
      {
         static constexpr analyze_type value = analyze_type::sor;
      };

      struct analyze_entry
      {
         explicit analyze_entry( const analyze_type in_type ) noexcept
            : type( in_type )
         {}

         analyze_type type;
         std::vector< std::string_view > subs;
      };

      template< typename C >
      class analyze_guard
      {
      public:
         analyze_guard( C& container, const typename C::value_type& value )
            : m_i( container.insert( value ) ),
              m_c( container )
         {}

         analyze_guard( analyze_guard&& ) = delete;
         analyze_guard( const analyze_guard& ) = delete;

         void operator=( analyze_guard&& ) = delete;
         void operator=( const analyze_guard& ) = delete;

         ~analyze_guard()
         {
            if( m_i.second ) {
               m_c.erase( m_i.first );
            }
         }

         explicit operator bool() const noexcept
         {
            return m_i.second;
         }

      private:
         const std::pair< typename C::iterator, bool > m_i;
         C& m_c;
      };

      template< typename C >
      analyze_guard( C&, const typename C::value_type& )->analyze_guard< C >;

      class analyze_cycles_impl
      {
      public:
         analyze_cycles_impl( analyze_cycles_impl&& ) = delete;
         analyze_cycles_impl( const analyze_cycles_impl& ) = delete;

         void operator=( analyze_cycles_impl&& ) = delete;
         void operator=( const analyze_cycles_impl& ) = delete;

         [[nodiscard]] std::size_t problems()
         {
            for( auto i = m_info.begin(); i != m_info.end(); ++i ) {
               m_results[ i->first ] = work( i, false );
               m_cache.clear();
            }
            return m_problems;
         }

         template< typename Rule >
         [[nodiscard]] bool consumes() const noexcept
         {
            const auto i = m_results.find( demangle< Rule >() );
            assert( i != m_results.end() );
            return i->second;
         }

      protected:
         explicit analyze_cycles_impl( const bool verbose ) noexcept
            : m_verbose( verbose ),
              m_problems( 0 )
         {}

         [[nodiscard]] std::map< std::string_view, analyze_entry >::const_iterator find( const std::string_view name ) const noexcept
         {
            const auto iter = m_info.find( name );
            assert( iter != m_info.end() );
            return iter;
         }

         [[nodiscard]] bool work( const std::map< std::string_view, analyze_entry >::const_iterator& start, const bool accum )
         {
            const auto j = m_cache.find( start->first );

            if( j != m_cache.end() ) {
               return j->second;
            }
            if( const auto g = analyze_guard( m_stack, start->first ) ) {
               switch( start->second.type ) {
                  case analyze_type::any: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = true;
                  }
                  case analyze_type::opt: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = false;
                  }
                  case analyze_type::seq: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = a;
                  }
                  case analyze_type::sor: {
                     bool a = true;
                     for( const auto& r : start->second.subs ) {
                        a = a && work( find( r ), accum );
                     }
                     return m_cache[ start->first ] = a;
                  }
               }
               assert( false );  // LCOV_EXCL_LINE
            }
            if( !accum ) {
               ++m_problems;
               if( m_verbose ) {
                  std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
               }
            }
            return m_cache[ start->first ] = accum;
         }

         const bool m_verbose;

         std::size_t m_problems;

         std::map< std::string_view, analyze_entry > m_info;
         std::set< std::string_view > m_stack;
         std::map< std::string_view, bool > m_cache;
         std::map< std::string_view, bool > m_results;
      };

      template< template< typename... > class Traits, typename... Subs >
      void analyze_insert_impl( rule_list< Subs... >& /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info );

      template< typename Name, template< typename... > class Traits >
      std::string_view analyze_insert( std::map< std::string_view, analyze_entry >& info )
      {
         using Rule = typename analyze_traits< Name, typename Name::rule_t >::reduced;

         const auto [ i, b ] = info.try_emplace( demangle< Name >(), analyze_type_traits< Rule >::value );
         if( b ) {
            analyze_insert_impl< Traits >( typename Traits< typename Rule::rule_t >::subs(), i->second.subs, info );
         }
         return i->first;
      }

      template< template< typename... > class Traits, typename... Subs >
      void analyze_insert_impl( rule_list< Subs... >&& /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info )
      {
         ( subs.emplace_back( analyze_insert< Subs, Traits >( info ) ), ... );
      }

      template< typename Grammar, template< typename... > class Traits = traits >
      class analyze_cycles
         : public analyze_cycles_impl
      {
      public:
         explicit analyze_cycles( const bool verbose )
            : analyze_cycles_impl( verbose )
         {
            analyze_insert< Grammar, Traits >( m_info );
         }
      };

   }  // namespace internal

   template< typename Grammar, template< typename... > class Traits = traits >
   [[nodiscard]] std::size_t analyze( const bool verbose = true )
   {
      return internal::analyze_cycles< Grammar, Traits >( verbose ).problems();
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<commit_msg>Simplify<commit_after>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_ANALYZE_HPP
#define TAO_PEGTL_CONTRIB_ANALYZE_HPP

#include <cassert>
#include <cstddef>
#include <iostream>
#include <map>
#include <set>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

#include "../config.hpp"
#include "../traits.hpp"
#include "../visit.hpp"
#include "../visit_rt.hpp"

#include "analyze_traits.hpp"

#include "../internal/demangle.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      enum class analyze_type : std::uint8_t
      {
         any,  // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules.
         opt,  // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules.
         seq,  // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules.
         sor   // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules.
      };

      template< typename T >
      inline constexpr analyze_type analyze_type_value;

      template<>
      inline constexpr analyze_type analyze_type_value< bytes< 1 > > = analyze_type::any;

      template< typename... Rules >
      inline constexpr analyze_type analyze_type_value< opt< Rules... > > = analyze_type::opt;

      template< typename... Rules >
      inline constexpr analyze_type analyze_type_value< seq< Rules... > > = analyze_type::seq;

      template< typename... Rules >
      inline constexpr analyze_type analyze_type_value< sor< Rules... > > = analyze_type::sor;

      struct analyze_entry
      {
         explicit analyze_entry( const analyze_type in_type ) noexcept
            : type( in_type )
         {}

         analyze_type type;
         std::vector< std::string_view > subs;
      };

      template< typename C >
      class analyze_guard
      {
      public:
         analyze_guard( C& container, const typename C::value_type& value )
            : m_i( container.insert( value ) ),
              m_c( container )
         {}

         analyze_guard( analyze_guard&& ) = delete;
         analyze_guard( const analyze_guard& ) = delete;

         void operator=( analyze_guard&& ) = delete;
         void operator=( const analyze_guard& ) = delete;

         ~analyze_guard()
         {
            if( m_i.second ) {
               m_c.erase( m_i.first );
            }
         }

         explicit operator bool() const noexcept
         {
            return m_i.second;
         }

      private:
         const std::pair< typename C::iterator, bool > m_i;
         C& m_c;
      };

      template< typename C >
      analyze_guard( C&, const typename C::value_type& )->analyze_guard< C >;

      class analyze_cycles_impl
      {
      public:
         analyze_cycles_impl( analyze_cycles_impl&& ) = delete;
         analyze_cycles_impl( const analyze_cycles_impl& ) = delete;

         void operator=( analyze_cycles_impl&& ) = delete;
         void operator=( const analyze_cycles_impl& ) = delete;

         [[nodiscard]] std::size_t problems()
         {
            for( auto i = m_info.begin(); i != m_info.end(); ++i ) {
               m_results[ i->first ] = work( i, false );
               m_cache.clear();
            }
            return m_problems;
         }

         template< typename Rule >
         [[nodiscard]] bool consumes() const noexcept
         {
            const auto i = m_results.find( demangle< Rule >() );
            assert( i != m_results.end() );
            return i->second;
         }

      protected:
         explicit analyze_cycles_impl( const bool verbose ) noexcept
            : m_verbose( verbose ),
              m_problems( 0 )
         {}

         [[nodiscard]] std::map< std::string_view, analyze_entry >::const_iterator find( const std::string_view name ) const noexcept
         {
            const auto iter = m_info.find( name );
            assert( iter != m_info.end() );
            return iter;
         }

         [[nodiscard]] bool work( const std::map< std::string_view, analyze_entry >::const_iterator& start, const bool accum )
         {
            const auto j = m_cache.find( start->first );

            if( j != m_cache.end() ) {
               return j->second;
            }
            if( const auto g = analyze_guard( m_stack, start->first ) ) {
               switch( start->second.type ) {
                  case analyze_type::any: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = true;
                  }
                  case analyze_type::opt: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = false;
                  }
                  case analyze_type::seq: {
                     bool a = false;
                     for( const auto& r : start->second.subs ) {
                        a = a || work( find( r ), accum || a );
                     }
                     return m_cache[ start->first ] = a;
                  }
                  case analyze_type::sor: {
                     bool a = true;
                     for( const auto& r : start->second.subs ) {
                        a = a && work( find( r ), accum );
                     }
                     return m_cache[ start->first ] = a;
                  }
               }
               assert( false );  // LCOV_EXCL_LINE
            }
            if( !accum ) {
               ++m_problems;
               if( m_verbose ) {
                  std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
               }
            }
            return m_cache[ start->first ] = accum;
         }

         const bool m_verbose;

         std::size_t m_problems;

         std::map< std::string_view, analyze_entry > m_info;
         std::set< std::string_view > m_stack;
         std::map< std::string_view, bool > m_cache;
         std::map< std::string_view, bool > m_results;
      };

      template< template< typename... > class Traits, typename... Subs >
      void analyze_insert_impl( rule_list< Subs... >& /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info );

      template< typename Name, template< typename... > class Traits >
      std::string_view analyze_insert( std::map< std::string_view, analyze_entry >& info )
      {
         using Rule = typename analyze_traits< Name, typename Name::rule_t >::reduced;

         const auto [ i, b ] = info.try_emplace( demangle< Name >(), analyze_type_value< Rule > );
         if( b ) {
            analyze_insert_impl< Traits >( typename Traits< typename Rule::rule_t >::subs(), i->second.subs, info );
         }
         return i->first;
      }

      template< template< typename... > class Traits, typename... Subs >
      void analyze_insert_impl( rule_list< Subs... >&& /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info )
      {
         ( subs.emplace_back( analyze_insert< Subs, Traits >( info ) ), ... );
      }

      template< typename Grammar, template< typename... > class Traits = traits >
      class analyze_cycles
         : public analyze_cycles_impl
      {
      public:
         explicit analyze_cycles( const bool verbose )
            : analyze_cycles_impl( verbose )
         {
            analyze_insert< Grammar, Traits >( m_info );
         }
      };

   }  // namespace internal

   template< typename Grammar, template< typename... > class Traits = traits >
   [[nodiscard]] std::size_t analyze( const bool verbose = true )
   {
      return internal::analyze_cycles< Grammar, Traits >( verbose ).problems();
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_COUNTER_HPP
#define TAO_PEGTL_CONTRIB_COUNTER_HPP

#include <cassert>
#include <map>
#include <string>
#include <utility>

#include "../config.hpp"
#include "../normal.hpp"

#include "../internal/demangle.hpp"

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      struct counter_data
      {
         unsigned start = 0;
         unsigned success = 0;
         unsigned failure = 0;
      };

      struct counter_state
      {
         std::map< std::string, counter_data > counts;
      };

      template< typename Rule >
      struct counter
         : normal< Rule >
      {
         template< typename Input >
         static void start( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].start;
         }

         template< typename Input >
         static void success( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].success;
         }

         template< typename Input >
         static void failure( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].failure;
         }
      };

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#endif
<commit_msg>Remove superfluous includes<commit_after>// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_COUNTER_HPP
#define TAO_PEGTL_CONTRIB_COUNTER_HPP

#include <map>
#include <string>

#include "../config.hpp"
#include "../normal.hpp"

#include "../internal/demangle.hpp"

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      struct counter_data
      {
         unsigned start = 0;
         unsigned success = 0;
         unsigned failure = 0;
      };

      struct counter_state
      {
         std::map< std::string, counter_data > counts;
      };

      template< typename Rule >
      struct counter
         : normal< Rule >
      {
         template< typename Input >
         static void start( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].start;
         }

         template< typename Input >
         static void success( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].success;
         }

         template< typename Input >
         static void failure( const Input& /*unused*/, counter_state& ts )
         {
            ++ts.counts[ internal::demangle< Rule >() ].failure;
         }
      };

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#endif
<|endoftext|>


<commit_before>#ifndef TOOLBOX_MARSHALL_MARSHALL_HPP
#define TOOLBOX_MARSHALL_MARSHALL_HPP

#include <meta/meta.hpp>
#include <toolbox/cpp/tuple_for_each.hpp>
#include <json/json.hpp>

namespace toolbox
{
namespace marshall
{

template<
	typename SizeT,
	typename ElementT,
	template<typename...> class ContainerT = std::vector>
struct dynamic_array : public ContainerT<ElementT>
{
	using array_size_t = SizeT;
	using element_t = ElementT;
};

template<typename...> struct is_dynamic_array : std::false_type {};
template<typename A, typename B, template<typename ... > class C> struct is_dynamic_array<dynamic_array<A, B, C>> : std::true_type {};

template<typename... Fields>
struct record
{
private:
	template<typename T>
	struct field_description
	{
		std::string short_name;
		std::string description;
	};

	template<typename T>
	struct field
	{
		field(const field_description<T> & desc) :
			description(desc) {}

		field_description<T> description;
		T value;
		using type = T;
	};

private:
	template<typename T> struct has_tag
	{
		template<typename U> static std::true_type check(typename U::marshall_record_tag *);
		template<typename> static std::false_type check(...);

		static constexpr auto value = decltype(check<T>(nullptr))::value;
	};

	template<typename Visitor, typename T>
	typename std::enable_if<has_tag<T>::value>::type
	visit_impl(Visitor &&visitor, field<T> &f)
	{
		visitor.enter(f);
		f.value.visit(visitor);
		visitor.leave(f);
	}

	template<typename Visitor, typename T>
	typename std::enable_if<!has_tag<T>::value>::type
	visit_impl(Visitor &&visitor, field<T> &f)
	{
		visitor.visit(f);
	}

public:
	using types = meta::list<Fields...>;
	using fields_count = meta::size<types>;
	using marshall_record_tag = void;

	record(field_description<Fields>... descriptions) :
		fields(descriptions...)
	{}

	template<typename Visitor>
	void visit(Visitor &&visitor)
	{
		cpp::tuple_for_each(
			fields,
			[&](auto &f)
			{
				visit_impl(visitor, f);
			}
		);
	}

	template<std::size_t I>
	auto & get()
	{
		return std::get<I>(fields).value;
	}

	std::tuple<field<Fields>...> fields;
};

namespace detail
{

template<typename S>
struct record_serializer
{
	record_serializer(S &s) : s(s) {}
	S& s;

	template<typename T> void enter(T &) {}
	template<typename T> void leave(T &) {}

	template<typename T>
	typename std::enable_if<is_dynamic_array<typename T::type>::value>::type
	visit(T &f)
	{
		typename T::type::array_size_t size = f.value.size();
		s.write(reinterpret_cast<const char *>(&size), sizeof(size));

		for (const auto &e : f.value) {
			s.write(reinterpret_cast<const char*>(&e), sizeof(e));
		}
	}

	template<typename T>
	typename std::enable_if<std::is_trivially_copyable<typename T::type>::value>::type
	visit(T &f)
	{
		s.write(reinterpret_cast<const char *>(&f.value), sizeof(f.value));
	}
};

template<typename S>
struct record_deserializer
{
	record_deserializer(S &s) : s(s) {}
	S& s;

	template<typename T> void enter(T &) {}
	template<typename T> void leave(T &) {}

	template<typename T>
	typename std::enable_if<is_dynamic_array<typename T::type>::value>::type
	visit(T &f)
	{
		using size_type = typename T::type::array_size_t;

		size_type size = f.value.size();
		s.read(reinterpret_cast<char *>(&size), sizeof(size));
		f.value.clear();

		for (size_type i = 0; i < size; i ++) {
			typename T::type::element_t el;
			s.read(reinterpret_cast<char *>(&el), sizeof(el));
			f.value.push_back(el);
		}
	}

	template<typename T>
	typename std::enable_if<std::is_trivially_copyable<typename T::type>::value>::type
	visit(T &f)
	{
		s.read(reinterpret_cast<char *>(&f.value), sizeof(f.value));
	}
};

}

template<typename S, typename T>
void serialize(S &s, T& record)
{
	record.visit(detail::record_serializer<S>{s});
}

template<typename S, typename T>
void deserialize(S &s, T& record)
{
	record.visit(detail::record_deserializer<S>{s});
}

namespace json
{
namespace detail
{
struct json_serializer
{
	nlohmann::json j;
	nlohmann::json *current;
	nlohmann::json *previous;

	json_serializer() :
		j {},
		current {&j}
	{}

	json_serializer(const json_serializer &) = delete;
	void operator=(const json_serializer &) = delete;

	template<typename T> void enter(T &t)
	{
		previous = current;
		current = &(*current)[t.description.short_name];
	}

	template<typename T> void leave(T &t)
	{
		current = previous;
	}

	template<typename T>
	typename std::enable_if<std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		static_assert(std::rank<typename T::type>::value == 1, "can only serialize 1-dimensional array");

		auto arr = nlohmann::json::array();

		for (const auto &e : t.value)
			arr.push_back(e);

		(*current)[t.description.short_name] = arr;
	}

	template<typename T>
	typename std::enable_if<!std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		(*current)[t.description.short_name] = t.value;
	}
};

struct json_deserializer
{
	nlohmann::json &j;
	nlohmann::json *current;
	nlohmann::json *previous;

	json_deserializer(nlohmann::json &j) : j(j), current(&j) {}

	template<typename T> void enter(T &t)
	{
		previous = current;
		current = &(*current)[t.description.short_name];
	}

	template<typename T> void leave(T &t)
	{
		current = previous;
	}

	template<typename T>
	typename std::enable_if<std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		using array_type = typename T::type;
		using value_type = typename std::remove_extent<array_type>::type;

		static_assert(std::rank<typename T::type>::value == 1, "can only deserialize 1-dimensional array");

		for (auto i = 0u; i < std::extent<typename T::type>::value; i ++)
			t.value[i] = (*current)[t.description.short_name][i].template get<value_type>();
	}

	template<typename T>
	typename std::enable_if<!std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		t.value = (*current)[t.description.short_name];
	}

};

} // namespace detail

template<typename T>
nlohmann::json serialize(T& record)
{
	detail::json_serializer visitor{};
	record.visit(visitor);
	return visitor.j;
}

template<typename T>
void deserialize(nlohmann::json &j, T &record)
{
	detail::json_deserializer visitor {j};
	record.visit(visitor);
}

} // namespace json

}
}

#endif
<commit_msg>[fix] compilation issue with GCC 6.3.0<commit_after>#ifndef TOOLBOX_MARSHALL_MARSHALL_HPP
#define TOOLBOX_MARSHALL_MARSHALL_HPP

#include <meta/meta.hpp>
#include <toolbox/cpp/tuple_for_each.hpp>
#include <json/json.hpp>

namespace toolbox
{
namespace marshall
{

template<
	typename SizeT,
	typename ElementT,
	template<typename...> class ContainerT = std::vector>
struct dynamic_array : public ContainerT<ElementT>
{
	using array_size_t = SizeT;
	using element_t = ElementT;
};

template<typename...> struct is_dynamic_array : std::false_type {};
template<typename A, typename B, template<typename ... > class C> struct is_dynamic_array<dynamic_array<A, B, C>> : std::true_type {};

template<typename... Fields>
struct record
{
private:
	template<typename T>
	struct field_description
	{
		std::string short_name;
		std::string description;
	};

	template<typename T>
	struct field
	{
		field(const field_description<T> & desc) :
			description(desc) {}

		field_description<T> description;
		T value;
		using type = T;
	};

private:
	template<typename T> struct has_tag
	{
		template<typename U> static std::true_type check(typename U::marshall_record_tag *);
		template<typename> static std::false_type check(...);

		static constexpr auto value = decltype(check<T>(nullptr))::value;
	};

	template<typename Visitor>
	struct visitor_impl
	{
		Visitor &visitor_;

		visitor_impl(Visitor &visitor) : visitor_ (visitor) {}

		template<typename T>
		typename std::enable_if<has_tag<T>::value>::type
		operator()(field<T> &f)
		{
			visitor_.enter(f);
			f.value.visit(visitor_);
			visitor_.leave(f);
		}

		template<typename T>
		typename std::enable_if<!has_tag<T>::value>::type
		operator()(field<T> &f)
		{
			visitor_.visit(f);
		}
	};

public:
	using types = meta::list<Fields...>;
	using fields_count = meta::size<types>;
	using marshall_record_tag = void;

	record(field_description<Fields>... descriptions) :
		fields(descriptions...)
	{}

	template<typename Visitor>
	void visit(Visitor &&visitor)
	{
		visitor_impl<Visitor> vis(visitor);
		cpp::tuple_for_each(
			fields,
			vis
		);
	}

	template<std::size_t I>
	auto & get()
	{
		return std::get<I>(fields).value;
	}

	std::tuple<field<Fields>...> fields;
};

namespace detail
{

template<typename S>
struct record_serializer
{
	record_serializer(S &s) : s(s) {}
	S& s;

	template<typename T> void enter(T &) {}
	template<typename T> void leave(T &) {}

	template<typename T>
	typename std::enable_if<is_dynamic_array<typename T::type>::value>::type
	visit(T &f)
	{
		typename T::type::array_size_t size = f.value.size();
		s.write(reinterpret_cast<const char *>(&size), sizeof(size));

		for (const auto &e : f.value) {
			s.write(reinterpret_cast<const char*>(&e), sizeof(e));
		}
	}

	template<typename T>
	typename std::enable_if<std::is_trivially_copyable<typename T::type>::value>::type
	visit(T &f)
	{
		s.write(reinterpret_cast<const char *>(&f.value), sizeof(f.value));
	}
};

template<typename S>
struct record_deserializer
{
	record_deserializer(S &s) : s(s) {}
	S& s;

	template<typename T> void enter(T &) {}
	template<typename T> void leave(T &) {}

	template<typename T>
	typename std::enable_if<is_dynamic_array<typename T::type>::value>::type
	visit(T &f)
	{
		using size_type = typename T::type::array_size_t;

		size_type size = f.value.size();
		s.read(reinterpret_cast<char *>(&size), sizeof(size));
		f.value.clear();

		for (size_type i = 0; i < size; i ++) {
			typename T::type::element_t el;
			s.read(reinterpret_cast<char *>(&el), sizeof(el));
			f.value.push_back(el);
		}
	}

	template<typename T>
	typename std::enable_if<std::is_trivially_copyable<typename T::type>::value>::type
	visit(T &f)
	{
		s.read(reinterpret_cast<char *>(&f.value), sizeof(f.value));
	}
};

}

template<typename S, typename T>
void serialize(S &s, T& record)
{
	record.visit(detail::record_serializer<S>{s});
}

template<typename S, typename T>
void deserialize(S &s, T& record)
{
	record.visit(detail::record_deserializer<S>{s});
}

namespace json
{
namespace detail
{
struct json_serializer
{
	nlohmann::json j;
	nlohmann::json *current;
	nlohmann::json *previous;

	json_serializer() :
		j {},
		current {&j}
	{}

	json_serializer(const json_serializer &) = delete;
	void operator=(const json_serializer &) = delete;

	template<typename T> void enter(T &t)
	{
		previous = current;
		current = &(*current)[t.description.short_name];
	}

	template<typename T> void leave(T &t)
	{
		current = previous;
	}

	template<typename T>
	typename std::enable_if<std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		static_assert(std::rank<typename T::type>::value == 1, "can only serialize 1-dimensional array");

		auto arr = nlohmann::json::array();

		for (const auto &e : t.value)
			arr.push_back(e);

		(*current)[t.description.short_name] = arr;
	}

	template<typename T>
	typename std::enable_if<!std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		(*current)[t.description.short_name] = t.value;
	}
};

struct json_deserializer
{
	nlohmann::json &j;
	nlohmann::json *current;
	nlohmann::json *previous;

	json_deserializer(nlohmann::json &j) : j(j), current(&j) {}

	template<typename T> void enter(T &t)
	{
		previous = current;
		current = &(*current)[t.description.short_name];
	}

	template<typename T> void leave(T &t)
	{
		current = previous;
	}

	template<typename T>
	typename std::enable_if<std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		using array_type = typename T::type;
		using value_type = typename std::remove_extent<array_type>::type;

		static_assert(std::rank<typename T::type>::value == 1, "can only deserialize 1-dimensional array");

		for (auto i = 0u; i < std::extent<typename T::type>::value; i ++)
			t.value[i] = (*current)[t.description.short_name][i].template get<value_type>();
	}

	template<typename T>
	typename std::enable_if<!std::is_array<typename T::type>::value>::type
	visit(T &t)
	{
		t.value = (*current)[t.description.short_name];
	}

};

} // namespace detail

template<typename T>
nlohmann::json serialize(T& record)
{
	detail::json_serializer visitor{};
	record.visit(visitor);
	return visitor.j;
}

template<typename T>
void deserialize(nlohmann::json &j, T &record)
{
	detail::json_deserializer visitor {j};
	record.visit(visitor);
}

} // namespace json

}
}

#endif
<|endoftext|>