<commit_before>#include <monsoon/objpipe/callback.h>
#include <monsoon/objpipe/array.h>
#include <monsoon/objpipe/errc.h>
#include "UnitTest++/UnitTest++.h"
#include "test_hacks.h"
#include <vector>

using monsoon::objpipe::objpipe_errc;

TEST(callback) {
  auto reader = monsoon::objpipe::new_callback<int>(
      [](auto& cb) {
        for (int i = 0; i < 5; ++i)
          cb(i);
      });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(array_using_iterators) {
  std::vector<int> il = { 0, 1, 2, 3, 4 };
  auto reader = monsoon::objpipe::new_array<int>(il.begin(), il.end());

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(array_using_initializer_list) {
  auto reader = monsoon::objpipe::new_array<int>({ 0, 1, 2, 3, 4 });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(filter_operation) {
  auto reader = monsoon::objpipe::new_array<int>({ 0, 1, 2, 3, 4 })
      .filter([](int x) { return x % 2 == 0; });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 is filtered out

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 is filtered out

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

int main() {
  return UnitTest::RunAllTests();
}
<commit_msg>Test objpipe transform operation.<commit_after>#include <monsoon/objpipe/callback.h>
#include <monsoon/objpipe/array.h>
#include <monsoon/objpipe/errc.h>
#include "UnitTest++/UnitTest++.h"
#include "test_hacks.h"
#include <vector>

using monsoon::objpipe::objpipe_errc;

TEST(callback) {
  auto reader = monsoon::objpipe::new_callback<int>(
      [](auto& cb) {
        for (int i = 0; i < 5; ++i)
          cb(i);
      });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(array_using_iterators) {
  std::vector<int> il = { 0, 1, 2, 3, 4 };
  auto reader = monsoon::objpipe::new_array<int>(il.begin(), il.end());

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(array_using_initializer_list) {
  auto reader = monsoon::objpipe::new_array<int>({ 0, 1, 2, 3, 4 });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(1, reader.front());
  CHECK_EQUAL(1, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(3, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(filter_operation) {
  auto reader = monsoon::objpipe::new_array<int>({ 0, 1, 2, 3, 4 })
      .filter([](int x) { return x % 2 == 0; });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 is filtered out

  // Element 2 access, using pull().
  CHECK_EQUAL(2, reader.pull());

  // Element 3 is filtered out

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(4, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

TEST(transform_operation) {
  auto reader = monsoon::objpipe::new_array<int>({ 0, 1, 2, 3, 4 })
      .transform([](int x) { return 2 * x; });

  CHECK_EQUAL(false, reader.empty());

  // Element 0 access, using front() and pop_front().
  CHECK_EQUAL(0, reader.front());
  reader.pop_front();

  // Element 1 access, using front() and pull().
  CHECK_EQUAL(2, reader.front());
  CHECK_EQUAL(2, reader.pull());

  // Element 2 access, using pull().
  CHECK_EQUAL(4, reader.pull());

  // Element 3 access, using try_pull().
  CHECK_EQUAL(6, reader.try_pull());

  // Element 4 access, using wait(), then pull().
  CHECK_EQUAL(objpipe_errc::success, reader.wait());
  CHECK_EQUAL(8, reader.pull());

  // No more elements.
  CHECK_EQUAL(false, bool(reader));
  CHECK_EQUAL(true, reader.empty());
  CHECK_EQUAL(objpipe_errc::closed, reader.wait());

  objpipe_errc e;
  std::optional<int> failed_pull = reader.pull(e);
  CHECK_EQUAL(false, failed_pull.has_value());
  CHECK_EQUAL(objpipe_errc::closed, e);
}

int main() {
  return UnitTest::RunAllTests();
}
<|endoftext|>


<commit_before>#ifndef __CPREL_CPREL_HH__
#define __CPREL_CPREL_HH__

#include <iostream>
#include <sstream>
#include <climits>

#include <gecode/kernel.hh>
#include <gecode/set.hh> // for channel constraint
#include <cptuple/cptuple.hh> // for the dom constraint
#include <rel/grelation.hh>

using Gecode::Exception;
using Gecode::VarArgArray;
using Gecode::VarArray;

// exceptions
namespace MPG { namespace CPRel {

/// Exception indicating invalid limits
class OutOfLimits : public Exception {
public:
  OutOfLimits(const char* l)
    : Exception(l,"Number out of limits") {}
};
/// Exception indicating empty domain declaration
class VariableEmptyDomain : public Exception {
public:
  VariableEmptyDomain(const char* l)
    : Exception(l,"Attempt to create variable with empty domain") {}
};
/// Exception indicating invalid arity
class ArityMissmatch : public Exception {
public:
  ArityMissmatch(const char* l)
    : Exception(l,"Invalid arity for operation") {}
};
/// Exception indicating invalid permutation
class InvalidPermutation : public Exception {
public:
  InvalidPermutation(const char* l)
    : Exception(l,"Invalid permutation for operation") {}
};
}}

// Variable implementation definition
#include <cprel/varimp.hh>

// Variable definition
#include <cprel/var.hh>

// array traits
namespace MPG {
class CPRelVarArgs; class CPRelVarArray;
}

namespace Gecode {
template<>
class ArrayTraits<Gecode::VarArray<MPG::CPRelVar> > {
public:
  typedef MPG::CPRelVarArray  StorageType;
  typedef MPG::CPRelVar       ValueType;
  typedef MPG::CPRelVarArgs   ArgsType;
};
template<>
class ArrayTraits<MPG::CPRelVarArray> {
public:
  typedef MPG::CPRelVarArray  StorageType;
  typedef MPG::CPRelVar       ValueType;
  typedef MPG::CPRelVarArgs   ArgsType;
};
template<>
class ArrayTraits<Gecode::VarArgArray<MPG::CPRelVar> > {
public:
  typedef MPG::CPRelVarArgs   StorageType;
  typedef MPG::CPRelVar       ValueType;
  typedef MPG::CPRelVarArgs   ArgsType;
};
template<>
class ArrayTraits<MPG::CPRelVarArgs> {
public:
  typedef MPG::CPRelVarArgs  StorageType;
  typedef MPG::CPRelVar      ValueType;
  typedef MPG::CPRelVarArgs  ArgsType;
};

}
// variable arrays
namespace MPG {
class CPRelVarArgs : public VarArgArray<CPRelVar> {
public:
  CPRelVarArgs(void) {}
  explicit CPRelVarArgs(int n) : VarArgArray<CPRelVar>(n) {}
  CPRelVarArgs(const CPRelVarArgs& a) : VarArgArray<CPRelVar>(a) {}
  CPRelVarArgs(const VarArray<CPRelVar>& a) : VarArgArray<CPRelVar>(a) {}
  CPRelVarArgs(Space& home, int n,
               const GRelation& l, const GRelation& u)
    : VarArgArray<CPRelVar>(n) {
    for (int i=0; i<n; i++)
      (*this)[i] = CPRelVar(home,l,u);
  }
};
class CPRelVarArray : public VarArray<CPRelVar> {
public:
  CPRelVarArray(void) {}
  CPRelVarArray(const CPRelVarArray& a)
    : VarArray<CPRelVar>(a) {}
  CPRelVarArray(Space& home, int n, const GRelation& l, const GRelation& u)
    : VarArray<CPRelVar>(home,n) {
    for (int i=0; i<n; i++)
      (*this)[i] = CPRelVar(home,l,u);
  }
};

}

// View implementation
#include <cprel/view.hh>

// Descriptors
#include <bdddomain/perm-descriptor.hh>

/**
 * \defgroup SetProp Set propagators on relations
 *
 * A relation can be seen as a set of tuples. From this point of view different
 * constraints can be defined. These propagators are presented in this module.
 */

/**
 * \defgroup RelProp Basic relation propagators
 *
 * The propagators presented in this module extend common operations on relations
 * to constraints.  As opposed to databases, columns in the relation decission
 * variables are identified by their possition. This is, a relation of arity \a
 * n has columns \f$0,\ldots,n-1\f$ being the column identified with 0 the right
 * most one.
 *
 * As the notion of "colum names" is merely numeric, some of the constraints that
 * work with column information take numbers identifying the columns as parameters.
 * Moreover, constraints like \a join and \a projection rely on some conventions
 * regarding this imput.
 */

/**
 * \defgroup RelBranch Branchers (distribution strategies) on relations
 *
 * This module contains the branchers that can be used on relation domains.
 */

/**
 * \defgroup ChannelProp Channel propagators on relation variables.
 *
 * Constraints that provide interaction between relation
 * decision variables and variables from other constraint systems.
 */

namespace MPG {
/**
 * \brief Posts: \f$ A = B \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 *
 * \see MPG::CPRel::Prop::Equal
 */
void equal(Gecode::Space& home, CPRelVar A, CPRelVar B);
/**
 * \brief Posts: \f$ A = \overline{B} \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 */
void complement(Gecode::Space& home, CPRelVar A, CPRelVar B);
/**
 * \brief Posts: \f$ A \cap B = C \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
 *
 * \see MPG::CPRel::Prop::Intersect
 */
void intersect(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
/**
 * \brief Posts: \f$ A \cup B = C \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
 */
void Union(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
/**
 * \brief Posts: \f$ A \subseteq B \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 */
void subset(Gecode::Space& home, CPRelVar A, CPRelVar B);
/**
 * \brief Posts: \f$ disjoint(A,B)\f$.
 * \ingroup SetProp
 *
 * Enforces that \a A and \a B are two disjoint relations.
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 */
void disjoint(Gecode::Space& home, CPRelVar A, CPRelVar B);
/**
 * \brief Posts the constraint: \f$ \forall t : t\in A \Rightarrow t\in B \iff t \in C \f$
 * \ingroup SetProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
 */
void implies(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
/**
 * \brief Posts the constraint: \f$ A = B \leftrightarrow_{\text{desc}}\f$.
 * \ingroup RelProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B  a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param desc an object describing the permutation. It represents a map from
 *        columns of \a A to columns of \a B.
 *
 * @see PermDescriptor
 */
void permutation(Gecode::Space& home, CPRelVar A, CPRelVar B,
                 const PermDescriptor& desc);
/**
 * \brief Posts the constraint: \f$ \Pi_{p} A = B \f$.
 * \ingroup RelProp
 *
 * @param p is the number of columns on the right of \a A to project on.
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n-p}\f$
 *
 * @see MPG::CPRel::Prop::Project
 */
void projection(Gecode::Space& home, int p, CPRelVar A, CPRelVar B);
/**
 * \brief Posts the constraint: \f$ A\;\bowtie_{j}\;B = C \f$
 * \ingroup RelProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param j is the number of columns on the right of \a A
 * and on the left of \a B to join on.
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-j}\f$
 *
 * @see MPG::CPRel::Prop::Join
 */
void join(Gecode::Space& home, CPRelVar A, int j, CPRelVar B, CPRelVar C);
/**
 * \brief Posts the constraint: \f$ A_{\smile_{f}}B = C \f$
 * \ingroup RelProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param f is the number of columns on the right of \a A
 * and on the left of \a B that a match must contain to be consider as a follow.
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-2j}\f$
 *
 * @see MPG::CPRel::Prop::Follow
 */
void follow(Gecode::Space& home, CPRelVar A, int f, CPRelVar B, CPRelVar C);
/**
 * \brief Posts the constraint: \f$ A \%_{d}B = C \f$
 * \ingroup RelProp
 *
 * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
 * @param d is the number of columns on the right of \a A
 * and on the left of \a B that a match must contain to be consider for the division
 * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
 * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-2j}\f$
 *
 * @see MPG::CPRel::Prop::Follow
 */
void divide(Gecode::Space& home, CPRelVar A, int d, CPRelVar B, CPRelVar C);
/**
 * \brief Posts the constraint: \f$ R = S\f$
 * \ingroup ChannelProp
 *
 * @param R a unary relation decision variable: \f$A\subseteq\mathcal{U}_{1}\f$
 * @param S a set decision variable.
 *
 * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
 * is not 1.
 */
void channel(Gecode::Space& home, CPRelVar R, Gecode::SetVar S);
/**
 * \brief Posts the constraint: \f$ t \in R\f$
 * \ingroup ChannelProp
 *
 * @param t a tuple decision variable which domain is a subset of \f$\mathcal{U}_{n}\f$
 * @param R a relation decision variable: \f$R \subseteq \mathcal{U}_{n}\f$.
 *
 * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
 * and the arity of \a t is not the same.
 */
void included(Gecode::Space& home, CPTupleVar t, CPRelVar R);
/**
 * \brief Posts the constraint: \f$ t \notin R\f$
 * \ingroup ChannelProp
 *
 * @param t a tuple decision variable which domain is a subset of \f$\mathcal{U}_{n}\f$
 * @param R a relation decision variable: \f$R \subseteq \mathcal{U}_{n}\f$.
 *
 * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
 * and the arity of \a t is not the same.
 */
void excluded(Gecode::Space& home, CPTupleVar t, CPRelVar R);

  void include(Gecode::Space& home, CPRelVar A, GRelation R);

  void exclude(Gecode::Space& home, CPRelVar A, GRelation R);
/**
 * \brief Simple branching on relations.
 * \ingroup RelBranch
 *
 * Branches on relation  \a R by selecting a tuple in it and creating a choice with
 * the tuple as part of the relation for the first alternative and the tuple as
 * excluded from the relation as the second alternative.
 *
 * @param R a relation decision variable.
 *
 */
void branch(Gecode::Home home, CPRelVar R);
}
#endif
<commit_msg>Disabled tuple constraint prototypes<commit_after>#ifndef __CPREL_CPREL_HH__
#define __CPREL_CPREL_HH__

#include <iostream>
#include <sstream>
#include <climits>

#include <gecode/kernel.hh>
#include <gecode/set.hh> // for channel constraint
//#include <cptuple/cptuple.hh> // for the dom constraint
#include <rel/grelation.hh>

using Gecode::Exception;
using Gecode::VarArgArray;
using Gecode::VarArray;

// exceptions
namespace MPG { namespace CPRel {

    /// Exception indicating invalid limits
    class OutOfLimits : public Exception {
    public:
      OutOfLimits(const char* l)
	: Exception(l,"Number out of limits") {}
    };
    /// Exception indicating empty domain declaration
    class VariableEmptyDomain : public Exception {
    public:
      VariableEmptyDomain(const char* l)
	: Exception(l,"Attempt to create variable with empty domain") {}
    };
    /// Exception indicating invalid arity
    class ArityMissmatch : public Exception {
    public:
      ArityMissmatch(const char* l)
	: Exception(l,"Invalid arity for operation") {}
    };
    /// Exception indicating invalid permutation
    class InvalidPermutation : public Exception {
    public:
      InvalidPermutation(const char* l)
	: Exception(l,"Invalid permutation for operation") {}
    };
  }}

// Variable implementation definition
#include <cprel/varimp.hh>

// Variable definition
#include <cprel/var.hh>

// array traits
namespace MPG {
  class CPRelVarArgs; class CPRelVarArray;
}

namespace Gecode {
  template<>
  class ArrayTraits<Gecode::VarArray<MPG::CPRelVar> > {
  public:
    typedef MPG::CPRelVarArray  StorageType;
    typedef MPG::CPRelVar       ValueType;
    typedef MPG::CPRelVarArgs   ArgsType;
  };
  template<>
  class ArrayTraits<MPG::CPRelVarArray> {
  public:
    typedef MPG::CPRelVarArray  StorageType;
    typedef MPG::CPRelVar       ValueType;
    typedef MPG::CPRelVarArgs   ArgsType;
  };
  template<>
  class ArrayTraits<Gecode::VarArgArray<MPG::CPRelVar> > {
  public:
    typedef MPG::CPRelVarArgs   StorageType;
    typedef MPG::CPRelVar       ValueType;
    typedef MPG::CPRelVarArgs   ArgsType;
  };
  template<>
  class ArrayTraits<MPG::CPRelVarArgs> {
  public:
    typedef MPG::CPRelVarArgs  StorageType;
    typedef MPG::CPRelVar      ValueType;
    typedef MPG::CPRelVarArgs  ArgsType;
  };

}
// variable arrays
namespace MPG {
  class CPRelVarArgs : public VarArgArray<CPRelVar> {
  public:
    CPRelVarArgs(void) {}
    explicit CPRelVarArgs(int n) : VarArgArray<CPRelVar>(n) {}
    CPRelVarArgs(const CPRelVarArgs& a) : VarArgArray<CPRelVar>(a) {}
    CPRelVarArgs(const VarArray<CPRelVar>& a) : VarArgArray<CPRelVar>(a) {}
    CPRelVarArgs(Space& home, int n,
		 const GRelation& l, const GRelation& u)
      : VarArgArray<CPRelVar>(n) {
      for (int i=0; i<n; i++)
	(*this)[i] = CPRelVar(home,l,u);
    }
  };
  class CPRelVarArray : public VarArray<CPRelVar> {
  public:
    CPRelVarArray(void) {}
    CPRelVarArray(const CPRelVarArray& a)
      : VarArray<CPRelVar>(a) {}
    CPRelVarArray(Space& home, int n, const GRelation& l, const GRelation& u)
      : VarArray<CPRelVar>(home,n) {
      for (int i=0; i<n; i++)
	(*this)[i] = CPRelVar(home,l,u);
    }
  };

}

// View implementation
#include <cprel/view.hh>

// Descriptors
#include <bdddomain/perm-descriptor.hh>

/**
 * \defgroup SetProp Set propagators on relations
 *
 * A relation can be seen as a set of tuples. From this point of view different
 * constraints can be defined. These propagators are presented in this module.
 */

/**
 * \defgroup RelProp Basic relation propagators
 *
 * The propagators presented in this module extend common operations on relations
 * to constraints.  As opposed to databases, columns in the relation decission
 * variables are identified by their possition. This is, a relation of arity \a
 * n has columns \f$0,\ldots,n-1\f$ being the column identified with 0 the right
 * most one.
 *
 * As the notion of "colum names" is merely numeric, some of the constraints that
 * work with column information take numbers identifying the columns as parameters.
 * Moreover, constraints like \a join and \a projection rely on some conventions
 * regarding this imput.
 */

/**
 * \defgroup RelBranch Branchers (distribution strategies) on relations
 *
 * This module contains the branchers that can be used on relation domains.
 */

/**
 * \defgroup ChannelProp Channel propagators on relation variables.
 *
 * Constraints that provide interaction between relation
 * decision variables and variables from other constraint systems.
 */

namespace MPG {
  /**
   * \brief Posts: \f$ A = B \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   *
   * \see MPG::CPRel::Prop::Equal
   */
  void equal(Gecode::Space& home, CPRelVar A, CPRelVar B);
  /**
   * \brief Posts: \f$ A = \overline{B} \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   */
  void complement(Gecode::Space& home, CPRelVar A, CPRelVar B);
  /**
   * \brief Posts: \f$ A \cap B = C \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
   *
   * \see MPG::CPRel::Prop::Intersect
   */
  void intersect(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts: \f$ A \cup B = C \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
   */
  void Union(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts: \f$ A \subseteq B \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   */
  void subset(Gecode::Space& home, CPRelVar A, CPRelVar B);
  /**
   * \brief Posts: \f$ disjoint(A,B)\f$.
   * \ingroup SetProp
   *
   * Enforces that \a A and \a B are two disjoint relations.
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   */
  void disjoint(Gecode::Space& home, CPRelVar A, CPRelVar B);
  /**
   * \brief Posts the constraint: \f$ \forall t : t\in A \Rightarrow t\in B \iff t \in C \f$
   * \ingroup SetProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n}\f$
   */
  void implies(Gecode::Space& home, CPRelVar A, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts the constraint: \f$ A = B \leftrightarrow_{\text{desc}}\f$.
   * \ingroup RelProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B  a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param desc an object describing the permutation. It represents a map from
   *        columns of \a A to columns of \a B.
   *
   * @see PermDescriptor
   */
  void permutation(Gecode::Space& home, CPRelVar A, CPRelVar B,
		   const PermDescriptor& desc);
  /**
   * \brief Posts the constraint: \f$ \Pi_{p} A = B \f$.
   * \ingroup RelProp
   *
   * @param p is the number of columns on the right of \a A to project on.
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{n-p}\f$
   *
   * @see MPG::CPRel::Prop::Project
   */
  void projection(Gecode::Space& home, int p, CPRelVar A, CPRelVar B);
  /**
   * \brief Posts the constraint: \f$ A\;\bowtie_{j}\;B = C \f$
   * \ingroup RelProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param j is the number of columns on the right of \a A
   * and on the left of \a B to join on.
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-j}\f$
   *
   * @see MPG::CPRel::Prop::Join
   */
  void join(Gecode::Space& home, CPRelVar A, int j, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts the constraint: \f$ A_{\smile_{f}}B = C \f$
   * \ingroup RelProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param f is the number of columns on the right of \a A
   * and on the left of \a B that a match must contain to be consider as a follow.
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-2j}\f$
   *
   * @see MPG::CPRel::Prop::Follow
   */
  void follow(Gecode::Space& home, CPRelVar A, int f, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts the constraint: \f$ A \%_{d}B = C \f$
   * \ingroup RelProp
   *
   * @param A a relation decision variable: \f$A\subseteq\mathcal{U}_{n}\f$
   * @param d is the number of columns on the right of \a A
   * and on the left of \a B that a match must contain to be consider for the division
   * @param B a relation decision variable: \f$B\subseteq\mathcal{U}_{m}\f$
   * @param C a relation decision variable: \f$C\subseteq\mathcal{U}_{n+m-2j}\f$
   *
   * @see MPG::CPRel::Prop::Follow
   */
  void divide(Gecode::Space& home, CPRelVar A, int d, CPRelVar B, CPRelVar C);
  /**
   * \brief Posts the constraint: \f$ R = S\f$
   * \ingroup ChannelProp
   *
   * @param R a unary relation decision variable: \f$A\subseteq\mathcal{U}_{1}\f$
   * @param S a set decision variable.
   *
   * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
   * is not 1.
   */
  void channel(Gecode::Space& home, CPRelVar R, Gecode::SetVar S);
  /**
   * \brief Posts the constraint: \f$ t \in R\f$
   * \ingroup ChannelProp
   *
   * @param t a tuple decision variable which domain is a subset of \f$\mathcal{U}_{n}\f$
   * @param R a relation decision variable: \f$R \subseteq \mathcal{U}_{n}\f$.
   *
   * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
   * and the arity of \a t is not the same.
   */
  //void included(Gecode::Space& home, CPTupleVar t, CPRelVar R);
  /**
   * \brief Posts the constraint: \f$ t \notin R\f$
   * \ingroup ChannelProp
   *
   * @param t a tuple decision variable which domain is a subset of \f$\mathcal{U}_{n}\f$
   * @param R a relation decision variable: \f$R \subseteq \mathcal{U}_{n}\f$.
   *
   * \warning Throws an exception MPG::CPRel::ArityMissmatch if the arity of \a R
   * and the arity of \a t is not the same.
   */
  //void excluded(Gecode::Space& home, CPTupleVar t, CPRelVar R);

  void include(Gecode::Space& home, CPRelVar A, GRelation R);

  void exclude(Gecode::Space& home, CPRelVar A, GRelation R);
  /**
   * \brief Simple branching on relations.
   * \ingroup RelBranch
   *
   * Branches on relation  \a R by selecting a tuple in it and creating a choice with
   * the tuple as part of the relation for the first alternative and the tuple as
   * excluded from the relation as the second alternative.
   *
   * @param R a relation decision variable.
   *
   */
  void branch(Gecode::Home home, CPRelVar R);
}
#endif
<|endoftext|>


<commit_before>#include "union_storage.h"
#include "storage/memstorage.h"
#include "storage/capacitor.h"
#include "utils/exception.h"
#include "utils/locker.h"
#include "storage/page_manager.h"
#include <cassert>

using namespace dariadb;
using namespace dariadb::storage;

class UnionStorage::Private {
public:
	Private(const PageManager::Params&page_storage_params,
		dariadb::storage::Capacitor::Params cap_params,
		dariadb::storage::UnionStorage::Limits limits) :
		mem_storage{ new MemoryStorage(page_storage_params.chunk_size) },
		_page_manager_params(page_storage_params),
		_cap_params(cap_params),
       _limits(limits)
	{
		dariadb::storage::ChunkPool::instance()->start(_limits.max_mem_chunks);

		mem_cap = new Capacitor(mem_storage, _cap_params);
		mem_storage_raw = dynamic_cast<MemoryStorage*>(mem_storage.get());
		assert(mem_storage_raw != nullptr);

		PageManager::start(_page_manager_params);

		auto open_chunks = PageManager::instance()->get_open_chunks();
        mem_storage_raw->append(open_chunks);
	}
	~Private() {
		this->flush();
        if (_limits.max_mem_chunks != 0) {
            auto all_chunks = this->mem_storage_raw->drop_all();
            PageManager::instance()->append(all_chunks); //use specified in ctor
        }
		delete mem_cap;
		PageManager::stop();

	}

	Time minTime() {
        std::lock_guard<std::mutex> lg(_locker);
        if(PageManager::instance()->chunks_in_cur_page()>0){
            return PageManager::instance()->minTime();
        }else{
            return mem_storage->minTime();
        }
	}

	Time maxTime() {
		return mem_storage->maxTime();
	}

	append_result append(const Meas::PMeas begin, const size_t size) {
		append_result result{};
		for (size_t i = 0; i < size; i++) {
			result = result + this->append(begin[i]);
		}
		return result;
	}

	append_result append(const Meas &value) {
		//std::lock_guard<std::mutex> lg(_locker);
		append_result result{};
        if (!mem_cap->append(value)){
        //if(mem_storage_raw->append(value).writed!=1){
			result.ignored++;
		}
		else {
			result.writed++;
		}

        drop_old_chunks();
		return result;
	}

	void drop_old_chunks() {
		if (_limits.max_mem_chunks == 0) {
			if (_limits.old_mem_chunks != 0) {
                std::lock_guard<std::mutex> lg(_drop_locker);
				auto old_chunks = mem_storage_raw->drop_old_chunks(_limits.old_mem_chunks);
                PageManager::instance()->append(old_chunks);
			}
		}
		else {
            std::lock_guard<std::mutex> lg(_drop_locker);
			auto old_chunks = mem_storage_raw->drop_old_chunks_by_limit(_limits.max_mem_chunks);
            PageManager::instance()->append(old_chunks);
		}
	}

	void subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
		mem_storage->subscribe(ids, flag, clbk);
	}

	Reader_ptr currentValue(const IdArray&ids, const Flag& flag) {
		return mem_storage->currentValue(ids, flag);
	}

	void flush() {
        std::lock_guard<std::mutex> lg(_locker);
		this->mem_cap->flush();
		this->drop_old_chunks();
	}

	class UnionCursor : public Cursor {
	public:
		Cursor_ptr _page_cursor;
		Cursor_ptr _mem_cursor;
		UnionCursor(Cursor_ptr &page_cursor, Cursor_ptr&mem_cursor):
			_page_cursor{page_cursor},
			_mem_cursor(mem_cursor)
		{
			this->reset_pos();
		}
		~UnionCursor() {
			_page_cursor = nullptr;
			_mem_cursor = nullptr;
		}

		bool is_end()const override {
			return
				(_page_cursor==nullptr?true:_page_cursor->is_end())
				&& (_mem_cursor==nullptr?true:_mem_cursor->is_end());
		}

		void readNext(Cursor::Callback*cbk)  override
		{
			if (!is_end()) {
				if ((_page_cursor!=nullptr) && (!_page_cursor->is_end())) {
					_page_cursor->readNext(cbk);
					return;
				}
				else
				{
					if ((_mem_cursor!=nullptr)&&(!_mem_cursor->is_end())) {
						_mem_cursor->readNext(cbk);
						return;
					}
				}
			}
            Chunk_Ptr empty;
            cbk->call(empty);
		}

		void reset_pos() override {
			if (_page_cursor != nullptr) {
				_page_cursor->reset_pos();
			}
			if (_mem_cursor != nullptr) {
				_mem_cursor->reset_pos();
			}
		}
	};

	Cursor_ptr chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
        std::lock_guard<std::mutex> lg(_locker);
		Cursor_ptr page_chunks, mem_chunks;
		if (from < mem_storage_raw->minTime()) {
			page_chunks = PageManager::instance()->chunksByIterval(ids, flag, from, to);
		}
        if (to > mem_storage_raw->minTime())
        {
			mem_chunks = mem_storage_raw->chunksByIterval(ids, flag, from, to);
		}

		Cursor_ptr result{ new UnionCursor{page_chunks,mem_chunks} };

		return result;
	}

	IdToChunkMap chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
        std::lock_guard<std::mutex> lg(_locker);
		if (timePoint < mem_storage_raw->minTime()) {
			return PageManager::instance()->chunksBeforeTimePoint(ids, flag, timePoint);
		}
		else {
			return mem_storage_raw->chunksBeforeTimePoint(ids, flag, timePoint);
		}
	}
	IdArray getIds() {
        std::lock_guard<std::mutex> lg(_locker);
		auto page_ids = PageManager::instance()->getIds();
		auto mem_ids = mem_storage_raw->getIds();
		dariadb::IdSet s;
		for (auto v : page_ids) {
			s.insert(v);
		}
		for (auto v : mem_ids) {
			s.insert(v);
		}
		return dariadb::IdArray{ s.begin(),s.end() };
	}

    size_t chunks_in_memory()const{
        std::lock_guard<std::mutex> lg(_locker);
        return mem_storage_raw->chunks_total_size();
    }

	storage::BaseStorage_ptr mem_storage;
	storage::MemoryStorage* mem_storage_raw;
	storage::Capacitor* mem_cap;

	storage::PageManager::Params _page_manager_params;
	dariadb::storage::Capacitor::Params _cap_params;
	dariadb::storage::UnionStorage::Limits _limits;
    mutable std::mutex _locker, _drop_locker;
};

UnionStorage::UnionStorage(storage::PageManager::Params page_manager_params,
	dariadb::storage::Capacitor::Params cap_params,
    const dariadb::storage::UnionStorage::Limits&limits):
	_impl{ new UnionStorage::Private(page_manager_params,
									cap_params, limits) }
{
}

UnionStorage::~UnionStorage() {
    _impl=nullptr;
}

Time UnionStorage::minTime() {
	return _impl->minTime();
}

Time UnionStorage::maxTime() {
	return _impl->maxTime();
}

append_result UnionStorage::append(const Meas::PMeas begin, const size_t size) {
	return _impl->append(begin, size);
}

append_result UnionStorage::append(const Meas &value) {
	return _impl->append(value);
}

void UnionStorage::subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
	_impl->subscribe(ids, flag, clbk);
}

Reader_ptr UnionStorage::currentValue(const IdArray&ids, const Flag& flag) {
	return _impl->currentValue(ids, flag);
}

void  UnionStorage::flush() {
	_impl->flush();
}

Cursor_ptr UnionStorage::chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
	return _impl->chunksByIterval(ids, flag, from, to);
}

IdToChunkMap UnionStorage::chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
	return _impl->chunksBeforeTimePoint(ids, flag, timePoint);
}

IdArray UnionStorage::getIds() {
	return _impl->getIds();
}

size_t UnionStorage::chunks_in_memory()const{
    return _impl->chunks_in_memory();
}
<commit_msg>union_storage: don lock when drop.<commit_after>#include "union_storage.h"
#include "storage/memstorage.h"
#include "storage/capacitor.h"
#include "utils/exception.h"
#include "utils/locker.h"
#include "storage/page_manager.h"
#include <cassert>

using namespace dariadb;
using namespace dariadb::storage;

class UnionStorage::Private {
public:
	Private(const PageManager::Params&page_storage_params,
		dariadb::storage::Capacitor::Params cap_params,
		dariadb::storage::UnionStorage::Limits limits) :
		mem_storage{ new MemoryStorage(page_storage_params.chunk_size) },
		_page_manager_params(page_storage_params),
		_cap_params(cap_params),
       _limits(limits)
	{
		dariadb::storage::ChunkPool::instance()->start(_limits.max_mem_chunks);

		mem_cap = new Capacitor(mem_storage, _cap_params);
		mem_storage_raw = dynamic_cast<MemoryStorage*>(mem_storage.get());
		assert(mem_storage_raw != nullptr);

		PageManager::start(_page_manager_params);

		auto open_chunks = PageManager::instance()->get_open_chunks();
        mem_storage_raw->append(open_chunks);
	}
	~Private() {
		this->flush();
        if (_limits.max_mem_chunks != 0) {
            auto all_chunks = this->mem_storage_raw->drop_all();
            PageManager::instance()->append(all_chunks); //use specified in ctor
        }
		delete mem_cap;
		PageManager::stop();

	}

	Time minTime() {
        std::lock_guard<std::mutex> lg(_locker);
        if(PageManager::instance()->chunks_in_cur_page()>0){
            return PageManager::instance()->minTime();
        }else{
            return mem_storage->minTime();
        }
	}

	Time maxTime() {
		return mem_storage->maxTime();
	}

	append_result append(const Meas::PMeas begin, const size_t size) {
		append_result result{};
		for (size_t i = 0; i < size; i++) {
			result = result + this->append(begin[i]);
		}
		return result;
	}

	append_result append(const Meas &value) {
		//std::lock_guard<std::mutex> lg(_locker);
		append_result result{};
        if (!mem_cap->append(value)){
        //if(mem_storage_raw->append(value).writed!=1){
			result.ignored++;
		}
		else {
			result.writed++;
		}

        drop_old_chunks();
		return result;
	}

	void drop_old_chunks() {
		if (_limits.max_mem_chunks == 0) {
			if (_limits.old_mem_chunks != 0) {
                //std::lock_guard<std::mutex> lg(_drop_locker);
				auto old_chunks = mem_storage_raw->drop_old_chunks(_limits.old_mem_chunks);
                PageManager::instance()->append(old_chunks);
			}
		}
		else {
            //std::lock_guard<std::mutex> lg(_drop_locker);
			auto old_chunks = mem_storage_raw->drop_old_chunks_by_limit(_limits.max_mem_chunks);
            PageManager::instance()->append(old_chunks);
		}
	}

	void subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
		mem_storage->subscribe(ids, flag, clbk);
	}

	Reader_ptr currentValue(const IdArray&ids, const Flag& flag) {
		return mem_storage->currentValue(ids, flag);
	}

	void flush() {
        std::lock_guard<std::mutex> lg(_locker);
		this->mem_cap->flush();
		this->drop_old_chunks();
	}

	class UnionCursor : public Cursor {
	public:
		Cursor_ptr _page_cursor;
		Cursor_ptr _mem_cursor;
		UnionCursor(Cursor_ptr &page_cursor, Cursor_ptr&mem_cursor):
			_page_cursor{page_cursor},
			_mem_cursor(mem_cursor)
		{
			this->reset_pos();
		}
		~UnionCursor() {
			_page_cursor = nullptr;
			_mem_cursor = nullptr;
		}

		bool is_end()const override {
			return
				(_page_cursor==nullptr?true:_page_cursor->is_end())
				&& (_mem_cursor==nullptr?true:_mem_cursor->is_end());
		}

		void readNext(Cursor::Callback*cbk)  override
		{
			if (!is_end()) {
				if ((_page_cursor!=nullptr) && (!_page_cursor->is_end())) {
					_page_cursor->readNext(cbk);
					return;
				}
				else
				{
					if ((_mem_cursor!=nullptr)&&(!_mem_cursor->is_end())) {
						_mem_cursor->readNext(cbk);
						return;
					}
				}
			}
            Chunk_Ptr empty;
            cbk->call(empty);
		}

		void reset_pos() override {
			if (_page_cursor != nullptr) {
				_page_cursor->reset_pos();
			}
			if (_mem_cursor != nullptr) {
				_mem_cursor->reset_pos();
			}
		}
	};

	Cursor_ptr chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
        std::lock_guard<std::mutex> lg(_locker);
		Cursor_ptr page_chunks, mem_chunks;
		if (from < mem_storage_raw->minTime()) {
			page_chunks = PageManager::instance()->chunksByIterval(ids, flag, from, to);
		}
        if (to > mem_storage_raw->minTime())
        {
			mem_chunks = mem_storage_raw->chunksByIterval(ids, flag, from, to);
		}

		Cursor_ptr result{ new UnionCursor{page_chunks,mem_chunks} };

		return result;
	}

	IdToChunkMap chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
        std::lock_guard<std::mutex> lg(_locker);
		if (timePoint < mem_storage_raw->minTime()) {
			return PageManager::instance()->chunksBeforeTimePoint(ids, flag, timePoint);
		}
		else {
			return mem_storage_raw->chunksBeforeTimePoint(ids, flag, timePoint);
		}
	}
	IdArray getIds() {
        std::lock_guard<std::mutex> lg(_locker);
		auto page_ids = PageManager::instance()->getIds();
		auto mem_ids = mem_storage_raw->getIds();
		dariadb::IdSet s;
		for (auto v : page_ids) {
			s.insert(v);
		}
		for (auto v : mem_ids) {
			s.insert(v);
		}
		return dariadb::IdArray{ s.begin(),s.end() };
	}

    size_t chunks_in_memory()const{
        std::lock_guard<std::mutex> lg(_locker);
        return mem_storage_raw->chunks_total_size();
    }

	storage::BaseStorage_ptr mem_storage;
	storage::MemoryStorage* mem_storage_raw;
	storage::Capacitor* mem_cap;

	storage::PageManager::Params _page_manager_params;
	dariadb::storage::Capacitor::Params _cap_params;
	dariadb::storage::UnionStorage::Limits _limits;
    mutable std::mutex _locker, _drop_locker;
};

UnionStorage::UnionStorage(storage::PageManager::Params page_manager_params,
	dariadb::storage::Capacitor::Params cap_params,
    const dariadb::storage::UnionStorage::Limits&limits):
	_impl{ new UnionStorage::Private(page_manager_params,
									cap_params, limits) }
{
}

UnionStorage::~UnionStorage() {
    _impl=nullptr;
}

Time UnionStorage::minTime() {
	return _impl->minTime();
}

Time UnionStorage::maxTime() {
	return _impl->maxTime();
}

append_result UnionStorage::append(const Meas::PMeas begin, const size_t size) {
	return _impl->append(begin, size);
}

append_result UnionStorage::append(const Meas &value) {
	return _impl->append(value);
}

void UnionStorage::subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
	_impl->subscribe(ids, flag, clbk);
}

Reader_ptr UnionStorage::currentValue(const IdArray&ids, const Flag& flag) {
	return _impl->currentValue(ids, flag);
}

void  UnionStorage::flush() {
	_impl->flush();
}

Cursor_ptr UnionStorage::chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
	return _impl->chunksByIterval(ids, flag, from, to);
}

IdToChunkMap UnionStorage::chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
	return _impl->chunksBeforeTimePoint(ids, flag, timePoint);
}

IdArray UnionStorage::getIds() {
	return _impl->getIds();
}

size_t UnionStorage::chunks_in_memory()const{
    return _impl->chunks_in_memory();
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh/libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "libmesh/boundary_info.h"
#include "libmesh/elem.h"
#include "libmesh/mesh_base.h"
#include "libmesh/parallel.h"
#include "libmesh/partitioner.h"
#include "libmesh/point_locator_base.h"
#include "libmesh/threads.h"

namespace libMesh
{

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (unsigned int d) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _dim           (d),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
  _skip_partitioning(false),
  _skip_renumber_nodes_and_elements(false)
{
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, _dim);
  libmesh_assert (libMesh::initialized());
}

MeshBase::MeshBase (const MeshBase& other_mesh) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (other_mesh._n_parts),
  _dim           (other_mesh._dim),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL),
  _skip_partitioning(other_mesh._skip_partitioning),
  _skip_renumber_nodes_and_elements(false)
{
  if(other_mesh._partitioner.get())
  {
    _partitioner = other_mesh._partitioner->clone();
  }
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_assert (!libMesh::closed());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements)
{
  parallel_only();

  // A distributed mesh may have processors with no elements (or
  // processors with no elements of higher dimension, if we ever
  // support mixed-dimension meshes), but we want consistent
  // mesh_dimension anyways.
  libmesh_assert(Parallel::verify(this->is_serial()));

  if (!this->is_serial())
    {
      unsigned int dim = this->mesh_dimension();
      Parallel::max(dim);
      this->set_mesh_dimension(dim);
    }

  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, _skip_renumber_nodes_and_elements is false.
  //
  // We may currently change that by passing
  // skip_renumber_nodes_and_elements==true to this function, but we
  // should use the allow_renumbering() accessor instead.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.

  if (skip_renumber_nodes_and_elements)
    {
      libmesh_deprecated();
      this->allow_renumbering(false);
    }

  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Let all the elements find their neighbors
  this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

void MeshBase::clear ()
{
  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->boundary_info->clear();

  // Clear our point locator.
  this->clear_point_locator();
}

unsigned int MeshBase::n_subdomains() const
{
  // This requires an inspection on every processor
  parallel_only();

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  std::set<unsigned int> subdomain_ids;

  for (; el!=end; ++el)
    subdomain_ids.insert((*el)->subdomain_id());

  // Some subdomains may only live on other processors
  Parallel::set_union(subdomain_ids, 0);

  unsigned int n_sbd_ids = subdomain_ids.size();
  Parallel::broadcast(n_sbd_ids);

  return n_sbd_ids;
}

unsigned int MeshBase::n_nodes_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_nodes_begin(proc_id),
						  this->pid_nodes_end  (proc_id)));
}

unsigned int MeshBase::n_elem_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_elements_begin(proc_id),
						  this->pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_active_elem_on_proc (const unsigned int proc_id) const
{
  libmesh_assert_less (proc_id, libMesh::n_processors());
  return static_cast<unsigned int>(std::distance (this->active_pid_elements_begin(proc_id),
						  this->active_pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

unsigned int MeshBase::n_active_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream out;

  out << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << this->n_subdomains()      << '\n'
      << "  n_partitions()="      << this->n_partitions()      << '\n'
      << "  n_processors()="      << libMesh::n_processors()   << '\n'
      << "  n_threads()="         << libMesh::n_threads()      << '\n'
      << "  processor_id()="      << this->processor_id()      << '\n';

  return out.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  // NULL partitioner means don't partition
  // Non-serial meshes aren't ready for partitioning yet.
  if(!skip_partitioning() &&
     partitioner().get() &&
     this->is_serial())
  {
    partitioner()->partition (*this, n_parts);
  }
  else
  {
    // Make sure locally cached partition count
    this->recalculate_n_partitions();

    // Make sure any other locally cached data is correct
    this->update_post_partitioning();
  }
}

unsigned int MeshBase::recalculate_n_partitions()
{
  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  Parallel::max(_n_parts);

  return _n_parts;
}

const PointLocatorBase& MeshBase::point_locator () const
{
  libmesh_deprecated();

  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE, *this).release());
    }

  return *_point_locator;
}

AutoPtr<PointLocatorBase> MeshBase::sub_point_locator () const
{
  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE, *this).release());
    }

  return PointLocatorBase::build(TREE, *this, _point_locator.get());
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

std::string& MeshBase::subdomain_name(subdomain_id_type id)
{
  return _block_id_to_name[id];
}

const std::string& MeshBase::subdomain_name(subdomain_id_type id) const
{
  // An empty string to return when no matching subdomain name is found
  static const std::string empty;

  std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id);
  if (iter == _block_id_to_name.end())
    return empty;
  else
    return iter->second;
}

subdomain_id_type MeshBase::get_id_by_name(const std::string& name) const
{
  // This function is searching the *values* of the map (linear search)
  // We might want to make this more efficient...
  std::map<subdomain_id_type, std::string>::const_iterator
    iter = _block_id_to_name.begin(),
    end_iter = _block_id_to_name.end();

  for ( ; iter != end_iter; ++iter)
    {
      if (iter->second == name)
        return iter->first;
    }

  libMesh::err << "Block '" << name << "' does not exist in mesh" << std::endl;
  libmesh_error();
}

} // namespace libMesh

<commit_msg>Always update parallel id counts in prepare_for_use<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh/libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "libmesh/boundary_info.h"
#include "libmesh/elem.h"
#include "libmesh/mesh_base.h"
#include "libmesh/parallel.h"
#include "libmesh/partitioner.h"
#include "libmesh/point_locator_base.h"
#include "libmesh/threads.h"

namespace libMesh
{

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (unsigned int d) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _dim           (d),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
  _skip_partitioning(false),
  _skip_renumber_nodes_and_elements(false)
{
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, _dim);
  libmesh_assert (libMesh::initialized());
}

MeshBase::MeshBase (const MeshBase& other_mesh) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (other_mesh._n_parts),
  _dim           (other_mesh._dim),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL),
  _skip_partitioning(other_mesh._skip_partitioning),
  _skip_renumber_nodes_and_elements(false)
{
  if(other_mesh._partitioner.get())
  {
    _partitioner = other_mesh._partitioner->clone();
  }
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_assert (!libMesh::closed());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements)
{
  parallel_only();

  // A distributed mesh may have processors with no elements (or
  // processors with no elements of higher dimension, if we ever
  // support mixed-dimension meshes), but we want consistent
  // mesh_dimension anyways.
  libmesh_assert(Parallel::verify(this->is_serial()));

  if (!this->is_serial())
    {
      unsigned int dim = this->mesh_dimension();
      Parallel::max(dim);
      this->set_mesh_dimension(dim);
    }

  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, _skip_renumber_nodes_and_elements is false.
  //
  // We may currently change that by passing
  // skip_renumber_nodes_and_elements==true to this function, but we
  // should use the allow_renumbering() accessor instead.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.

  if (skip_renumber_nodes_and_elements)
    {
      libmesh_deprecated();
      this->allow_renumbering(false);
    }

  // Mesh modification operations might not leave us with consistent
  // id counts, but our partitioner might need that consistency.
  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();
  else
    this->update_parallel_id_counts();

  // Let all the elements find their neighbors
  this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

void MeshBase::clear ()
{
  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->boundary_info->clear();

  // Clear our point locator.
  this->clear_point_locator();
}

unsigned int MeshBase::n_subdomains() const
{
  // This requires an inspection on every processor
  parallel_only();

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  std::set<unsigned int> subdomain_ids;

  for (; el!=end; ++el)
    subdomain_ids.insert((*el)->subdomain_id());

  // Some subdomains may only live on other processors
  Parallel::set_union(subdomain_ids, 0);

  unsigned int n_sbd_ids = subdomain_ids.size();
  Parallel::broadcast(n_sbd_ids);

  return n_sbd_ids;
}

unsigned int MeshBase::n_nodes_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_nodes_begin(proc_id),
						  this->pid_nodes_end  (proc_id)));
}

unsigned int MeshBase::n_elem_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_elements_begin(proc_id),
						  this->pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_active_elem_on_proc (const unsigned int proc_id) const
{
  libmesh_assert_less (proc_id, libMesh::n_processors());
  return static_cast<unsigned int>(std::distance (this->active_pid_elements_begin(proc_id),
						  this->active_pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

unsigned int MeshBase::n_active_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream out;

  out << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << this->n_subdomains()      << '\n'
      << "  n_partitions()="      << this->n_partitions()      << '\n'
      << "  n_processors()="      << libMesh::n_processors()   << '\n'
      << "  n_threads()="         << libMesh::n_threads()      << '\n'
      << "  processor_id()="      << this->processor_id()      << '\n';

  return out.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  // NULL partitioner means don't partition
  // Non-serial meshes aren't ready for partitioning yet.
  if(!skip_partitioning() &&
     partitioner().get() &&
     this->is_serial())
  {
    partitioner()->partition (*this, n_parts);
  }
  else
  {
    // Make sure locally cached partition count
    this->recalculate_n_partitions();

    // Make sure any other locally cached data is correct
    this->update_post_partitioning();
  }
}

unsigned int MeshBase::recalculate_n_partitions()
{
  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  Parallel::max(_n_parts);

  return _n_parts;
}

const PointLocatorBase& MeshBase::point_locator () const
{
  libmesh_deprecated();

  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE, *this).release());
    }

  return *_point_locator;
}

AutoPtr<PointLocatorBase> MeshBase::sub_point_locator () const
{
  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE, *this).release());
    }

  return PointLocatorBase::build(TREE, *this, _point_locator.get());
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

std::string& MeshBase::subdomain_name(subdomain_id_type id)
{
  return _block_id_to_name[id];
}

const std::string& MeshBase::subdomain_name(subdomain_id_type id) const
{
  // An empty string to return when no matching subdomain name is found
  static const std::string empty;

  std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id);
  if (iter == _block_id_to_name.end())
    return empty;
  else
    return iter->second;
}

subdomain_id_type MeshBase::get_id_by_name(const std::string& name) const
{
  // This function is searching the *values* of the map (linear search)
  // We might want to make this more efficient...
  std::map<subdomain_id_type, std::string>::const_iterator
    iter = _block_id_to_name.begin(),
    end_iter = _block_id_to_name.end();

  for ( ; iter != end_iter; ++iter)
    {
      if (iter->second == name)
        return iter->first;
    }

  libMesh::err << "Block '" << name << "' does not exist in mesh" << std::endl;
  libmesh_error();
}

} // namespace libMesh

<|endoftext|>


<commit_before><commit_msg>gltfio: Fix animator crash for orphaned nodes.<commit_after><|endoftext|>


<commit_before>/**
 * @file   ModelLayer.hpp
 * @brief  ModelLayer class prototype.
 * @author zer0
 * @date   2018-10-22
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Noncopyable.hpp>
#include <libtbag/Err.hpp>
#include <libtbag/Type.hpp>
#include <libtbag/util/BufferInfo.hpp>

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace graph {

// Forward declarations.
class ModelNet;
class ModelLayer;

/**
 * LayerBase class prototype.
 *
 * @author zer0
 * @date   2018-10-23
 */
class LayerBase
{
public:
    friend class ModelLayer;

public:
    using Err = libtbag::Err;
    using Layers = std::vector<ModelLayer>;

public:
    TBAG_CONSTEXPR static int const NO_ASSIGN_ID = -1;
    TBAG_CONSTEXPR static int const DEFAULT_PROPERTY_BUFFER_SIZE = 1024;

private:
    /**
     * Layer class type.
     *
     * @warning
     *  Initialization using static strings is required.
     */
    char const * const TYPE;

private:
    /**
     * Layer instance id.
     *
     * @warning
     *  This value is assigned when added to the model. @n
     *  The user should not modify this value.
     */
    int _assign_id = NO_ASSIGN_ID;

    /**
     * Whether the operation(forward or backward) is complete.
     *
     * @warning
     *  This value is controlled by the model. @n
     *  The user should not modify this value.
     */
    bool _complete = false;

public:
    /** User's data. */
    void * opaque = nullptr;

public:
    LayerBase() : TYPE("UNKNOWN") { /* EMPTY. */ }
    LayerBase(char const * const & type) : TYPE(type) { /* EMPTY. */ }
    virtual ~LayerBase() { /* EMPTY. */ }

public:
    inline char const * type() const TBAG_NOEXCEPT
    { return TYPE; }

public:
    inline int id() const TBAG_NOEXCEPT
    { return _assign_id; }

    inline bool complete() const TBAG_NOEXCEPT
    { return _complete; }

public:
    virtual Err setup(char const * data, int size) { return E_SUCCESS; }
    virtual Err teardown() { return E_SUCCESS; }

    virtual Err forward(Layers const & input) { return E_SUCCESS; }
    virtual Err backward(Layers const & input) { return E_SUCCESS; }

    virtual Err get(char const * key, char * buffer, int * size) const { return E_SUCCESS; }
    virtual Err set(char const * key, char const * data) { return E_SUCCESS; }
};

/**
 * ModelLayer class prototype.
 *
 * @author zer0
 * @date   2018-10-22
 */
class TBAG_API ModelLayer
{
public:
    friend class ModelNet;

public:
    using Err = libtbag::Err;
    using Layers = std::vector<ModelLayer>;
    using SharedBase = std::shared_ptr<LayerBase>;

private:
    SharedBase _base;

public:
    ModelLayer();
    explicit ModelLayer(std::nullptr_t) TBAG_NOEXCEPT;
    explicit ModelLayer(LayerBase * base) TBAG_NOEXCEPT;
    explicit ModelLayer(SharedBase const & base) TBAG_NOEXCEPT;
    ModelLayer(ModelLayer const & obj) TBAG_NOEXCEPT;
    ModelLayer(ModelLayer && obj) TBAG_NOEXCEPT;
    ~ModelLayer();

public:
    ModelLayer & operator =(ModelLayer const & obj) TBAG_NOEXCEPT;
    ModelLayer & operator =(ModelLayer && obj) TBAG_NOEXCEPT;

public:
    void copy(ModelLayer const & obj) TBAG_NOEXCEPT;
    void swap(ModelLayer & obj) TBAG_NOEXCEPT;

public:
    inline friend void swap(ModelLayer & lh, ModelLayer & rh) TBAG_NOEXCEPT
    { lh.swap(rh); }

public:
    inline LayerBase       * get()       TBAG_NOEXCEPT { return _base.get(); }
    inline LayerBase const * get() const TBAG_NOEXCEPT { return _base.get(); }

    inline LayerBase       * operator ->()       TBAG_NOEXCEPT { return get(); }
    inline LayerBase const * operator ->() const TBAG_NOEXCEPT { return get(); }

    inline LayerBase       & ref()       TBAG_NOEXCEPT { return *get(); }
    inline LayerBase const & ref() const TBAG_NOEXCEPT { return *get(); }

    inline LayerBase       & operator *()       TBAG_NOEXCEPT { return ref(); }
    inline LayerBase const & operator *() const TBAG_NOEXCEPT { return ref(); }

public:
    inline bool exists() const TBAG_NOEXCEPT
    { return static_cast<bool>(_base); }

    inline operator bool() const TBAG_NOEXCEPT
    { return exists(); }

public:
    friend inline bool operator <(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() < y.get(); }

    friend inline bool operator >(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() > y.get(); }

    friend inline bool operator <=(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() <= y.get(); }

    friend inline bool operator >=(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() >= y.get(); }

    inline bool operator ==(ModelLayer const & obj) const TBAG_NOEXCEPT
    { return get() == obj.get(); }

    inline bool operator !=(ModelLayer const & obj) const TBAG_NOEXCEPT
    { return get() != obj.get(); }

private:
    void _complete();
    void _incomplete();
    void _assign_id(int id);

public:
    char const * type() const;

public:
    int id() const;
    bool isComplete() const;

public:
    Err setup(std::string const & data);
    Err teardown();

public:
    Err forward(Layers const & input);
    Err backward(Layers const & input);

public:
    Err get(std::string const & key, std::string & data) const;
    Err set(std::string const & key, std::string const & data);

public:
    std::string toString() const;

public:
    template <typename LayerType, typename ... Args>
    static ModelLayer create(Args && ... args)
    {
        STATIC_ASSERT_CHECK_IS_BASE_OF(LayerBase, LayerType);
        STATIC_ASSERT_CHECK_IS_DEFAULT_CONSTRUCTIBLE(LayerType);
        typedef typename libtbag::remove_cr<LayerType>::type ResultLayerType;

        auto shared = std::make_shared<ResultLayerType>(std::forward<Args>(args) ...);
        if (static_cast<bool>(shared)) {
            return ModelLayer(std::static_pointer_cast<LayerBase>(shared));
        }
        return ModelLayer(nullptr);
    }
};

} // namespace graph

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__

<commit_msg>Create LayerBase::getProperty() methods.<commit_after>/**
 * @file   ModelLayer.hpp
 * @brief  ModelLayer class prototype.
 * @author zer0
 * @date   2018-10-22
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Noncopyable.hpp>
#include <libtbag/Err.hpp>
#include <libtbag/Type.hpp>
#include <libtbag/util/BufferInfo.hpp>

#include <cstdint>
#include <cstring>

#include <memory>
#include <string>
#include <vector>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace graph {

// Forward declarations.
class ModelNet;
class ModelLayer;

/**
 * LayerBase class prototype.
 *
 * @author zer0
 * @date   2018-10-23
 */
class LayerBase
{
public:
    friend class ModelLayer;

public:
    using Err = libtbag::Err;
    using Layers = std::vector<ModelLayer>;

public:
    TBAG_CONSTEXPR static int const NO_ASSIGN_ID = -1;
    TBAG_CONSTEXPR static int const DEFAULT_PROPERTY_BUFFER_SIZE = 1024;

private:
    /**
     * Layer class type.
     *
     * @warning
     *  Initialization using static strings is required.
     */
    char const * const TYPE;

private:
    /**
     * Layer instance id.
     *
     * @warning
     *  This value is assigned when added to the model. @n
     *  The user should not modify this value.
     */
    int _assign_id = NO_ASSIGN_ID;

    /**
     * Whether the operation(forward or backward) is complete.
     *
     * @warning
     *  This value is controlled by the model. @n
     *  The user should not modify this value.
     */
    bool _complete = false;

public:
    /** User's data. */
    void * opaque = nullptr;

public:
    LayerBase() : TYPE("UNKNOWN") { /* EMPTY. */ }
    LayerBase(char const * const & type) : TYPE(type) { /* EMPTY. */ }
    virtual ~LayerBase() { /* EMPTY. */ }

public:
    inline char const * type() const TBAG_NOEXCEPT
    { return TYPE; }

public:
    inline int id() const TBAG_NOEXCEPT
    { return _assign_id; }

    inline bool complete() const TBAG_NOEXCEPT
    { return _complete; }

public:
    virtual Err setup(char const * data, int size) { return E_SUCCESS; }
    virtual Err teardown() { return E_SUCCESS; }

    virtual Err forward(Layers const & input) { return E_SUCCESS; }
    virtual Err backward(Layers const & input) { return E_SUCCESS; }

    virtual Err get(char const * key, char * buffer, int * size) const { return E_SUCCESS; }
    virtual Err set(char const * key, char const * data) { return E_SUCCESS; }

public:
    static Err getProperty(char * buffer, int * buffer_size, char const * value, int value_size)
    {
        if (*buffer_size >= value_size) {
            ::strncpy(buffer, value, value_size);
            return E_SUCCESS;
        } else {
            *buffer_size = value_size;
            return E_ENOBUFS;
        }
    }

    static Err getProperty(char * buffer, int * buffer_size, char const * value)
    {
        return getProperty(buffer, buffer_size, value, ::strlen(value));
    }

    static Err getProperty(char * buffer, int * buffer_size, std::string const & str)
    {
        return getProperty(buffer, buffer_size, str.c_str(), static_cast<int>(str.size()));
    }

    template <typename T>
    static Err getProperty(char * buffer, int * buffer_size, T const & value)
    {
        return getProperty(buffer, buffer_size, std::to_string(value));
    }
};

/**
 * ModelLayer class prototype.
 *
 * @author zer0
 * @date   2018-10-22
 */
class TBAG_API ModelLayer
{
public:
    friend class ModelNet;

public:
    using Err = libtbag::Err;
    using Layers = std::vector<ModelLayer>;
    using SharedBase = std::shared_ptr<LayerBase>;

private:
    SharedBase _base;

public:
    ModelLayer();
    explicit ModelLayer(std::nullptr_t) TBAG_NOEXCEPT;
    explicit ModelLayer(LayerBase * base) TBAG_NOEXCEPT;
    explicit ModelLayer(SharedBase const & base) TBAG_NOEXCEPT;
    ModelLayer(ModelLayer const & obj) TBAG_NOEXCEPT;
    ModelLayer(ModelLayer && obj) TBAG_NOEXCEPT;
    ~ModelLayer();

public:
    ModelLayer & operator =(ModelLayer const & obj) TBAG_NOEXCEPT;
    ModelLayer & operator =(ModelLayer && obj) TBAG_NOEXCEPT;

public:
    void copy(ModelLayer const & obj) TBAG_NOEXCEPT;
    void swap(ModelLayer & obj) TBAG_NOEXCEPT;

public:
    inline friend void swap(ModelLayer & lh, ModelLayer & rh) TBAG_NOEXCEPT
    { lh.swap(rh); }

public:
    inline LayerBase       * get()       TBAG_NOEXCEPT { return _base.get(); }
    inline LayerBase const * get() const TBAG_NOEXCEPT { return _base.get(); }

    inline LayerBase       * operator ->()       TBAG_NOEXCEPT { return get(); }
    inline LayerBase const * operator ->() const TBAG_NOEXCEPT { return get(); }

    inline LayerBase       & ref()       TBAG_NOEXCEPT { return *get(); }
    inline LayerBase const & ref() const TBAG_NOEXCEPT { return *get(); }

    inline LayerBase       & operator *()       TBAG_NOEXCEPT { return ref(); }
    inline LayerBase const & operator *() const TBAG_NOEXCEPT { return ref(); }

public:
    inline bool exists() const TBAG_NOEXCEPT
    { return static_cast<bool>(_base); }

    inline operator bool() const TBAG_NOEXCEPT
    { return exists(); }

public:
    friend inline bool operator <(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() < y.get(); }

    friend inline bool operator >(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() > y.get(); }

    friend inline bool operator <=(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() <= y.get(); }

    friend inline bool operator >=(ModelLayer const & x, ModelLayer const & y) TBAG_NOEXCEPT
    { return x.get() >= y.get(); }

    inline bool operator ==(ModelLayer const & obj) const TBAG_NOEXCEPT
    { return get() == obj.get(); }

    inline bool operator !=(ModelLayer const & obj) const TBAG_NOEXCEPT
    { return get() != obj.get(); }

private:
    void _complete();
    void _incomplete();
    void _assign_id(int id);

public:
    char const * type() const;

public:
    int id() const;
    bool isComplete() const;

public:
    Err setup(std::string const & data);
    Err teardown();

public:
    Err forward(Layers const & input);
    Err backward(Layers const & input);

public:
    Err get(std::string const & key, std::string & data) const;
    Err set(std::string const & key, std::string const & data);

public:
    std::string toString() const;

public:
    template <typename LayerType, typename ... Args>
    static ModelLayer create(Args && ... args)
    {
        STATIC_ASSERT_CHECK_IS_BASE_OF(LayerBase, LayerType);
        STATIC_ASSERT_CHECK_IS_DEFAULT_CONSTRUCTIBLE(LayerType);
        typedef typename libtbag::remove_cr<LayerType>::type ResultLayerType;

        auto shared = std::make_shared<ResultLayerType>(std::forward<Args>(args) ...);
        if (static_cast<bool>(shared)) {
            return ModelLayer(std::static_pointer_cast<LayerBase>(shared));
        }
        return ModelLayer(nullptr);
    }
};

} // namespace graph

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_GRAPH_MODELLAYER_HPP__

<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/cuda/device.hpp>
#include <thrust/system_error.h>
#include <thrust/system/cuda/error.h>
#include <cuda_runtime.h>

namespace agency
{
namespace cuda
{
namespace detail
{

template<class T>
class managed_allocator
{
  private:
    device_id device_;

    const device_id& device() const
    {
      return device_;
    }

  public:
    using value_type = T;

    managed_allocator()
      : device_()
    {
      auto devices = all_devices();

      if(!devices.empty())
      {
        device_ = devices[0];
      }
    }

    managed_allocator(const managed_allocator&) = default;

    template<class U>
    managed_allocator(const managed_allocator<U>& other)
      : device_(other.device_)
    {}

    value_type* allocate(size_t n)
    {
      // switch to our device
      scoped_current_device set_current_device(device());

      value_type* result = nullptr;

      cudaError_t error = cudaMallocManaged(&result, n * sizeof(T), cudaMemAttachGlobal);

      if(error != cudaSuccess)
      {
        throw thrust::system_error(error, thrust::cuda_category(), "managed_allocator::allocate(): cudaMallocManaged");
      }

      return result;
    }

    void deallocate(value_type* ptr, size_t)
    {
      // switch to our device
      scoped_current_device set_current_device(device());

      cudaError_t error = cudaFree(ptr);

      if(error != cudaSuccess)
      {
        throw thrust::system_error(error, thrust::cuda_category(), "managed_allocator::deallocate(): cudaFree");
      }
    }

    template<class U, class... Args>
    void construct(U* ptr, Args&&... args)
    {
      // we need to synchronize with all devices before touching the ptr
      detail::wait(all_devices());

      new(ptr) U(std::forward<Args>(args)...);
    }
};

} // end detail
} // end cuda
} // end agency

<commit_msg>Make all types of managed_allocator friends<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/cuda/device.hpp>
#include <thrust/system_error.h>
#include <thrust/system/cuda/error.h>
#include <cuda_runtime.h>

namespace agency
{
namespace cuda
{
namespace detail
{

template<class T>
class managed_allocator
{
  private:
    template<class> friend class managed_allocator;

    device_id device_;

    const device_id& device() const
    {
      return device_;
    }

  public:
    using value_type = T;

    managed_allocator()
      : device_()
    {
      auto devices = all_devices();

      if(!devices.empty())
      {
        device_ = devices[0];
      }
    }

    managed_allocator(const managed_allocator&) = default;

    template<class U>
    managed_allocator(const managed_allocator<U>& other)
      : device_(other.device_)
    {}

    value_type* allocate(size_t n)
    {
      // switch to our device
      scoped_current_device set_current_device(device());

      value_type* result = nullptr;

      cudaError_t error = cudaMallocManaged(&result, n * sizeof(T), cudaMemAttachGlobal);

      if(error != cudaSuccess)
      {
        throw thrust::system_error(error, thrust::cuda_category(), "managed_allocator::allocate(): cudaMallocManaged");
      }

      return result;
    }

    void deallocate(value_type* ptr, size_t)
    {
      // switch to our device
      scoped_current_device set_current_device(device());

      cudaError_t error = cudaFree(ptr);

      if(error != cudaSuccess)
      {
        throw thrust::system_error(error, thrust::cuda_category(), "managed_allocator::deallocate(): cudaFree");
      }
    }

    template<class U, class... Args>
    void construct(U* ptr, Args&&... args)
    {
      // we need to synchronize with all devices before touching the ptr
      detail::wait(all_devices());

      new(ptr) U(std::forward<Args>(args)...);
    }
};

} // end detail
} // end cuda
} // end agency

<|endoftext|>