<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH
#define DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH

#include <vector>
#include <type_traits>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/mapper/interface.hh>

namespace Dune {
namespace GDT {

template <class VectorImp>
class ConstLocalDoFVector
{
  static_assert(std::is_base_of<Stuff::LA::VectorInterface<typename VectorImp::Traits>, VectorImp>::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");

public:
  typedef VectorImp VectorType;
  typedef typename VectorType::ScalarType ScalarType;

  template <class M, class EntityType>
  ConstLocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, const VectorType& vector)
    : vector_(vector)
    , indices_(mapper.numDofs(entity))
  {
    mapper.globalIndices(entity, indices_);
  }

  ~ConstLocalDoFVector()
  {
  }

  size_t size() const
  {
    return indices_.size();
  }

  ScalarType get(const size_t ii) const
  {
    assert(ii < indices_.size());
    return vector_.get_entry(indices_[ii]);
  }

private:
  const VectorType& vector_;

protected:
  mutable Dune::DynamicVector<size_t> indices_;

private:
  template <class V>
  friend std::ostream& operator<<(std::ostream& /*out*/, const ConstLocalDoFVector<V>& /*vector*/);
}; // class ConstLocalDoFVector

template <class V>
std::ostream& operator<<(std::ostream& out, const ConstLocalDoFVector<V>& vector)
{
  out << "[";
  const size_t sz = vector.size();
  if (sz > 0) {
    out << vector.get(0);
    for (size_t ii = 1; ii < sz; ++ii)
      out << ", " << vector.get(ii);
  } else
    out << " ";
  out << "]";
  return out;
} // ... operator<<(...)

template <class VectorImp>
class LocalDoFVector : public ConstLocalDoFVector<VectorImp>
{
  typedef ConstLocalDoFVector<VectorImp> BaseType;

public:
  typedef typename BaseType::VectorType VectorType;
  typedef typename BaseType::ScalarType ScalarType;

  template <class M, class EntityType>
  LocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, VectorType& vector)
    : BaseType(mapper, entity, vector)
    , vector_(vector)
  {
  }

  ~LocalDoFVector()
  {
  }

  void set(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.set_entry(indices_[ii], val);
  }

  void add(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.add(indices_[ii], val);
  }

private:
  using BaseType::indices_;
  VectorType& vector_;
}; // class LocalDoFVector

template <class SpaceImp, class VectorImp>
class ConstLocalDiscreteFunction
    : public Stuff::LocalfunctionInterface<typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType,
                                           SpaceImp::dimDomain, typename SpaceImp::RangeFieldType, SpaceImp::dimRange,
                                           SpaceImp::dimRangeCols>
{
  static_assert(std::is_base_of<SpaceInterface<typename SpaceImp::Traits>, SpaceImp>::value,
                "SpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>, VectorImp>::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");
  static_assert(std::is_same<typename SpaceImp::RangeFieldType, typename VectorImp::ScalarType>::value,
                "Types do not match!");
  typedef Stuff::LocalfunctionInterface<typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType,
                                        SpaceImp::dimDomain, typename SpaceImp::RangeFieldType, SpaceImp::dimRange,
                                        SpaceImp::dimRangeCols> BaseType;
  typedef ConstLocalDiscreteFunction<SpaceImp, VectorImp> ThisType;

public:
  typedef SpaceImp SpaceType;
  typedef VectorImp VectorType;
  typedef typename BaseType::EntityType EntityType;

  typedef typename BaseType::DomainFieldType DomainFieldType;
  static const unsigned int dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainType DomainType;

  typedef typename BaseType::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = BaseType::dimRangeCols;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeType RangeType;

  typedef typename BaseType::JacobianRangeType JacobianRangeType;

private:
  typedef typename SpaceType::BaseFunctionSetType BaseFunctionSetType;

public:
  typedef ConstLocalDoFVector<VectorType> ConstLocalDoFVectorType;

  ConstLocalDiscreteFunction(const SpaceType& space, const VectorType& globalVector, const EntityType& ent)
    : BaseType(ent)
    , space_(space)
    , base_(new BaseFunctionSetType(space_.base_function_set(this->entity())))
    , localVector_(new ConstLocalDoFVectorType(space_.mapper(), this->entity(), globalVector))
    , tmpBaseValues_(base_->size(), RangeType(0))
    , tmpBaseJacobianValues_(base_->size(), JacobianRangeType(0))
  {
    assert(localVector_->size() == base_->size());
  }

  ConstLocalDiscreteFunction(ThisType&& source)
    : BaseType(source.entity())
    , space_(source.space_)
    , base_(std::move(source.base_))
    , localVector_(std::move(source.localVector_))
    , tmpBaseValues_(std::move(source.tmpBaseValues_))
    , tmpBaseJacobianValues_(std::move(source.tmpBaseJacobianValues_))
  {
  }

  ConstLocalDiscreteFunction(const ThisType& other) = delete;

  ThisType& operator=(const ThisType& other) = delete;

  virtual ~ConstLocalDiscreteFunction()
  {
  }

  const BaseFunctionSetType& base() const
  {
    return *base_;
  }

  const ConstLocalDoFVectorType& vector() const
  {
    return *localVector_;
  }

  virtual size_t order() const DS_OVERRIDE
  {
    return base_->order();
  }

  virtual void evaluate(const DomainType& xx, RangeType& ret) const DS_OVERRIDE
  {
    assert(this->is_a_valid_point(xx));
    Dune::Stuff::Common::clear(ret);
    assert(localVector_->size() == tmpBaseValues_.size());
    base_->evaluate(xx, tmpBaseValues_);
    for (size_t ii = 0; ii < localVector_->size(); ++ii) {
      tmpBaseValues_[ii] *= localVector_->get(ii);
      ret += tmpBaseValues_[ii];
    }
  } // ... evaluate(...)

  virtual void jacobian(const DomainType& xx, JacobianRangeType& ret) const DS_OVERRIDE
  {
    assert(this->is_a_valid_point(xx));
    ret *= RangeFieldType(0);
    assert(localVector_->size() == tmpBaseJacobianValues_.size());
    base_->jacobian(xx, tmpBaseJacobianValues_);
    for (size_t ii = 0; ii < localVector_->size(); ++ii) {
      tmpBaseJacobianValues_[ii] *= localVector_->get(ii);
      ret += tmpBaseJacobianValues_[ii];
    }
  } // ... jacobian(...)

  using BaseType::evaluate;
  using BaseType::jacobian;

protected:
  const SpaceType& space_;
  std::unique_ptr<const BaseFunctionSetType> base_;
  std::unique_ptr<const ConstLocalDoFVectorType> localVector_;

private:
  mutable std::vector<RangeType> tmpBaseValues_;
  mutable std::vector<JacobianRangeType> tmpBaseJacobianValues_;
}; // class ConstLocalDiscreteFunction

template <class SpaceImp, class VectorImp>
class LocalDiscreteFunction : public ConstLocalDiscreteFunction<SpaceImp, VectorImp>
{
  typedef ConstLocalDiscreteFunction<SpaceImp, VectorImp> BaseType;
  typedef LocalDiscreteFunction<SpaceImp, VectorImp> ThisType;

public:
  typedef typename BaseType::SpaceType SpaceType;
  typedef typename BaseType::VectorType VectorType;
  typedef typename BaseType::EntityType EntityType;

  typedef typename BaseType::DomainFieldType DomainFieldType;
  static const unsigned int dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainType DomainType;

  typedef typename BaseType::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = BaseType::dimRangeCols;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeType RangeType;

  typedef typename BaseType::JacobianRangeType JacobianRangeType;

private:
  typedef typename SpaceType::BaseFunctionSetType BaseFunctionSetType;

public:
  typedef LocalDoFVector<VectorType> LocalDoFVectorType;

  LocalDiscreteFunction(const SpaceType& space, VectorType& globalVector, const EntityType& ent)
    : BaseType(space, globalVector, ent)
    , localVector_(new LocalDoFVectorType(space_.mapper(), entity_, globalVector))
  {
    assert(localVector_->size() == base_->size());
  }

  LocalDiscreteFunction(ThisType&& source)
    : BaseType(std::move(source)) // <- because of this
    , localVector_(std::move(source.localVector_)) // <- I am not sure if this is valid -+^
  {
  }

  LocalDiscreteFunction(const ThisType& other) = delete;

  ThisType& operator=(const ThisType& other) = delete;

  virtual ~LocalDiscreteFunction()
  {
  }

  LocalDoFVectorType& vector()
  {
    return *localVector_;
  }

private:
  using BaseType::space_;
  using BaseType::entity_;
  using BaseType::base_;
  std::unique_ptr<LocalDoFVectorType> localVector_;
}; // class LocalDiscreteFunction

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH
<commit_msg>fixes unusable add method in LocalDofVector<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH
#define DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH

#include <vector>
#include <type_traits>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/mapper/interface.hh>

namespace Dune {
namespace GDT {

template <class VectorImp>
class ConstLocalDoFVector
{
  static_assert(std::is_base_of<Stuff::LA::VectorInterface<typename VectorImp::Traits>, VectorImp>::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");

public:
  typedef VectorImp VectorType;
  typedef typename VectorType::ScalarType ScalarType;

  template <class M, class EntityType>
  ConstLocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, const VectorType& vector)
    : vector_(vector)
    , indices_(mapper.numDofs(entity))
  {
    mapper.globalIndices(entity, indices_);
  }

  ~ConstLocalDoFVector()
  {
  }

  size_t size() const
  {
    return indices_.size();
  }

  ScalarType get(const size_t ii) const
  {
    assert(ii < indices_.size());
    return vector_.get_entry(indices_[ii]);
  }

private:
  const VectorType& vector_;

protected:
  mutable Dune::DynamicVector<size_t> indices_;

private:
  template <class V>
  friend std::ostream& operator<<(std::ostream& /*out*/, const ConstLocalDoFVector<V>& /*vector*/);
}; // class ConstLocalDoFVector

template <class V>
std::ostream& operator<<(std::ostream& out, const ConstLocalDoFVector<V>& vector)
{
  out << "[";
  const size_t sz = vector.size();
  if (sz > 0) {
    out << vector.get(0);
    for (size_t ii = 1; ii < sz; ++ii)
      out << ", " << vector.get(ii);
  } else
    out << " ";
  out << "]";
  return out;
} // ... operator<<(...)

template <class VectorImp>
class LocalDoFVector : public ConstLocalDoFVector<VectorImp>
{
  typedef ConstLocalDoFVector<VectorImp> BaseType;

public:
  typedef typename BaseType::VectorType VectorType;
  typedef typename BaseType::ScalarType ScalarType;

  template <class M, class EntityType>
  LocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, VectorType& vector)
    : BaseType(mapper, entity, vector)
    , vector_(vector)
  {
  }

  ~LocalDoFVector()
  {
  }

  void set(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.set_entry(indices_[ii], val);
  }

  void add(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.add_to_entry(indices_[ii], val);
  }

private:
  using BaseType::indices_;
  VectorType& vector_;
}; // class LocalDoFVector

template <class SpaceImp, class VectorImp>
class ConstLocalDiscreteFunction
    : public Stuff::LocalfunctionInterface<typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType,
                                           SpaceImp::dimDomain, typename SpaceImp::RangeFieldType, SpaceImp::dimRange,
                                           SpaceImp::dimRangeCols>
{
  static_assert(std::is_base_of<SpaceInterface<typename SpaceImp::Traits>, SpaceImp>::value,
                "SpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>, VectorImp>::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");
  static_assert(std::is_same<typename SpaceImp::RangeFieldType, typename VectorImp::ScalarType>::value,
                "Types do not match!");
  typedef Stuff::LocalfunctionInterface<typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType,
                                        SpaceImp::dimDomain, typename SpaceImp::RangeFieldType, SpaceImp::dimRange,
                                        SpaceImp::dimRangeCols> BaseType;
  typedef ConstLocalDiscreteFunction<SpaceImp, VectorImp> ThisType;

public:
  typedef SpaceImp SpaceType;
  typedef VectorImp VectorType;
  typedef typename BaseType::EntityType EntityType;

  typedef typename BaseType::DomainFieldType DomainFieldType;
  static const unsigned int dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainType DomainType;

  typedef typename BaseType::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = BaseType::dimRangeCols;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeType RangeType;

  typedef typename BaseType::JacobianRangeType JacobianRangeType;

private:
  typedef typename SpaceType::BaseFunctionSetType BaseFunctionSetType;

public:
  typedef ConstLocalDoFVector<VectorType> ConstLocalDoFVectorType;

  ConstLocalDiscreteFunction(const SpaceType& space, const VectorType& globalVector, const EntityType& ent)
    : BaseType(ent)
    , space_(space)
    , base_(new BaseFunctionSetType(space_.base_function_set(this->entity())))
    , localVector_(new ConstLocalDoFVectorType(space_.mapper(), this->entity(), globalVector))
    , tmpBaseValues_(base_->size(), RangeType(0))
    , tmpBaseJacobianValues_(base_->size(), JacobianRangeType(0))
  {
    assert(localVector_->size() == base_->size());
  }

  ConstLocalDiscreteFunction(ThisType&& source)
    : BaseType(source.entity())
    , space_(source.space_)
    , base_(std::move(source.base_))
    , localVector_(std::move(source.localVector_))
    , tmpBaseValues_(std::move(source.tmpBaseValues_))
    , tmpBaseJacobianValues_(std::move(source.tmpBaseJacobianValues_))
  {
  }

  ConstLocalDiscreteFunction(const ThisType& other) = delete;

  ThisType& operator=(const ThisType& other) = delete;

  virtual ~ConstLocalDiscreteFunction()
  {
  }

  const BaseFunctionSetType& base() const
  {
    return *base_;
  }

  const ConstLocalDoFVectorType& vector() const
  {
    return *localVector_;
  }

  virtual size_t order() const DS_OVERRIDE
  {
    return base_->order();
  }

  virtual void evaluate(const DomainType& xx, RangeType& ret) const DS_OVERRIDE
  {
    assert(this->is_a_valid_point(xx));
    Dune::Stuff::Common::clear(ret);
    assert(localVector_->size() == tmpBaseValues_.size());
    base_->evaluate(xx, tmpBaseValues_);
    for (size_t ii = 0; ii < localVector_->size(); ++ii) {
      tmpBaseValues_[ii] *= localVector_->get(ii);
      ret += tmpBaseValues_[ii];
    }
  } // ... evaluate(...)

  virtual void jacobian(const DomainType& xx, JacobianRangeType& ret) const DS_OVERRIDE
  {
    assert(this->is_a_valid_point(xx));
    ret *= RangeFieldType(0);
    assert(localVector_->size() == tmpBaseJacobianValues_.size());
    base_->jacobian(xx, tmpBaseJacobianValues_);
    for (size_t ii = 0; ii < localVector_->size(); ++ii) {
      tmpBaseJacobianValues_[ii] *= localVector_->get(ii);
      ret += tmpBaseJacobianValues_[ii];
    }
  } // ... jacobian(...)

  using BaseType::evaluate;
  using BaseType::jacobian;

protected:
  const SpaceType& space_;
  std::unique_ptr<const BaseFunctionSetType> base_;
  std::unique_ptr<const ConstLocalDoFVectorType> localVector_;

private:
  mutable std::vector<RangeType> tmpBaseValues_;
  mutable std::vector<JacobianRangeType> tmpBaseJacobianValues_;
}; // class ConstLocalDiscreteFunction

template <class SpaceImp, class VectorImp>
class LocalDiscreteFunction : public ConstLocalDiscreteFunction<SpaceImp, VectorImp>
{
  typedef ConstLocalDiscreteFunction<SpaceImp, VectorImp> BaseType;
  typedef LocalDiscreteFunction<SpaceImp, VectorImp> ThisType;

public:
  typedef typename BaseType::SpaceType SpaceType;
  typedef typename BaseType::VectorType VectorType;
  typedef typename BaseType::EntityType EntityType;

  typedef typename BaseType::DomainFieldType DomainFieldType;
  static const unsigned int dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainType DomainType;

  typedef typename BaseType::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = BaseType::dimRangeCols;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeType RangeType;

  typedef typename BaseType::JacobianRangeType JacobianRangeType;

private:
  typedef typename SpaceType::BaseFunctionSetType BaseFunctionSetType;

public:
  typedef LocalDoFVector<VectorType> LocalDoFVectorType;

  LocalDiscreteFunction(const SpaceType& space, VectorType& globalVector, const EntityType& ent)
    : BaseType(space, globalVector, ent)
    , localVector_(new LocalDoFVectorType(space_.mapper(), entity_, globalVector))
  {
    assert(localVector_->size() == base_->size());
  }

  LocalDiscreteFunction(ThisType&& source)
    : BaseType(std::move(source)) // <- because of this
    , localVector_(std::move(source.localVector_)) // <- I am not sure if this is valid -+^
  {
  }

  LocalDiscreteFunction(const ThisType& other) = delete;

  ThisType& operator=(const ThisType& other) = delete;

  virtual ~LocalDiscreteFunction()
  {
  }

  LocalDoFVectorType& vector()
  {
    return *localVector_;
  }

private:
  using BaseType::space_;
  using BaseType::entity_;
  using BaseType::base_;
  std::unique_ptr<LocalDoFVectorType> localVector_;
}; // class LocalDiscreteFunction

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_LOCAL_HH
<|endoftext|>


<commit_before>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_OPERATORS_INTERFACES_HH
#define DUNE_PYMOR_OPERATORS_INTERFACES_HH

#include <dune/pymor/common/exceptions.hh>
#include <dune/pymor/parameters/base.hh>
#include <dune/pymor/la/container/interfaces.hh>
#include <dune/pymor/la/container.hh>

namespace Dune {
namespace Pymor {

class OperatorInterface
  : public Parametric
{
public:
  template< class... Args >
  OperatorInterface(Args&& ...args)
    : Parametric(std::forward< Args >(args)...)
  {}

  virtual ~OperatorInterface() {}

  virtual bool linear() const = 0;

  virtual unsigned int dim_source() const = 0;

  virtual unsigned int dim_range() const = 0;

  virtual std::string type_source() const = 0;

  virtual std::string type_range() const = 0;

  virtual void apply(const LA::VectorInterface* /*source*/,
                     LA::VectorInterface* /*range*/,
                     const Parameter /*mu*/ = Parameter()) const
    throw (Exception::types_are_not_compatible,
           Exception::you_have_to_implement_this,
           Exception::sizes_do_not_match,
           Exception::wrong_parameter_type,
           Exception::requirements_not_met) = 0;

  virtual LA::VectorInterface* apply(const LA::VectorInterface* source, const Parameter mu = Parameter()) const
    throw (Exception::types_are_not_compatible,
           Exception::you_have_to_implement_this,
           Exception::sizes_do_not_match,
           Exception::wrong_parameter_type)
  {
    DUNE_PYMOR_THROW(Exception::types_are_not_compatible,
                     "source (" << source->type() << ") is not a compatible type_source (" << type_source() << ")!");
    LA::VectorInterface* ret = LA::createVector(type_range(), dim_range());
    apply(source, ret, mu);
    return ret;
  }

  virtual double apply2(const LA::VectorInterface* range,
                        const LA::VectorInterface* source,
                        const Parameter mu = Parameter()) const
    throw (Exception::types_are_not_compatible,
           Exception::sizes_do_not_match,
           Exception::wrong_parameter_type)
  {
    std::stringstream msg;
    size_t throw_up = 0;
    if (source->type() != type_source()) {
      msg << "source (" << source->type() << ") is not a compatible type_source (" << type_source() << ")";
      ++throw_up;
    }
    if (range->type() != type_range()) {
      if (throw_up)
        msg << " and ";
      msg << "range (" << range->type() << ") is not a compatible type_range (" << type_range() << ")";
    }
    if (throw_up) DUNE_PYMOR_THROW(Exception::types_are_not_compatible, msg.str() << "!");
    LA::VectorInterface* tmp = apply(source, mu);
    return range->dot(tmp);
  }

  virtual OperatorInterface* freeze_parameter(const Parameter /*mu*/ = Parameter()) const
    throw (Exception::this_is_not_parametric) = 0;
}; // class OperatorInterface

} // namespace Pymor
} // namespace Dune

#endif // DUNE_PYMOR_OPERATORS_INTERFACES_HH
<commit_msg>[operators.interface]<commit_after>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_OPERATORS_INTERFACES_HH
#define DUNE_PYMOR_OPERATORS_INTERFACES_HH

#include <dune/pymor/common/exceptions.hh>
#include <dune/pymor/parameters/base.hh>
#include <dune/pymor/la/container/interfaces.hh>
#include <dune/pymor/la/container.hh>

namespace Dune {
namespace Pymor {

class OperatorInterface
  : public Parametric
{
public:
  template< class... Args >
  OperatorInterface(Args&& ...args)
    : Parametric(std::forward< Args >(args)...)
  {}

  virtual ~OperatorInterface() {}

  virtual bool linear() const = 0;

  virtual unsigned int dim_source() const = 0;

  virtual unsigned int dim_range() const = 0;

  virtual std::string type_source() const = 0;

  virtual std::string type_range() const = 0;

  virtual void apply(const LA::VectorInterface* /*source*/,
                     LA::VectorInterface* /*range*/,
                     const Parameter /*mu*/ = Parameter()) const throw (Exception::types_are_not_compatible,
                                                                        Exception::you_have_to_implement_this,
                                                                        Exception::sizes_do_not_match,
                                                                        Exception::wrong_parameter_type,
                                                                        Exception::requirements_not_met) = 0;

  virtual LA::VectorInterface* apply(const LA::VectorInterface* source, const Parameter mu = Parameter()) const
    throw (Exception::types_are_not_compatible,
           Exception::you_have_to_implement_this,
           Exception::sizes_do_not_match,
           Exception::wrong_parameter_type)
  {
    DUNE_PYMOR_THROW(Exception::types_are_not_compatible,
                     "source (" << source->type() << ") is not a compatible type_source (" << type_source() << ")!");
    LA::VectorInterface* ret = LA::createVector(type_range(), dim_range());
    apply(source, ret, mu);
    return ret;
  }

  virtual double apply2(const LA::VectorInterface* range,
                        const LA::VectorInterface* source,
                        const Parameter mu = Parameter()) const throw (Exception::types_are_not_compatible,
                                                                       Exception::sizes_do_not_match,
                                                                       Exception::wrong_parameter_type)
  {
    std::stringstream msg;
    size_t throw_up = 0;
    if (source->type() != type_source()) {
      msg << "source (" << source->type() << ") is not a compatible type_source (" << type_source() << ")";
      ++throw_up;
    }
    if (range->type() != type_range()) {
      if (throw_up)
        msg << " and ";
      msg << "range (" << range->type() << ") is not a compatible type_range (" << type_range() << ")";
    }
    if (throw_up) DUNE_PYMOR_THROW(Exception::types_are_not_compatible, msg.str() << "!");
    if (source->dim() != dim_source())
      DUNE_PYMOR_THROW(Exception::sizes_do_not_match,
                       "dim of source (" << source->dim() << ") does not match dim_source of this (" << dim_source()
                       << ")!");
    if (range->dim() != dim_range())
      DUNE_PYMOR_THROW(Exception::sizes_do_not_match,
                       "dim of range (" << range->dim() << ") does not match dim_range of this (" << dim_range()
                       << ")!");
    LA::VectorInterface* tmp = apply(source, mu);
    return range->dot(tmp);
  }

  virtual OperatorInterface* freeze_parameter(const Parameter /*mu*/ = Parameter()) const
    throw (Exception::this_is_not_parametric, Exception::you_have_to_implement_this)
  {
    DUNE_PYMOR_THROW(Exception::you_have_to_implement_this, "you really do!");
  }
}; // class OperatorInterface

} // namespace Pymor
} // namespace Dune

#endif // DUNE_PYMOR_OPERATORS_INTERFACES_HH
<|endoftext|>


<commit_before>#include "docking.h"
#include "../../console/console_log.h"
#include "../../system/editor_window.h"
#include "assets_dock.h"
#include "console_dock.h"
#include "core/logging/logging.h"
#include "game_dock.h"
#include "hierarchy_dock.h"
#include "inspector_dock.h"
#include "runtime/system/engine.h"
#include "scene_dock.h"
#include "style_dock.h"

bool docking_system::initialize()
{
	auto log = std::make_shared<console_log>();
	_docks.emplace_back(std::make_unique<scene_dock>("SCENE", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<game_dock>("GAME", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<hierarchy_dock>("HIERARCHY", true, ImVec2(300.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<inspector_dock>("INSPECTOR", true, ImVec2(300.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<assets_dock>("ASSETS", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<console_dock>("CONSOLE", true, ImVec2(200.0f, 200.0f), log));
	_docks.emplace_back(std::make_unique<style_dock>("STYLE", true, ImVec2(300.0f, 200.0f)));

	auto& scene = _docks[0];
	auto& game = _docks[1];
	auto& hierarchy = _docks[2];
	auto& inspector = _docks[3];
	auto& assets = _docks[4];
	auto& console = _docks[5];
	auto& style = _docks[6];

	auto& engine = core::get_subsystem<runtime::engine>();
	const auto& windows = engine.get_windows();
	auto& window = static_cast<main_editor_window&>(*windows[0]);
	auto& dockspace = window.get_dockspace();
	dockspace.dock_to(scene.get(), imguidock::slot::none, 200, true);
	dockspace.dock_with(game.get(), scene.get(), imguidock::slot::tab, 300, false);
	dockspace.dock_with(inspector.get(), scene.get(), imguidock::slot::right, 400, true);
	dockspace.dock_with(hierarchy.get(), scene.get(), imguidock::slot::left, 300, true);
	dockspace.dock_to(console.get(), imguidock::slot::bottom, 300, true);
	dockspace.dock_with(assets.get(), console.get(), imguidock::slot::tab, 250, true);
	dockspace.dock_with(style.get(), assets.get(), imguidock::slot::right, 400, true);

	auto logging_container = logging::get_mutable_logging_container();
	logging_container->add_sink(log);
	window.set_log("Console", log);
	std::function<void()> log_version = []() { APPLOG_INFO("Version 1.0"); };
	log->register_command("version", "Returns the current version of the Editor.", {}, {}, log_version);

	return true;
}

void docking_system::dispose()
{
	_docks.clear();
}
<commit_msg>cleanup.<commit_after>#include "docking.h"
#include "../../console/console_log.h"
#include "../../system/editor_window.h"
#include "assets_dock.h"
#include "console_dock.h"
#include "core/logging/logging.h"
#include "game_dock.h"
#include "hierarchy_dock.h"
#include "inspector_dock.h"
#include "runtime/system/engine.h"
#include "scene_dock.h"
#include "style_dock.h"

bool docking_system::initialize()
{
	auto log = std::make_shared<console_log>();
	_docks.emplace_back(std::make_unique<scene_dock>("SCENE", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<game_dock>("GAME", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<hierarchy_dock>("HIERARCHY", true, ImVec2(300.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<inspector_dock>("INSPECTOR", true, ImVec2(300.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<assets_dock>("ASSETS", true, ImVec2(200.0f, 200.0f)));
	_docks.emplace_back(std::make_unique<console_dock>("CONSOLE", true, ImVec2(200.0f, 200.0f), log));
	_docks.emplace_back(std::make_unique<style_dock>("STYLE", true, ImVec2(300.0f, 200.0f)));

	auto& scene = _docks[0];
	auto& game = _docks[1];
	auto& hierarchy = _docks[2];
	auto& inspector = _docks[3];
	auto& assets = _docks[4];
	auto& console = _docks[5];
	auto& style = _docks[6];

	auto& engine = core::get_subsystem<runtime::engine>();
	const auto& windows = engine.get_windows();
	auto& window = static_cast<main_editor_window&>(*windows[0]);
	auto& dockspace = window.get_dockspace();
	dockspace.dock_to(scene.get(), imguidock::slot::none, 200, true);
	dockspace.dock_with(game.get(), scene.get(), imguidock::slot::tab, 300, false);
	dockspace.dock_with(inspector.get(), scene.get(), imguidock::slot::right, 400, true);
	dockspace.dock_with(hierarchy.get(), scene.get(), imguidock::slot::left, 300, true);
	dockspace.dock_to(console.get(), imguidock::slot::bottom, 300, true);
	dockspace.dock_with(assets.get(), console.get(), imguidock::slot::tab, 250, true);
	dockspace.dock_with(style.get(), assets.get(), imguidock::slot::right, 400, true);

	auto logging_container = logging::get_mutable_logging_container();
	logging_container->add_sink(log);
	window.set_log("CONSOLE", log);
	std::function<void()> log_version = []() { APPLOG_INFO("Version 1.0"); };
	log->register_command("version", "Returns the current version of the Editor.", {}, {}, log_version);

	return true;
}

void docking_system::dispose()
{
	_docks.clear();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <set>
#include <iostream>
#include <fstream>

#include "syscall_desc.h"
#include "tagmap.h"
#include "pin.H"
#include "osutils.H"

#include "hooks/hooks.H"
#include "dtracker.H"

// #define DTRACKER_DEBUG
#include "dtracker_debug.H"

/* Syscall descriptors, defined in libdft. */
extern syscall_desc_t syscall_desc[SYSCALL_MAX];

/* Array that maps fds to ufds.
 * File descriptors are recycled by the OS, so they are not suitable
 * to be used as taint marks. OTH, ufds monotonically increase, so
 * they are unique through the program execution. We use UINT32 for
 * them, which should be sufficient.
 */
ufdmap_t ufdmap;

/* Set of watched fds - maybe change this to bitset? */
std::set<int> fdset;

/* Counters for stdin/stdout/stderr.
 * TODO: Maybe this should be generalized. I.e. maintain counters for
 * all fds where isatty(fd) returns true.
 */
off_t stdcount[STDFD_MAX];

/* Raw provenance output stream. */
std::ofstream rawProvStream;

/* Current executable name.
 * TODO: Check if this works correctly while following execv().
 */
std::string exename("N/A");

/* Pin knob for setting the raw prov output file */
static KNOB<string> ProvRawKnob(KNOB_MODE_WRITEONCE, "pintool", "o",
	"rawprov.out", "The output file for raw prov data"
);

/* Pin knobs for tracking stdin/stdout/stderr */
static KNOB<string> TrackStdin(KNOB_MODE_WRITEONCE, "pintool", "stdin",
	"0", "Taint data originating from stdin."
);
static KNOB<string> TrackStdout(KNOB_MODE_WRITEONCE, "pintool", "stdout",
	"1", "Log the taint tag data for stdout."
);
static KNOB<string> TrackStderr(KNOB_MODE_WRITEONCE, "pintool", "stderr",
	"0", "Log the taint tag data for stderr."
);

/*
 * Called when a new image is loaded.
 * Currently only acts when the main executable is loaded to set exename global.
 */
static void ImageLoad(IMG img, VOID * v) {
	// TODO: check if this works correctly when execv() is used.
    if (IMG_IsMainExecutable(img)) {
		exename = path_resolve(IMG_Name(img).c_str());
		PROVLOG_EXEC(exename);

		// Add stdin/stdout/stderr to watched file descriptors.
		// This should take place while loading the image in order to have
		// exename available.
		if ( atoi(TrackStdin.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDIN_FILENO);
			std::string fdn = fdname(STDIN_FILENO);
			fdset.insert(STDIN_FILENO);
			LOG( "Watching fd" + decstr(STDIN_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDIN_FILENO, F_GETFL), 0);
		}
		if ( atoi(TrackStdout.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDOUT_FILENO);
			std::string fdn = fdname(STDOUT_FILENO);
			fdset.insert(STDOUT_FILENO);
			LOG( "Watching fd" + decstr(STDOUT_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDOUT_FILENO, F_GETFL), 0);
		}
		if ( atoi(TrackStderr.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDERR_FILENO);
			std::string fdn = fdname(STDERR_FILENO);
			fdset.insert(STDERR_FILENO);
			LOG( "Watching fd" + decstr(STDERR_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDERR_FILENO, F_GETFL), 0);
		}
	}
}

/*
 * Called before exit.
 * Handles any fd's that haven't been closed.
 */
static void OnExit(INT32, void *) {
	/* Generate close log entries for remaining ufds.
	 * Don't you love the c++11 loop syntax?
	 */
	for ( auto &fd : fdset ) {
		ufd_t ufd = ufdmap.get(fd);
		ufdmap.del(fd);
		PROVLOG_CLOSE(ufd);
	}
}

/*
 * Tool used for verifying that libdft propagates taint correctly.
 */
int main(int argc, char **argv) {
	/* initialize symbol processing */
	PIN_InitSymbols();

	if (unlikely(PIN_Init(argc, argv)))
		goto err;

	IMG_AddInstrumentFunction(ImageLoad, 0);
	PIN_AddFiniFunction(OnExit, 0);

#ifdef DTRACKER_DEBUG
	INS_AddInstrumentFunction(CheckMagicValue, 0);
#endif

	LOG("Initializing libdft.\n");
	if (unlikely(libdft_init() != 0))
		goto err;

	// reset counters
	bzero(stdcount, sizeof(stdcount));

	// Open raw prov file.
	// This file is to be post-processed to get the data in a proper format.
    rawProvStream.open(ProvRawKnob.Value().c_str());

	/*
	 * Install taint sources and sinks.
	 * syscall_set_{pre, post}() set the callbacks in the libdft
	 * syscall description struct.
	 * These callbacks are respectively invoked through
	 * sysenter_save() and sysexit_save() function of libdft.
	 * In turn, these libdft functions are hooked to run before/after
	 * every syscall using PIN_AddSyscall{Entry, Exit}Function().
	 */

	/* dtracker_openclose.cpp: open(2), creat(2), close(2) */
	(void)syscall_set_pre(&syscall_desc[__NR_open], pre_open_hook);
	(void)syscall_set_pre(&syscall_desc[__NR_creat], pre_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_open], post_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_creat], post_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_close], post_close_hook);

	/* dtracker_read.cpp: read(2), readv(2) */
	(void)syscall_set_post(&syscall_desc[__NR_read], post_read_hook);
	(void)syscall_set_post(&syscall_desc[__NR_readv], post_readv_hook);

	/* dtracker_write.cpp: write(2), writev(2) */
	(void)syscall_set_post(&syscall_desc[__NR_write], post_write_hook);
	(void)syscall_set_post(&syscall_desc[__NR_writev], post_writev_hook);

	/* dtracker_mmap.cpp: mmap2(2), munmap(2) */
	(void)syscall_set_post(&syscall_desc[__NR_mmap2], post_mmap2_hook);
	(void)syscall_set_post(&syscall_desc[__NR_munmap], post_munmap_hook);

	/* start the program and return something to make the compiler happy */
	LOG("Starting program.\n");
	PIN_StartProgram();
	return EXIT_SUCCESS;

err:
	/* error handling */

	/* detach from the process */
	libdft_die();

	/* return */
	return EXIT_FAILURE;
}

<commit_msg>indenting fix<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <set>
#include <iostream>
#include <fstream>

#include "syscall_desc.h"
#include "tagmap.h"
#include "pin.H"
#include "osutils.H"

#include "hooks/hooks.H"
#include "dtracker.H"

// #define DTRACKER_DEBUG
#include "dtracker_debug.H"

/* Syscall descriptors, defined in libdft. */
extern syscall_desc_t syscall_desc[SYSCALL_MAX];

/* Array that maps fds to ufds.
 * File descriptors are recycled by the OS, so they are not suitable
 * to be used as taint marks. OTH, ufds monotonically increase, so
 * they are unique through the program execution. We use UINT32 for
 * them, which should be sufficient.
 */
ufdmap_t ufdmap;

/* Set of watched fds - maybe change this to bitset? */
std::set<int> fdset;

/* Counters for stdin/stdout/stderr.
 * TODO: Maybe this should be generalized. I.e. maintain counters for
 * all fds where isatty(fd) returns true.
 */
off_t stdcount[STDFD_MAX];

/* Raw provenance output stream. */
std::ofstream rawProvStream;

/* Current executable name.
 * TODO: Check if this works correctly while following execv().
 */
std::string exename("N/A");

/* Pin knob for setting the raw prov output file */
static KNOB<string> ProvRawKnob(KNOB_MODE_WRITEONCE, "pintool", "o",
	"rawprov.out", "The output file for raw prov data"
);

/* Pin knobs for tracking stdin/stdout/stderr */
static KNOB<string> TrackStdin(KNOB_MODE_WRITEONCE, "pintool", "stdin",
	"0", "Taint data originating from stdin."
);
static KNOB<string> TrackStdout(KNOB_MODE_WRITEONCE, "pintool", "stdout",
	"1", "Log the taint tag data for stdout."
);
static KNOB<string> TrackStderr(KNOB_MODE_WRITEONCE, "pintool", "stderr",
	"0", "Log the taint tag data for stderr."
);

/*
 * Called when a new image is loaded.
 * Currently only acts when the main executable is loaded to set exename global.
 */
static void ImageLoad(IMG img, VOID * v) {
	// TODO: check if this works correctly when execv() is used.
	if (IMG_IsMainExecutable(img)) {
		exename = path_resolve(IMG_Name(img).c_str());
		PROVLOG_EXEC(exename);

		// Add stdin/stdout/stderr to watched file descriptors.
		// This should take place while loading the image in order to have
		// exename available.
		if ( atoi(TrackStdin.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDIN_FILENO);
			std::string fdn = fdname(STDIN_FILENO);
			fdset.insert(STDIN_FILENO);
			LOG( "Watching fd" + decstr(STDIN_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDIN_FILENO, F_GETFL), 0);
		}
		if ( atoi(TrackStdout.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDOUT_FILENO);
			std::string fdn = fdname(STDOUT_FILENO);
			fdset.insert(STDOUT_FILENO);
			LOG( "Watching fd" + decstr(STDOUT_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDOUT_FILENO, F_GETFL), 0);
		}
		if ( atoi(TrackStderr.Value().c_str()) ) {
			ufd_t ufd = ufdmap.get(STDERR_FILENO);
			std::string fdn = fdname(STDERR_FILENO);
			fdset.insert(STDERR_FILENO);
			LOG( "Watching fd" + decstr(STDERR_FILENO) + " (" + fdn + ").\n");
			PROVLOG_OPEN(ufd, fdn, fcntl(STDERR_FILENO, F_GETFL), 0);
		}
	}
}

/*
 * Called before exit.
 * Handles any fd's that haven't been closed.
 */
static void OnExit(INT32, void *) {
	/* Generate close log entries for remaining ufds.
	 * Don't you love the c++11 loop syntax?
	 */
	for ( auto &fd : fdset ) {
		ufd_t ufd = ufdmap.get(fd);
		ufdmap.del(fd);
		PROVLOG_CLOSE(ufd);
	}
}

/*
 * Tool used for verifying that libdft propagates taint correctly.
 */
int main(int argc, char **argv) {
	/* initialize symbol processing */
	PIN_InitSymbols();

	if (unlikely(PIN_Init(argc, argv)))
		goto err;

	IMG_AddInstrumentFunction(ImageLoad, 0);
	PIN_AddFiniFunction(OnExit, 0);

#ifdef DTRACKER_DEBUG
	INS_AddInstrumentFunction(CheckMagicValue, 0);
#endif

	LOG("Initializing libdft.\n");
	if (unlikely(libdft_init() != 0))
		goto err;

	// reset counters
	bzero(stdcount, sizeof(stdcount));

	// Open raw prov file.
	// This file is to be post-processed to get the data in a proper format.
	rawProvStream.open(ProvRawKnob.Value().c_str());

	/*
	 * Install taint sources and sinks.
	 * syscall_set_{pre, post}() set the callbacks in the libdft
	 * syscall description struct.
	 * These callbacks are respectively invoked through
	 * sysenter_save() and sysexit_save() function of libdft.
	 * In turn, these libdft functions are hooked to run before/after
	 * every syscall using PIN_AddSyscall{Entry, Exit}Function().
	 */

	/* dtracker_openclose.cpp: open(2), creat(2), close(2) */
	(void)syscall_set_pre(&syscall_desc[__NR_open], pre_open_hook);
	(void)syscall_set_pre(&syscall_desc[__NR_creat], pre_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_open], post_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_creat], post_open_hook);
	(void)syscall_set_post(&syscall_desc[__NR_close], post_close_hook);

	/* dtracker_read.cpp: read(2), readv(2) */
	(void)syscall_set_post(&syscall_desc[__NR_read], post_read_hook);
	(void)syscall_set_post(&syscall_desc[__NR_readv], post_readv_hook);

	/* dtracker_write.cpp: write(2), writev(2) */
	(void)syscall_set_post(&syscall_desc[__NR_write], post_write_hook);
	(void)syscall_set_post(&syscall_desc[__NR_writev], post_writev_hook);

	/* dtracker_mmap.cpp: mmap2(2), munmap(2) */
	(void)syscall_set_post(&syscall_desc[__NR_mmap2], post_mmap2_hook);
	(void)syscall_set_post(&syscall_desc[__NR_munmap], post_munmap_hook);

	/* start the program and return something to make the compiler happy */
	LOG("Starting program.\n");
	PIN_StartProgram();
	return EXIT_SUCCESS;

err:
	/* error handling */

	/* detach from the process */
	libdft_die();

	/* return */
	return EXIT_FAILURE;
}

<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "ResourceLoader.h"
#include "ResourceRegistry.h"
#include "Log.h"

namespace crown
{

//-----------------------------------------------------------------------------
ResourceLoader::ResourceLoader(Bundle& bundle, Allocator& resource_heap) :
	Thread("resource-loader"),
	m_bundle(bundle),
	m_resource_heap(resource_heap),
	m_load_queue(default_allocator()),
	m_done_queue(default_allocator())
{
}

//-----------------------------------------------------------------------------
void ResourceLoader::load(ResourceId resource)
{
	m_load_mutex.lock();
	m_load_queue.push_back(resource);
	Log::i("Signaling...");
	m_load_requests.signal();
	m_load_mutex.unlock();
}

//-----------------------------------------------------------------------------
uint32_t ResourceLoader::remaining() const
{
	return m_load_queue.size();
}

//-----------------------------------------------------------------------------
uint32_t ResourceLoader::num_loaded() const
{
	return m_done_queue.size();
}

//-----------------------------------------------------------------------------
void ResourceLoader::get_loaded(List<LoadedResource>& l)
{
	m_done_mutex.lock();
	for (uint32_t i = 0; i < m_done_queue.size(); i++)
	{
		l.push_back(m_done_queue[i]);
	}

	m_done_queue.clear();
	m_done_mutex.unlock();
}

//-----------------------------------------------------------------------------
int32_t ResourceLoader::run()
{
	while (!is_terminating())
	{
		m_load_mutex.lock();
		while (m_load_queue.size() == 0)
		{
			Log::i("Waiting...");
			m_load_requests.wait(m_load_mutex);
		}
		Log::i("Loading...");
		ResourceId resource = m_load_queue.front();
		m_load_queue.pop_front();
		m_load_mutex.unlock();

		void* data = resource_on_load(resource.type, m_resource_heap, m_bundle, resource);

		m_done_mutex.lock();
		m_done_queue.push_back(LoadedResource(resource, data));
		m_done_mutex.unlock();
	}

	return 0;
}

} // namespace crown
<commit_msg>Add logs everywhere<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "ResourceLoader.h"
#include "ResourceRegistry.h"
#include "Log.h"

namespace crown
{

//-----------------------------------------------------------------------------
ResourceLoader::ResourceLoader(Bundle& bundle, Allocator& resource_heap) :
	Thread("resource-loader"),
	m_bundle(bundle),
	m_resource_heap(resource_heap),
	m_load_queue(default_allocator()),
	m_done_queue(default_allocator())
{
}

//-----------------------------------------------------------------------------
void ResourceLoader::load(ResourceId resource)
{
	m_load_mutex.lock();
	Log::i("load: lock");
	m_load_queue.push_back(resource);
	Log::i("Signaling...");
	m_load_requests.signal();
	Log::i("load: unlock");
	m_load_mutex.unlock();
}

//-----------------------------------------------------------------------------
uint32_t ResourceLoader::remaining() const
{
	Log::i("remaining()");
	return m_load_queue.size();
}

//-----------------------------------------------------------------------------
uint32_t ResourceLoader::num_loaded() const
{
	Log::i("num_loaded");
	return m_done_queue.size();
}

//-----------------------------------------------------------------------------
void ResourceLoader::get_loaded(List<LoadedResource>& l)
{
	m_done_mutex.lock();
	Log::i("get_loaded: lock");
	for (uint32_t i = 0; i < m_done_queue.size(); i++)
	{
		l.push_back(m_done_queue[i]);
	}

	m_done_queue.clear();
	Log::i("get_loaded: unlock");
	m_done_mutex.unlock();
}

//-----------------------------------------------------------------------------
int32_t ResourceLoader::run()
{
	while (!is_terminating())
	{
		m_load_mutex.lock();
		while (m_load_queue.size() == 0)
		{
			Log::i("Waiting...");
			m_load_requests.wait(m_load_mutex);
		}
		Log::i("Loading...");
		ResourceId resource = m_load_queue.front();
		m_load_queue.pop_front();
		m_load_mutex.unlock();

		void* data = resource_on_load(resource.type, m_resource_heap, m_bundle, resource);

		m_done_mutex.lock();
		m_done_queue.push_back(LoadedResource(resource, data));
		m_done_mutex.unlock();
	}

	return 0;
}

} // namespace crown
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 shawnw

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef USEFUL_MUTEX_HPP
#define USEFUL_MUTEX_HPP

#include <atomic>
#include <mutex>
#include <condition_variable>
#include <stdexcept>

namespace useful {

  /* Basic thread barrier. Initialize with a number N, and threads that wait on the barrier
   * will block until N threads are waiting. Useful for environments without the concurrency TS. */
  class barrier {
  private:
    int count;
    std::mutex m;
    std::condition_variable cond;

  public:
    explicit barrier(int c = -1) : count(c), m(), cond() {}

    // Returns false if the barrier has already been passed by other threads.
    bool at() {
      std::unique_lock<std::mutex> guard(m);

      if (count > 0) {
        count -= 1;
        if (count == 0) {
          cond.notify_all();
        } else {
          cond.wait(guard, [this]{ return count <= 0; });
          count = -1;
        }
        return true;
      } else {
        return false;
      }
    }

    // Set the number of threads the barrier should wait for. Can't be used on a barrier
    // currently being waited for.
    void waitfor(int c) {
      std::lock_guard<std::mutex> guard(m);
      if (count > 0)
        throw std::logic_error("Attempt to reset a currently active barrier.");
      count = c;
    }
  };

  /* Spin lock using std::atomic_flag, usable with std::lock_guard etc. */
  class spin_lock {
  private:
    std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
  public:
    void lock() {
      while (lock_.test_and_set(std::memory_order_acquire))
        ;
    }
    bool try_lock() {
      return !lock_.test_and_set(std::memory_order_acquire);
    }
    void unlock() {
      lock_.clear(std::memory_order_release);
    }
  };

  /* Ticket lock, see https://en.wikipedia.org/wiki/Ticket_lock */
  class ticket_lock {
  private:
    using itype = unsigned int;
    std::atomic<itype> current_ticket{0};
    std::atomic<itype> next_ticket{0};
  public:
    void lock() {
      itype this_ticket = next_ticket.fetch_add(1, std::memory_order_relaxed);
      while (current_ticket.load(std::memory_order_acquire) != this_ticket)
        ;
    }
    void unlock() {
      current_ticket.fetch_add(1, std::memory_order_release);
    }
  };
};

#endif
<commit_msg>Ensure that spin and ticket lock objects are non-copyable.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016 shawnw

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef USEFUL_MUTEX_HPP
#define USEFUL_MUTEX_HPP

#include <atomic>
#include <mutex>
#include <condition_variable>
#include <stdexcept>

namespace useful {

  /* Basic thread barrier. Initialize with a number N, and threads that wait on the barrier
   * will block until N threads are waiting. Useful for environments without the concurrency TS. */
  class barrier {
  private:
    int count;
    std::mutex m;
    std::condition_variable cond;

  public:
    explicit barrier(int c = -1) : count(c), m(), cond() {}
    barrier(const barrier &) = delete;
    barrier(const barrier &&) = delete;
    barrier& operator=(const barrier &) = delete;
    barrier& operator=(const barrier &&) = delete;

    // Returns false if the barrier has already been passed by other threads.
    bool at() {
      std::unique_lock<std::mutex> guard(m);

      if (count > 0) {
        count -= 1;
        if (count == 0) {
          cond.notify_all();
        } else {
          cond.wait(guard, [this]{ return count <= 0; });
          count = -1;
        }
        return true;
      } else {
        return false;
      }
    }

    // Set the number of threads the barrier should wait for. Can't be used on a barrier
    // currently being waited for.
    void waitfor(int c) {
      std::lock_guard<std::mutex> guard(m);
      if (count > 0)
        throw std::logic_error("Attempt to reset a currently active barrier.");
      count = c;
    }
  };

  /* Spin lock using std::atomic_flag, usable with std::lock_guard
     etc. Satisfies Mutex concept */
  class spin_lock {
  private:
    std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
  public:
    spin_lock(const spin_lock &) = delete;
    spin_lock(const spin_lock &&) = delete;
    spin_lock& operator=(const spin_lock &) = delete;
    spin_lock& operator=(const spin_lock &&) = delete;

    void lock() {
      while (lock_.test_and_set(std::memory_order_acquire))
        ;
    }
    bool try_lock() {
      return !lock_.test_and_set(std::memory_order_acquire);
    }
    void unlock() {
      lock_.clear(std::memory_order_release);
    }
  };

  /* Ticket lock, see https://en.wikipedia.org/wiki/Ticket_lock
     Satisfies BasicLockable concept. */
  class ticket_lock {
  private:
    using itype = unsigned int;
    std::atomic<itype> current_ticket{0};
    std::atomic<itype> next_ticket{0};
  public:
    ticket_lock(const ticket_lock &) = delete;
    ticket_lock(const ticket_lock &&) = delete;
    ticket_lock& operator=(const ticket_lock &) = delete;
    ticket_lock& operator=(const ticket_lock &&) = delete;

    void lock() {
      itype this_ticket = next_ticket.fetch_add(1, std::memory_order_relaxed);
      while (current_ticket.load(std::memory_order_acquire) != this_ticket)
        ;
    }
    void unlock() {
      current_ticket.fetch_add(1, std::memory_order_release);
    }
  };
};

#endif
<|endoftext|>


<commit_before>#include "ugc/storage.hpp"
#include "ugc/serdes.hpp"
#include "ugc/serdes_json.hpp"

#include "indexer/classificator.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/feature_decl.hpp"
#include "indexer/ftraits.hpp"
#include "indexer/index.hpp"

#include "platform/platform.hpp"

#include "coding/file_name_utils.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/internal/file_data.hpp"

#include <algorithm>
#include <utility>

#include "3party/jansson/myjansson.hpp"

namespace ugc
{
using namespace std;

namespace
{
string const kIndexFileName = "index.json";
string const kUGCUpdateFileName = "ugc.update.bin";
string const kTmpFileExtension = ".tmp";

using Sink = MemWriter<string>;

string GetUGCFilePath() { return my::JoinPath(GetPlatform().SettingsDir(), kUGCUpdateFileName); }

string GetIndexFilePath() { return my::JoinPath(GetPlatform().SettingsDir(), kIndexFileName); }

bool GetUGCFileSize(uint64_t & size)
{
  try
  {
    FileReader reader(GetUGCFilePath(), true /* with exceptions */);
    size = reader.Size();
  }
  catch (RootException const &)
  {
    return false;
  }

  return true;
}

void DeserializeUGCIndex(string const & jsonData, vector<Storage::UGCIndex> & res)
{
  if (jsonData.empty())
    return;

  DeserializerJsonV0 des(jsonData);
  des(res);
}

string SerializeUGCIndex(vector<Storage::UGCIndex> const & indexes)
{
  if (indexes.empty())
    return string();

  auto array = my::NewJSONArray();
  for (auto const & index : indexes)
  {
    string data;
    {
      Sink sink(data);
      SerializerJson<Sink> ser(sink);
      ser(index);
    }

    my::Json node(data);
    json_array_append_new(array.get(), node.get_deep_copy());
  }

  unique_ptr<char, JSONFreeDeleter> buffer(json_dumps(array.get(), JSON_COMPACT | JSON_ENSURE_ASCII));
  return string(buffer.get());
}

template <typename UGCUpdate>
Storage::SettingResult SetGenericUGCUpdate(
    vector<Storage::UGCIndex> & indexes, size_t & numberOfDeleted, FeatureID const & id,
    UGCUpdate const & ugc,
    FeatureType const & featureType,
    Version const version = Version::Latest)
{
  if (!ugc.IsValid())
    return Storage::SettingResult::InvalidUGC;

  auto const mercator = feature::GetCenter(featureType);
  feature::TypesHolder th(featureType);
  th.SortBySpec();
  auto const optMatchingType = ftraits::UGC::GetType(th);
  CHECK(optMatchingType, ());
  auto const type = th.GetBestType();
  for (auto & index : indexes)
  {
    if (type == index.m_type && mercator == index.m_mercator && !index.m_deleted)
    {
      index.m_deleted = true;
      ++numberOfDeleted;
      break;
    }
  }

  Storage::UGCIndex index;
  uint64_t offset;
  if (!GetUGCFileSize(offset))
    offset = 0;

  index.m_mercator = mercator;
  index.m_type = type;
  index.m_matchingType = *optMatchingType;
  index.m_mwmName = id.GetMwmName();
  index.m_dataVersion = id.GetMwmVersion();
  index.m_featureId = id.m_index;
  index.m_offset = offset;

  auto const ugcFilePath = GetUGCFilePath();
  try
  {
    FileWriter w(ugcFilePath, FileWriter::Op::OP_APPEND);
    Serialize(w, ugc, version);
    indexes.emplace_back(move(index));
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", ugcFilePath, "reason:", exception.what()));
    return Storage::SettingResult::WritingError;
  }

  return Storage::SettingResult::Success;
}
}  // namespace

UGCUpdate Storage::GetUGCUpdate(FeatureID const & id) const
{
  if (m_UGCIndexes.empty())
    return {};

  auto const feature = GetFeature(id);
  auto const mercator = feature::GetCenter(*feature);
  feature::TypesHolder th(*feature);
  th.SortBySpec();
  auto const type = th.GetBestType();

  auto const index = find_if(
      m_UGCIndexes.begin(), m_UGCIndexes.end(), [type, &mercator](UGCIndex const & index) -> bool {
        return type == index.m_type && mercator == index.m_mercator && !index.m_deleted;
      });

  if (index == m_UGCIndexes.end())
    return {};

  auto const offset = index->m_offset;
  auto const size = static_cast<size_t>(UGCSizeAtIndex(distance(m_UGCIndexes.begin(), index)));
  vector<uint8_t> buf;
  buf.resize(size);
  auto const ugcFilePath = GetUGCFilePath();
  try
  {
    FileReader r(ugcFilePath, true /* withExceptions */);
    r.Read(offset, buf.data(), size);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
    return {};
  }

  MemReader r(buf.data(), buf.size());
  NonOwningReaderSource source(r);
  UGCUpdate update;
  Deserialize(source, update);
  return update;
}

Storage::SettingResult Storage::SetUGCUpdate(FeatureID const & id, UGCUpdate const & ugc)
{
  auto const feature = GetFeature(id);
  return SetGenericUGCUpdate(m_UGCIndexes, m_numberOfDeleted, id, ugc,
                             *feature);
}

void Storage::Load()
{
  string data;
  auto const indexFilePath = GetIndexFilePath();
  try
  {
    FileReader r(indexFilePath);
    r.ReadAsString(data);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LWARNING, ("Exception while reading file:", indexFilePath, "reason:", exception.what()));
    return;
  }

  DeserializeUGCIndex(data, m_UGCIndexes);
  for (auto const & i : m_UGCIndexes)
  {
    if (i.m_deleted)
      ++m_numberOfDeleted;
  }
}

void Storage::SaveIndex() const
{
  if (m_UGCIndexes.empty())
    return;

  auto const jsonData = SerializeUGCIndex(m_UGCIndexes);
  auto const indexFilePath = GetIndexFilePath();
  try
  {
    FileWriter w(indexFilePath);
    w.Write(jsonData.c_str(), jsonData.length());
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", indexFilePath, "reason:", exception.what()));
  }
}

void Storage::Defragmentation()
{
  auto const indexesSize = m_UGCIndexes.size();
  if (m_numberOfDeleted < indexesSize / 2)
    return;

  auto const ugcFilePath = GetUGCFilePath();
  auto const tmpUGCFilePath = ugcFilePath + kTmpFileExtension;

  try
  {
    FileReader r(ugcFilePath, true /* withExceptions */);
    FileWriter w(tmpUGCFilePath, FileWriter::Op::OP_APPEND);
    uint64_t actualOffset = 0;
    for (size_t i = 0; i < indexesSize; ++i)
    {
      auto & index = m_UGCIndexes[i];
      if (index.m_deleted)
        continue;

      auto const offset = index.m_offset;
      auto const size = static_cast<size_t>(UGCSizeAtIndex(i));
      vector<uint8_t> buf;
      buf.resize(size);
      r.Read(offset, buf.data(), size);
      w.Write(buf.data(), size);
      index.m_offset = actualOffset;
      actualOffset += size;
    }
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
    return;
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", tmpUGCFilePath, "reason:", exception.what()));
    return;
  }

  m_UGCIndexes.erase(remove_if(m_UGCIndexes.begin(), m_UGCIndexes.end(),
                               [](UGCIndex const & i) -> bool { return i.m_deleted; }), m_UGCIndexes.end());

  CHECK(my::DeleteFileX(ugcFilePath), ());
  CHECK(my::RenameFileX(tmpUGCFilePath, ugcFilePath), ());

  m_numberOfDeleted = 0;
}

string Storage::GetUGCToSend() const
{
  if (m_UGCIndexes.empty())
    return string();

  auto array = my::NewJSONArray();
  auto const indexesSize = m_UGCIndexes.size();
  auto const ugcFilePath = GetUGCFilePath();
  FileReader r(ugcFilePath, true /* withExceptions */);
  vector<uint8_t> buf;
  for (size_t i = 0; i < indexesSize; ++i)
  {
    buf.clear();
    auto const & index = m_UGCIndexes[i];
    if (index.m_synchronized || index.m_deleted)
      continue;

    auto const offset = index.m_offset;
    auto const bufSize = static_cast<size_t>(UGCSizeAtIndex(i));
    buf.resize(bufSize);
    try
    {
      r.Read(offset, buf.data(), bufSize);
    }
    catch (FileReader::Exception const & exception)
    {
      LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
      return string();
    }

    MemReader r(buf.data(), buf.size());
    NonOwningReaderSource source(r);
    UGCUpdate update;
    Deserialize(source, update);

    string data;
    {
      Sink sink(data);
      SerializerJson<Sink> ser(sink);
      ser(update);
    }

    my::Json serializedUgc(data);
    auto embeddedNode = my::NewJSONObject();
    ToJSONObject(*embeddedNode.get(), "data_version", index.m_dataVersion);
    ToJSONObject(*embeddedNode.get(), "mwm_name", index.m_mwmName);
    ToJSONObject(*embeddedNode.get(), "feature_id", index.m_featureId);
    ToJSONObject(*embeddedNode.get(), "feature_type", classif().GetReadableObjectName(index.m_matchingType));
    ToJSONObject(*serializedUgc.get(), "feature", *embeddedNode.release());
    json_array_append_new(array.get(), serializedUgc.get_deep_copy());
  }

  if (json_array_size(array.get()) == 0)
    return string();

  auto reviewsNode = my::NewJSONObject();
  ToJSONObject(*reviewsNode.get(), "reviews", *array.release());

  unique_ptr<char, JSONFreeDeleter> buffer(json_dumps(reviewsNode.get(), JSON_COMPACT | JSON_ENSURE_ASCII));
  return string(buffer.get());
}

size_t Storage::GetNumberOfUnsynchronized() const
{
  size_t numberOfUnsynchronized = 0;
  for (auto const & i : m_UGCIndexes)
  {
    if (!i.m_deleted && !i.m_synchronized)
      ++numberOfUnsynchronized;
  }
  return numberOfUnsynchronized;
}

void Storage::MarkAllAsSynchronized()
{
  if (m_UGCIndexes.empty())
    return;

  size_t numberOfUnsynchronized = 0;
  for (auto & index : m_UGCIndexes)
  {
    if (!index.m_synchronized)
    {
      index.m_synchronized = true;
      numberOfUnsynchronized++;
    }
  }

  if (numberOfUnsynchronized == 0)
    return;

  auto const indexPath = GetIndexFilePath();
  my::DeleteFileX(indexPath);
  SaveIndex();
}

uint64_t Storage::UGCSizeAtIndex(size_t const indexPosition) const
{
  CHECK(!m_UGCIndexes.empty(), ());
  auto const indexesSize = m_UGCIndexes.size();
  CHECK_LESS(indexPosition, indexesSize, ());
  auto const indexOffset = m_UGCIndexes[indexPosition].m_offset;
  uint64_t nextOffset;
  if (indexPosition == indexesSize - 1)
    CHECK(GetUGCFileSize(nextOffset), ());
  else
    nextOffset = m_UGCIndexes[indexPosition + 1].m_offset;

  CHECK_GREATER(nextOffset, indexOffset, ());
  return nextOffset - indexOffset;
}

unique_ptr<FeatureType> Storage::GetFeature(FeatureID const & id) const
{
  CHECK(id.IsValid(), ());
  Index::FeaturesLoaderGuard guard(m_index, id.m_mwmId);
  auto feature = guard.GetOriginalOrEditedFeatureByIndex(id.m_index);
  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);
  if (feature->GetFeatureType() == feature::EGeomType::GEOM_AREA)
    feature->ParseTriangles(FeatureType::BEST_GEOMETRY);
  CHECK(feature, ());
  return feature;
}

// Testing
Storage::SettingResult Storage::SetUGCUpdateForTesting(FeatureID const & id,
                                                       v0::UGCUpdate const & ugc)
{
  auto const feature = GetFeature(id);
  return SetGenericUGCUpdate(m_UGCIndexes, m_numberOfDeleted, id, ugc,
                             *feature, Version::V0);
}
}  // namespace ugc

namespace lightweight
{
size_t GetNumberOfUnsentUGC()
{
  auto const indexFilePath = ugc::GetIndexFilePath();
  if (!Platform::IsFileExistsByFullPath(indexFilePath))
    return 0;

  string data;
  try
  {
    FileReader r(indexFilePath);
    r.ReadAsString(data);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LWARNING, ("Exception while reading file:", indexFilePath, "reason:", exception.what()));
    return 0;
  }

  vector<ugc::Storage::UGCIndex> index;
  ugc::DeserializeUGCIndex(data, index);
  size_t number = 0;
  for (auto const & i : index)
  {
    if (!i.m_deleted && !i.m_synchronized)
      ++number;
  }

  return number;
}
}  // namespace lightweight
<commit_msg>[ugc] Moved index emplacing out of exception handler<commit_after>#include "ugc/storage.hpp"
#include "ugc/serdes.hpp"
#include "ugc/serdes_json.hpp"

#include "indexer/classificator.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/feature_decl.hpp"
#include "indexer/ftraits.hpp"
#include "indexer/index.hpp"

#include "platform/platform.hpp"

#include "coding/file_name_utils.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/internal/file_data.hpp"

#include <algorithm>
#include <utility>

#include "3party/jansson/myjansson.hpp"

namespace ugc
{
using namespace std;

namespace
{
string const kIndexFileName = "index.json";
string const kUGCUpdateFileName = "ugc.update.bin";
string const kTmpFileExtension = ".tmp";

using Sink = MemWriter<string>;

string GetUGCFilePath() { return my::JoinPath(GetPlatform().SettingsDir(), kUGCUpdateFileName); }

string GetIndexFilePath() { return my::JoinPath(GetPlatform().SettingsDir(), kIndexFileName); }

bool GetUGCFileSize(uint64_t & size)
{
  try
  {
    FileReader reader(GetUGCFilePath(), true /* with exceptions */);
    size = reader.Size();
  }
  catch (RootException const &)
  {
    return false;
  }

  return true;
}

void DeserializeUGCIndex(string const & jsonData, vector<Storage::UGCIndex> & res)
{
  if (jsonData.empty())
    return;

  DeserializerJsonV0 des(jsonData);
  des(res);
}

string SerializeUGCIndex(vector<Storage::UGCIndex> const & indexes)
{
  if (indexes.empty())
    return string();

  auto array = my::NewJSONArray();
  for (auto const & index : indexes)
  {
    string data;
    {
      Sink sink(data);
      SerializerJson<Sink> ser(sink);
      ser(index);
    }

    my::Json node(data);
    json_array_append_new(array.get(), node.get_deep_copy());
  }

  unique_ptr<char, JSONFreeDeleter> buffer(json_dumps(array.get(), JSON_COMPACT | JSON_ENSURE_ASCII));
  return string(buffer.get());
}

template <typename UGCUpdate>
Storage::SettingResult SetGenericUGCUpdate(
    vector<Storage::UGCIndex> & indexes, size_t & numberOfDeleted, FeatureID const & id,
    UGCUpdate const & ugc,
    FeatureType const & featureType,
    Version const version = Version::Latest)
{
  if (!ugc.IsValid())
    return Storage::SettingResult::InvalidUGC;

  auto const mercator = feature::GetCenter(featureType);
  feature::TypesHolder th(featureType);
  th.SortBySpec();
  auto const optMatchingType = ftraits::UGC::GetType(th);
  CHECK(optMatchingType, ());
  auto const type = th.GetBestType();
  for (auto & index : indexes)
  {
    if (type == index.m_type && mercator == index.m_mercator && !index.m_deleted)
    {
      index.m_deleted = true;
      ++numberOfDeleted;
      break;
    }
  }

  Storage::UGCIndex index;
  uint64_t offset;
  if (!GetUGCFileSize(offset))
    offset = 0;

  index.m_mercator = mercator;
  index.m_type = type;
  index.m_matchingType = *optMatchingType;
  index.m_mwmName = id.GetMwmName();
  index.m_dataVersion = id.GetMwmVersion();
  index.m_featureId = id.m_index;
  index.m_offset = offset;

  auto const ugcFilePath = GetUGCFilePath();
  try
  {
    FileWriter w(ugcFilePath, FileWriter::Op::OP_APPEND);
    Serialize(w, ugc, version);
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", ugcFilePath, "reason:", exception.what()));
    return Storage::SettingResult::WritingError;
  }

  indexes.emplace_back(move(index));
  return Storage::SettingResult::Success;
}
}  // namespace

UGCUpdate Storage::GetUGCUpdate(FeatureID const & id) const
{
  if (m_UGCIndexes.empty())
    return {};

  auto const feature = GetFeature(id);
  auto const mercator = feature::GetCenter(*feature);
  feature::TypesHolder th(*feature);
  th.SortBySpec();
  auto const type = th.GetBestType();

  auto const index = find_if(
      m_UGCIndexes.begin(), m_UGCIndexes.end(), [type, &mercator](UGCIndex const & index) -> bool {
        return type == index.m_type && mercator == index.m_mercator && !index.m_deleted;
      });

  if (index == m_UGCIndexes.end())
    return {};

  auto const offset = index->m_offset;
  auto const size = static_cast<size_t>(UGCSizeAtIndex(distance(m_UGCIndexes.begin(), index)));
  vector<uint8_t> buf;
  buf.resize(size);
  auto const ugcFilePath = GetUGCFilePath();
  try
  {
    FileReader r(ugcFilePath, true /* withExceptions */);
    r.Read(offset, buf.data(), size);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
    return {};
  }

  MemReader r(buf.data(), buf.size());
  NonOwningReaderSource source(r);
  UGCUpdate update;
  Deserialize(source, update);
  return update;
}

Storage::SettingResult Storage::SetUGCUpdate(FeatureID const & id, UGCUpdate const & ugc)
{
  auto const feature = GetFeature(id);
  return SetGenericUGCUpdate(m_UGCIndexes, m_numberOfDeleted, id, ugc,
                             *feature);
}

void Storage::Load()
{
  string data;
  auto const indexFilePath = GetIndexFilePath();
  try
  {
    FileReader r(indexFilePath);
    r.ReadAsString(data);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LWARNING, ("Exception while reading file:", indexFilePath, "reason:", exception.what()));
    return;
  }

  DeserializeUGCIndex(data, m_UGCIndexes);
  for (auto const & i : m_UGCIndexes)
  {
    if (i.m_deleted)
      ++m_numberOfDeleted;
  }
}

void Storage::SaveIndex() const
{
  if (m_UGCIndexes.empty())
    return;

  auto const jsonData = SerializeUGCIndex(m_UGCIndexes);
  auto const indexFilePath = GetIndexFilePath();
  try
  {
    FileWriter w(indexFilePath);
    w.Write(jsonData.c_str(), jsonData.length());
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", indexFilePath, "reason:", exception.what()));
  }
}

void Storage::Defragmentation()
{
  auto const indexesSize = m_UGCIndexes.size();
  if (m_numberOfDeleted < indexesSize / 2)
    return;

  auto const ugcFilePath = GetUGCFilePath();
  auto const tmpUGCFilePath = ugcFilePath + kTmpFileExtension;

  try
  {
    FileReader r(ugcFilePath, true /* withExceptions */);
    FileWriter w(tmpUGCFilePath, FileWriter::Op::OP_APPEND);
    uint64_t actualOffset = 0;
    for (size_t i = 0; i < indexesSize; ++i)
    {
      auto & index = m_UGCIndexes[i];
      if (index.m_deleted)
        continue;

      auto const offset = index.m_offset;
      auto const size = static_cast<size_t>(UGCSizeAtIndex(i));
      vector<uint8_t> buf;
      buf.resize(size);
      r.Read(offset, buf.data(), size);
      w.Write(buf.data(), size);
      index.m_offset = actualOffset;
      actualOffset += size;
    }
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
    return;
  }
  catch (FileWriter::Exception const & exception)
  {
    LOG(LERROR, ("Exception while writing file:", tmpUGCFilePath, "reason:", exception.what()));
    return;
  }

  m_UGCIndexes.erase(remove_if(m_UGCIndexes.begin(), m_UGCIndexes.end(),
                               [](UGCIndex const & i) -> bool { return i.m_deleted; }), m_UGCIndexes.end());

  CHECK(my::DeleteFileX(ugcFilePath), ());
  CHECK(my::RenameFileX(tmpUGCFilePath, ugcFilePath), ());

  m_numberOfDeleted = 0;
}

string Storage::GetUGCToSend() const
{
  if (m_UGCIndexes.empty())
    return string();

  auto array = my::NewJSONArray();
  auto const indexesSize = m_UGCIndexes.size();
  auto const ugcFilePath = GetUGCFilePath();
  FileReader r(ugcFilePath, true /* withExceptions */);
  vector<uint8_t> buf;
  for (size_t i = 0; i < indexesSize; ++i)
  {
    buf.clear();
    auto const & index = m_UGCIndexes[i];
    if (index.m_synchronized || index.m_deleted)
      continue;

    auto const offset = index.m_offset;
    auto const bufSize = static_cast<size_t>(UGCSizeAtIndex(i));
    buf.resize(bufSize);
    try
    {
      r.Read(offset, buf.data(), bufSize);
    }
    catch (FileReader::Exception const & exception)
    {
      LOG(LERROR, ("Exception while reading file:", ugcFilePath, "reason:", exception.what()));
      return string();
    }

    MemReader r(buf.data(), buf.size());
    NonOwningReaderSource source(r);
    UGCUpdate update;
    Deserialize(source, update);

    string data;
    {
      Sink sink(data);
      SerializerJson<Sink> ser(sink);
      ser(update);
    }

    my::Json serializedUgc(data);
    auto embeddedNode = my::NewJSONObject();
    ToJSONObject(*embeddedNode.get(), "data_version", index.m_dataVersion);
    ToJSONObject(*embeddedNode.get(), "mwm_name", index.m_mwmName);
    ToJSONObject(*embeddedNode.get(), "feature_id", index.m_featureId);
    ToJSONObject(*embeddedNode.get(), "feature_type", classif().GetReadableObjectName(index.m_matchingType));
    ToJSONObject(*serializedUgc.get(), "feature", *embeddedNode.release());
    json_array_append_new(array.get(), serializedUgc.get_deep_copy());
  }

  if (json_array_size(array.get()) == 0)
    return string();

  auto reviewsNode = my::NewJSONObject();
  ToJSONObject(*reviewsNode.get(), "reviews", *array.release());

  unique_ptr<char, JSONFreeDeleter> buffer(json_dumps(reviewsNode.get(), JSON_COMPACT | JSON_ENSURE_ASCII));
  return string(buffer.get());
}

size_t Storage::GetNumberOfUnsynchronized() const
{
  size_t numberOfUnsynchronized = 0;
  for (auto const & i : m_UGCIndexes)
  {
    if (!i.m_deleted && !i.m_synchronized)
      ++numberOfUnsynchronized;
  }
  return numberOfUnsynchronized;
}

void Storage::MarkAllAsSynchronized()
{
  if (m_UGCIndexes.empty())
    return;

  size_t numberOfUnsynchronized = 0;
  for (auto & index : m_UGCIndexes)
  {
    if (!index.m_synchronized)
    {
      index.m_synchronized = true;
      numberOfUnsynchronized++;
    }
  }

  if (numberOfUnsynchronized == 0)
    return;

  auto const indexPath = GetIndexFilePath();
  my::DeleteFileX(indexPath);
  SaveIndex();
}

uint64_t Storage::UGCSizeAtIndex(size_t const indexPosition) const
{
  CHECK(!m_UGCIndexes.empty(), ());
  auto const indexesSize = m_UGCIndexes.size();
  CHECK_LESS(indexPosition, indexesSize, ());
  auto const indexOffset = m_UGCIndexes[indexPosition].m_offset;
  uint64_t nextOffset;
  if (indexPosition == indexesSize - 1)
    CHECK(GetUGCFileSize(nextOffset), ());
  else
    nextOffset = m_UGCIndexes[indexPosition + 1].m_offset;

  CHECK_GREATER(nextOffset, indexOffset, ());
  return nextOffset - indexOffset;
}

unique_ptr<FeatureType> Storage::GetFeature(FeatureID const & id) const
{
  CHECK(id.IsValid(), ());
  Index::FeaturesLoaderGuard guard(m_index, id.m_mwmId);
  auto feature = guard.GetOriginalOrEditedFeatureByIndex(id.m_index);
  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);
  if (feature->GetFeatureType() == feature::EGeomType::GEOM_AREA)
    feature->ParseTriangles(FeatureType::BEST_GEOMETRY);
  CHECK(feature, ());
  return feature;
}

// Testing
Storage::SettingResult Storage::SetUGCUpdateForTesting(FeatureID const & id,
                                                       v0::UGCUpdate const & ugc)
{
  auto const feature = GetFeature(id);
  return SetGenericUGCUpdate(m_UGCIndexes, m_numberOfDeleted, id, ugc,
                             *feature, Version::V0);
}
}  // namespace ugc

namespace lightweight
{
size_t GetNumberOfUnsentUGC()
{
  auto const indexFilePath = ugc::GetIndexFilePath();
  if (!Platform::IsFileExistsByFullPath(indexFilePath))
    return 0;

  string data;
  try
  {
    FileReader r(indexFilePath);
    r.ReadAsString(data);
  }
  catch (FileReader::Exception const & exception)
  {
    LOG(LWARNING, ("Exception while reading file:", indexFilePath, "reason:", exception.what()));
    return 0;
  }

  vector<ugc::Storage::UGCIndex> index;
  ugc::DeserializeUGCIndex(data, index);
  size_t number = 0;
  for (auto const & i : index)
  {
    if (!i.m_deleted && !i.m_synchronized)
      ++number;
  }

  return number;
}
}  // namespace lightweight
<|endoftext|>


<commit_before>#pragma once

#define randf() (rand() / (float)RAND_MAX)

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#define GLM_ENABLE_EXPERIMENTAL
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/quaternion.hpp>
#pragma GCC diagnostic pop

#include <core/json.hpp>

namespace glm {

    inline void to_json(json& j, const vec3& p) {
        j.array({p.x, p.y, p.z});
    }

    inline void from_json(const json& j, vec3& p) {
        int ix = 0;
        for (auto it = j.begin(); it != j.end(); ++it, ix++) {
            p[ix] = *it;
        }
    }

} // namespace glm
<commit_msg>Fix warnings<commit_after>#pragma once

#define randf() (rand() / (float)RAND_MAX)

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#define GLM_ENABLE_EXPERIMENTAL
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/quaternion.hpp>
#pragma GCC diagnostic pop

#include <core/json.hpp>

namespace glm {

    inline void to_json( nlohmann::json &j, const glm::vec3 &p ) {
        j.array( {p.x, p.y, p.z} );
    }

    inline void from_json( const nlohmann::json &j, glm::vec3 &p ) {
        int ix = 0;
        for ( auto it = j.begin( ); it != j.end( ); ++it, ix++ ) {
            p[ix] = *it;
        }
    }

} // namespace glm
<|endoftext|>


<commit_before>#include<bits/stdc++.h>
#define token std::pair<std::string, std::string> // token type, token content

// The sg compiler
// Pascal Sommer, November 2016

// requires GCC >= 4.4

class Scanner{
    // The Scanner class doesn't do the lexing, but is the interface for the
    // actual lexer to the file. It keeps track of the line and character
    // number, and lets the lexer fetch words or lines, and provides a simple
    // form of backtracking.
    std::stringstream buffered;
    std::ifstream infile;
    std::string file_path;
    int fallback_line_number;
    int fallback_character_number;

    bool read_to_buffer(){
	std::string line = "";
	if( ! getline(infile, line)) return false;

	buffered << line;

	if(infile.bad()){
	    std::cerr<<"IO Error\n";
	    return false;
        }

	return ! buffered.str().empty();
    }

    void skip_whitespace(){

    }

    // todo: figure out what kind of buffer functionality
    // I need exactly

public:
    int line_number;
    int line_character_number;

    bool match_string(std::string pattern);
    std::string get_alphanum();
    std::string get_rest_of_line();
    std::string get_position();

    Scanner(std::string file_path): file_path(file_path)
    {
	infile.open(file_path, std::ifstream::in);
	line_number = 0;
	line_character_number = 0;
	//buffered = "";
    }
};

// if string matches, consume input, otherwise don't
// consume anything. Skips any leading whitespace.
bool Scanner::match_string(std::string pattern){

}

// consumes word unless EOF. Returns without leading
// or trailing whitespace.
std::string Scanner::get_alphanum(){

}

// get until newline, and consume input.
std::string Scanner::get_rest_of_line(){

}

// return the file path, line number and character number
std::string Scanner::get_position(){
    return file_path + ", " +
	std::to_string(line_number) + ":" +
	std::to_string(line_character_number);
}

class Lexer{
    // The Lexer class uses the Scanner class as an interface to the file. It
    // has a single public method (besides the constructor) that returns a
    // vector of tokens.
    Scanner* scanner;
    const std::vector<token> v_empty;
    std::vector<token> v_error;

    void print_error(std::string message){
	std::cerr<<"ERROR in " << scanner->get_position() << ": " << message <<"\n";
    }

    // the lex_<type> functions return the lexed tokens if
    // the type matches, otherwise return an empty vector
    // because c++ is lacking a maybe monad.

    std::vector<token> lex_node(){
	if( ! (scanner->match_string("node") || scanner->match_string("n")) ){
	    return v_empty;
	}

	std::string name = scanner->get_alphanum();

	std::vector<token> out = {{"node", name}};

	if(scanner->match_string(":")){
	    // bash node
	    std::string command = scanner->get_rest_of_line();
	    if(command == ""){
		print_error("Expected bash command");
		return v_error;
	    }

	    out.push_back({"bash_command", command});
	}else if(scanner->match_string("/")){
	    // io node
	    std::string io_type = scanner->get_alphanum();
	    if(io_type != "infile" && io_type != "outfile"){
		print_error("Expected type of io node ('infile' or 'outfile')");
		return v_error;
	    }
	    std::string number = scanner->get_alphanum();
	    if(number == ""){
		print_error("Expected number of file");
		return v_error;
	    }
	    out.push_back({io_type, number});
	}else if(scanner->match_string("-")){
	    // instance node
	    std::string name = scanner->get_alphanum();
	    if(name == ""){
		print_error("Expected group name");
		return v_error;
	    }

	    out.push_back({"instance", name});
	}else{
	    print_error("Expected ':', '/' or '-'");
	    return v_error;
	}
    }

    std::vector<token> lex_modifier(){
	std::vector<token> out;
	if(scanner->match_string(".")){
	    std::string mod = scanner->get_alphanum();
	    if(mod == ""){
		print_error("Expected node modifier");
		return v_error;
	    }
	    out.push_back({"node_modifier", mod});
	}
	return out;
    }

    std::vector<token> lex_mod_name(std::string token_name){
	std::vector<token> out;

	std::string name = scanner->get_alphanum();
	if(name == ""){
	    print_error("Expected name of node");
	    return v_error;
	}
	out.push_back({token_name, name});

	// modifier of the source
	std::vector<token> mod = lex_modifier();
	if(mod == v_error){
	    return v_error;
	}else if(! mod.empty()){
	    out.push_back(mod[0]);
	}

	return out;
    }

    std::vector<token> lex_edge(){
	if( ! (scanner->match_string("edge") || scanner->match_string("e")) ){
	    return v_empty;
	}

	std::vector<token> out = {{"edge", ""}};

	// source of the edge
	std::vector<token> name1 = lex_mod_name("edge_source");
	if(name1 == v_error){
	    return v_error;
	}
	for(auto p:name1){
	    out.push_back(p);
	}

	// destination of the edge
	std::vector<token> name2 = lex_mod_name("edge_destination");
	if(name2 == v_error){
	    return v_error;
	}
	for(auto p:name2){
	    out.push_back(p);
	}

	return out;
    }

    std::vector<token> lex_group_header(){
	if( ! (scanner->match_string("group") || scanner->match_string("g")) ){
	    return v_empty;
	}

	std::string name = scanner->get_alphanum();

	if( ! scanner->match_string("{")){
	    print_error("Expected '{'");
	    return v_error;
	}
    }

    std::vector<token> lex_group_close(){
	if( ! scanner->match_string("}")){
	    return v_empty;
	}

    }

    std::vector<token> lex_comment(){
	if ( ! scanner->match_string("#")){
	    return v_empty;
	}

	// inline populate vector, requires GCC >= 4.4
	std::vector<token> out = {{"comment", scanner->get_rest_of_line()}};
	return out;
    }

public:
    std::string file_path;

    Lexer(std::string file_path): file_path(file_path){
	scanner = new Scanner(file_path);
	v_error.push_back({"ERROR", "ERROR"});
    }
};
<commit_msg>lex components<commit_after>#include<bits/stdc++.h>
#define token std::pair<std::string, std::string> // token type, token content

// The sg compiler
// Pascal Sommer, November 2016

// requires GCC >= 4.4

class Scanner{
    // The Scanner class doesn't do the lexing, but is the interface for the
    // actual lexer to the file. It keeps track of the line and character
    // number, and lets the lexer fetch words or lines, and provides a simple
    // form of backtracking.
    std::stringstream buffered;
    std::ifstream infile;
    std::string file_path;
    int fallback_line_number;
    int fallback_character_number;

    bool read_to_buffer(){
	std::string line = "";
	if( ! getline(infile, line)) return false;

	buffered << line;

	if(infile.bad()){
	    std::cerr<<"IO Error\n";
	    return false;
        }

	return ! buffered.str().empty();
    }

    void skip_whitespace(){

    }

    // todo: figure out what kind of buffer functionality
    // I need exactly

public:
    int line_number;
    int line_character_number;

    bool match_string(std::string pattern);
    std::string get_alphanum();
    std::string get_rest_of_line();
    std::string get_position();

    Scanner(std::string file_path): file_path(file_path)
    {
	infile.open(file_path, std::ifstream::in);
	line_number = 0;
	line_character_number = 0;
	//buffered = "";
    }
};

// if string matches, consume input, otherwise don't
// consume anything. Skips any leading whitespace.
bool Scanner::match_string(std::string pattern){

}

// consumes word unless EOF. Returns without leading
// or trailing whitespace.
std::string Scanner::get_alphanum(){

}

// get until newline, and consume input.
std::string Scanner::get_rest_of_line(){

}

// return the file path, line number and character number
std::string Scanner::get_position(){
    return file_path + ", " +
	std::to_string(line_number) + ":" +
	std::to_string(line_character_number);
}

class Lexer{
    // The Lexer class uses the Scanner class as an interface to the file. It
    // has a single public method (besides the constructor) that returns a
    // vector of tokens.
    Scanner* scanner;
    const std::vector<token> v_empty;
    std::vector<token> v_error;

    void print_error(std::string message){
	std::cerr<<"ERROR in " << scanner->get_position() << ": " << message <<"\n";
    }

    // the lex_<type> functions return the lexed tokens if
    // the type matches, otherwise return an empty vector
    // because c++ is lacking a maybe monad.

    std::vector<token> lex_node(){
	if( ! (scanner->match_string("node") || scanner->match_string("n")) ){
	    return v_empty;
	}

	std::string name = scanner->get_alphanum();

	std::vector<token> out = {{"node", name}};

	if(scanner->match_string(":")){
	    // bash node
	    std::string command = scanner->get_rest_of_line();
	    if(command == ""){
		print_error("Expected bash command");
		return v_error;
	    }

	    out.push_back({"bash_command", command});
	}else if(scanner->match_string("/")){
	    // io node
	    std::string io_type = scanner->get_alphanum();
	    if(io_type != "infile" && io_type != "outfile"){
		print_error("Expected type of io node ('infile' or 'outfile')");
		return v_error;
	    }
	    std::string number = scanner->get_alphanum();
	    if(number == ""){
		print_error("Expected number of file");
		return v_error;
	    }
	    out.push_back({io_type, number});
	}else if(scanner->match_string("-")){
	    // instance node
	    std::string name = scanner->get_alphanum();
	    if(name == ""){
		print_error("Expected group name");
		return v_error;
	    }

	    out.push_back({"instance", name});
	}else{
	    print_error("Expected ':', '/' or '-'");
	    return v_error;
	}

	return out;
    }

    std::vector<token> lex_modifier(){
	std::vector<token> out;
	if(scanner->match_string(".")){
	    std::string mod = scanner->get_alphanum();
	    if(mod == ""){
		print_error("Expected node modifier");
		return v_error;
	    }
	    out.push_back({"node_modifier", mod});
	}
	return out;
    }

    std::vector<token> lex_mod_name(std::string token_name){
	std::vector<token> out;

	std::string name = scanner->get_alphanum();
	if(name == ""){
	    print_error("Expected name of node");
	    return v_error;
	}
	out.push_back({token_name, name});

	// modifier of the source
	std::vector<token> mod = lex_modifier();
	if(mod == v_error){
	    return v_error;
	}else if(! mod.empty()){
	    out.push_back(mod[0]);
	}

	return out;
    }

    std::vector<token> lex_edge(){
	if( ! (scanner->match_string("edge") || scanner->match_string("e")) ){
	    return v_empty;
	}

	std::vector<token> out = {{"edge", ""}};

	// source of the edge
	std::vector<token> name1 = lex_mod_name("edge_source");
	if(name1 == v_error){
	    return v_error;
	}
	for(auto p:name1){
	    out.push_back(p);
	}

	// destination of the edge
	std::vector<token> name2 = lex_mod_name("edge_destination");
	if(name2 == v_error){
	    return v_error;
	}
	for(auto p:name2){
	    out.push_back(p);
	}

	return out;
    }

    std::vector<token> lex_group_header(){
	if( ! (scanner->match_string("group") || scanner->match_string("g")) ){
	    return v_empty;
	}

	std::string name = scanner->get_alphanum();

	if(name == ""){
	    print_error("Expected group name");
	    return v_error;
	}

	if( ! scanner->match_string("{")){
	    print_error("Expected '{'");
	    return v_error;
	}

	std::vector<token> out = {{"group", name}};
	return out;
    }

    std::vector<token> lex_group_close(){
	if( ! scanner->match_string("}")){
	    return v_empty;
	}

	std::vector<token> out = {{"group_close", "}"}};
	return out;
    }

    std::vector<token> lex_comment(){
	if ( ! scanner->match_string("#")){
	    return v_empty;
	}

	// inline populate vector, requires GCC >= 4.4
	std::vector<token> out = {{"comment", scanner->get_rest_of_line()}};
	return out;
    }

public:
    std::string file_path;

    Lexer(std::string file_path): file_path(file_path){
	scanner = new Scanner(file_path);
	v_error.push_back({"ERROR", "ERROR"});
    }
};
<|endoftext|>