Liebe Gitlab-Nutzerin, lieber Gitlab-Nutzer,
es ist nun möglich sich mittels des ZIH-Logins/LDAP an unserem Dienst anzumelden. Die Konten der externen Nutzer:innen sind über den Reiter "Standard" erreichbar.
Die Administratoren


Dear Gitlab user,
it is now possible to log in to our service using the ZIH login/LDAP. The accounts of external users can be accessed via the "Standard" tab.
The administrators

Commit 98d84228 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Merge branch 'feature/tree_container' into 'master'

add extended TreeContainer implementation and replace TreeData

See merge request !193
parents 1f3895e9 a7a4301c
Pipeline #4517 failed with stage
in 15 seconds
...@@ -57,8 +57,6 @@ namespace AMDiS ...@@ -57,8 +57,6 @@ namespace AMDiS
, colBasis_(colBasis) , colBasis_(colBasis)
, updatePattern_(true) , updatePattern_(true)
{ {
operators_.init(*rowBasis_, *colBasis_);
auto const rowSize = rowBasis_->localView().maxSize(); auto const rowSize = rowBasis_->localView().maxSize();
auto const colSize = colBasis_->localView().maxSize(); auto const colSize = colBasis_->localView().maxSize();
elementMatrix_.resize(rowSize, colSize); elementMatrix_.resize(rowSize, colSize);
......
...@@ -20,13 +20,15 @@ addOperator(ContextTag contextTag, Expr const& expr, ...@@ -20,13 +20,15 @@ addOperator(ContextTag contextTag, Expr const& expr,
static_assert( Concepts::PreTreePath<ColTreePath>, static_assert( Concepts::PreTreePath<ColTreePath>,
"col must be a valid treepath, or an integer/index-constant"); "col must be a valid treepath, or an integer/index-constant");
auto i = child(this->rowBasis()->localView().tree(), makeTreePath(row)); auto i = makeTreePath(row);
auto j = child(this->colBasis()->localView().tree(), makeTreePath(col)); auto node_i = child(this->rowBasis()->localView().tree(), i);
auto j = makeTreePath(col);
auto node_j = child(this->colBasis()->localView().tree(), j);
using LocalContext = typename ContextTag::type; using LocalContext = typename ContextTag::type;
using Tr = DefaultAssemblerTraits<LocalContext, ElementMatrix>; using Tr = DefaultAssemblerTraits<LocalContext, ElementMatrix>;
auto op = makeLocalOperator<LocalContext>(expr, this->rowBasis()->gridView()); auto op = makeLocalOperator<LocalContext>(expr, this->rowBasis()->gridView());
auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), i, j)); auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), node_i, node_j));
operators_[i][j].push(contextTag, std::move(localAssembler)); operators_[i][j].push(contextTag, std::move(localAssembler));
updatePattern_ = true; updatePattern_ = true;
...@@ -47,9 +49,9 @@ assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView) ...@@ -47,9 +49,9 @@ assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView)
auto const& element = rowLocalView.element(); auto const& element = rowLocalView.element();
auto geometry = element.geometry(); auto geometry = element.geometry();
for_each_node(rowLocalView.tree(), [&](auto const& rowNode, auto) { for_each_node(rowLocalView.tree(), [&](auto const& rowNode, auto rowTp) {
for_each_node(colLocalView.tree(), [&](auto const& colNode, auto) { for_each_node(colLocalView.tree(), [&](auto const& colNode, auto colTp) {
auto& matOp = operators_[rowNode][colNode]; auto& matOp = operators_[rowTp][colTp];
if (matOp) { if (matOp) {
matOp.bind(element, geometry); matOp.bind(element, geometry);
assembleOperators(gv, element, matOp, makeMatrixAssembler(rowNode, colNode, elementMatrix_)); assembleOperators(gv, element, matOp, makeMatrixAssembler(rowNode, colNode, elementMatrix_));
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include <list> #include <list>
#include <memory> #include <memory>
#include <amdis/typetree/TreeData.hpp> #include <amdis/typetree/TreeContainer.hpp>
namespace AMDiS namespace AMDiS
{ {
...@@ -48,6 +48,8 @@ namespace AMDiS ...@@ -48,6 +48,8 @@ namespace AMDiS
/// Container for storing shared pointers to boundary conditions indexed by their position in /// Container for storing shared pointers to boundary conditions indexed by their position in
/// the basis tree, see \ref MatrixData. /// the basis tree, see \ref MatrixData.
template <class Mat, class Sol, class Rhs, class RB, class CB> template <class Mat, class Sol, class Rhs, class RB, class CB>
using BoundaryConditions = MatrixData<RB, CB, BCData<Mat, Sol, Rhs>::template type>; using BoundaryConditions
= TreeMatrix<BCData<Mat, Sol, Rhs>::template type,
typename RB::LocalView::Tree, typename CB::LocalView::Tree>;
} // end namespace AMDiS } // end namespace AMDiS
...@@ -94,7 +94,7 @@ namespace AMDiS ...@@ -94,7 +94,7 @@ namespace AMDiS
template <class Node> template <class Node>
using NodeElementData = typename NodeDataTransfer<Node, Container, Basis>::NodeElementData; using NodeElementData = typename NodeDataTransfer<Node, Container, Basis>::NodeElementData;
using ElementData = TYPEOF(makeTreeContainer<NodeElementData>(std::declval<const Tree&>())); using ElementData = TreeContainer<NodeElementData,Tree,true>;
using Interface = DataTransferInterface<Container>; using Interface = DataTransferInterface<Container>;
...@@ -138,7 +138,7 @@ namespace AMDiS ...@@ -138,7 +138,7 @@ namespace AMDiS
/// Data transfer on a single basis node /// Data transfer on a single basis node
template <class Node> template <class Node>
using NDT = NodeDataTransfer<Node, Container, Basis>; using NDT = NodeDataTransfer<Node, Container, Basis>;
using NodeDataTransferContainer = TYPEOF(makeTreeContainer<NDT>(std::declval<const Tree&>())); using NodeDataTransferContainer = TreeContainer<NDT,Tree,true>;
NodeDataTransferContainer nodeDataTransfer_; NodeDataTransferContainer nodeDataTransfer_;
}; };
......
...@@ -46,7 +46,7 @@ template <class C, class B> ...@@ -46,7 +46,7 @@ template <class C, class B>
DataTransfer<C,B>::DataTransfer(std::shared_ptr<B const> basis) DataTransfer<C,B>::DataTransfer(std::shared_ptr<B const> basis)
: basis_(std::move(basis)) : basis_(std::move(basis))
, mapper_(basis_->gridView().grid(), Dune::mcmgElementLayout()) , mapper_(basis_->gridView().grid(), Dune::mcmgElementLayout())
, nodeDataTransfer_(makeTreeContainer<NDT>(basis_->localView().tree())) , nodeDataTransfer_()
{} {}
...@@ -66,7 +66,7 @@ preAdapt(C const& coeff, bool mightCoarsen) ...@@ -66,7 +66,7 @@ preAdapt(C const& coeff, bool mightCoarsen)
persistentContainer_.clear(); // Redundant if postAdapt was correctly called last cycle persistentContainer_.clear(); // Redundant if postAdapt was correctly called last cycle
for (const auto& e : elements(gv)) for (const auto& e : elements(gv))
{ {
auto it = persistentContainer_.emplace(idSet.id(e), makeTreeContainer<NodeElementData>(lv.tree())); auto it = persistentContainer_.emplace(idSet.id(e), makeTreeContainer<NodeElementData,true>(lv.tree()));
lv.bind(e); lv.bind(e);
auto& treeContainer = it.first->second; auto& treeContainer = it.first->second;
...@@ -88,7 +88,7 @@ preAdapt(C const& coeff, bool mightCoarsen) ...@@ -88,7 +88,7 @@ preAdapt(C const& coeff, bool mightCoarsen)
while (father.mightVanish() && father.hasFather()) while (father.mightVanish() && father.hasFather())
{ {
father = father.father(); father = father.father();
auto it = persistentContainer_.emplace(idSet.id(father), makeTreeContainer<NodeElementData>(lv.tree())); auto it = persistentContainer_.emplace(idSet.id(father), makeTreeContainer<NodeElementData,true>(lv.tree()));
if (!it.second) if (!it.second)
continue; continue;
......
...@@ -44,8 +44,6 @@ namespace AMDiS ...@@ -44,8 +44,6 @@ namespace AMDiS
: Super(*basis) : Super(*basis)
, basis_(basis) , basis_(basis)
{ {
operators_.init(*basis);
auto const localSize = basis->localView().maxSize(); auto const localSize = basis->localView().maxSize();
elementVector_.resize(localSize); elementVector_.resize(localSize);
} }
......
...@@ -18,12 +18,13 @@ addOperator(ContextTag contextTag, Expr const& expr, TreePath path) ...@@ -18,12 +18,13 @@ addOperator(ContextTag contextTag, Expr const& expr, TreePath path)
static_assert( Concepts::PreTreePath<TreePath>, static_assert( Concepts::PreTreePath<TreePath>,
"path must be a valid treepath, or an integer/index-constant"); "path must be a valid treepath, or an integer/index-constant");
auto i = child(this->basis()->localView().tree(), makeTreePath(path)); auto i = makeTreePath(path);
auto node = child(this->basis()->localView().tree(), i);
using LocalContext = typename ContextTag::type; using LocalContext = typename ContextTag::type;
using Tr = DefaultAssemblerTraits<LocalContext, ElementVector>; using Tr = DefaultAssemblerTraits<LocalContext, ElementVector>;
auto op = makeLocalOperator<LocalContext>(expr, this->basis()->gridView()); auto op = makeLocalOperator<LocalContext>(expr, this->basis()->gridView());
auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), i)); auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), node));
operators_[i].push(contextTag, std::move(localAssembler)); operators_[i].push(contextTag, std::move(localAssembler));
} }
...@@ -41,8 +42,8 @@ assemble(LocalView const& localView) ...@@ -41,8 +42,8 @@ assemble(LocalView const& localView)
auto const& element = localView.element(); auto const& element = localView.element();
auto geometry = element.geometry(); auto geometry = element.geometry();
for_each_node(localView.tree(), [&](auto const& node, auto) { for_each_node(localView.tree(), [&](auto const& node, auto tp) {
auto& rhsOp = operators_[node]; auto& rhsOp = operators_[tp];
if (rhsOp) { if (rhsOp) {
rhsOp.bind(element, geometry); rhsOp.bind(element, geometry);
assembleOperators(gv, element, rhsOp, makeVectorAssembler(node, elementVector_)); assembleOperators(gv, element, rhsOp, makeVectorAssembler(node, elementVector_));
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include <amdis/BoundarySubset.hpp> #include <amdis/BoundarySubset.hpp>
#include <amdis/AssemblerInterface.hpp> #include <amdis/AssemblerInterface.hpp>
#include <amdis/typetree/TreeData.hpp> #include <amdis/typetree/TreeContainer.hpp>
namespace AMDiS namespace AMDiS
{ {
...@@ -141,10 +141,15 @@ namespace AMDiS ...@@ -141,10 +141,15 @@ namespace AMDiS
template <class RowBasis, class ColBasis, class ElementMatrix> template <class RowBasis, class ColBasis, class ElementMatrix>
using MatrixOperators using MatrixOperators
= MatrixData<RowBasis, ColBasis, OperatorLists<typename RowBasis::GridView,ElementMatrix>::template MatData>; = TreeMatrix<
OperatorLists<typename RowBasis::GridView,ElementMatrix>::template MatData,
typename RowBasis::LocalView::Tree,
typename ColBasis::LocalView::Tree>;
template <class GlobalBasis, class ElementVector> template <class Basis, class ElementVector>
using VectorOperators using VectorOperators
= VectorData<GlobalBasis, OperatorLists<typename GlobalBasis::GridView,ElementVector>::template VecData>; = TreeContainer<
OperatorLists<typename Basis::GridView,ElementVector>::template VecData,
typename Basis::LocalView::Tree>;
} // end namespace AMDiS } // end namespace AMDiS
...@@ -197,7 +197,7 @@ auto PeriodicBC<Mat, Sol, Rhs, Basis, TP>:: ...@@ -197,7 +197,7 @@ auto PeriodicBC<Mat, Sol, Rhs, Basis, TP>::
coords(Node const& tree, std::vector<std::size_t> const& localIndices) const coords(Node const& tree, std::vector<std::size_t> const& localIndices) const
{ {
std::vector<Domain> dofCoords(localIndices.size()); std::vector<Domain> dofCoords(localIndices.size());
for_each_leaf_node(tree, [&](auto const& node, auto const& tp) for_each_leaf_node(tree, [&](auto const& node, auto&&)
{ {
std::size_t size = node.finiteElement().size(); std::size_t size = node.finiteElement().size();
auto geometry = node.element().geometry(); auto geometry = node.element().geometry();
......
...@@ -33,17 +33,12 @@ ...@@ -33,17 +33,12 @@
#include <amdis/ProblemStatBase.hpp> #include <amdis/ProblemStatBase.hpp>
#include <amdis/ProblemStatTraits.hpp> #include <amdis/ProblemStatTraits.hpp>
#include <amdis/StandardProblemIteration.hpp> #include <amdis/StandardProblemIteration.hpp>
#include <amdis/common/SharedPtr.hpp> #include <amdis/common/SharedPtr.hpp>
#include <amdis/common/TupleUtility.hpp> #include <amdis/common/TupleUtility.hpp>
#include <amdis/common/TypeTraits.hpp> #include <amdis/common/TypeTraits.hpp>
#include <amdis/GridFunctions.hpp> #include <amdis/GridFunctions.hpp>
#include <amdis/gridfunctions/DiscreteFunction.hpp> #include <amdis/gridfunctions/DiscreteFunction.hpp>
#include <amdis/io/FileWriterBase.hpp> #include <amdis/io/FileWriterBase.hpp>
#include <amdis/typetree/TreeData.hpp>
#include <amdis/typetree/TreePath.hpp> #include <amdis/typetree/TreePath.hpp>
namespace AMDiS namespace AMDiS
...@@ -305,7 +300,7 @@ namespace AMDiS ...@@ -305,7 +300,7 @@ namespace AMDiS
bool storeMatrixData = false) override; bool storeMatrixData = false) override;
/// Implementation of \ref ProblemStatBase::estimate. /// Implementation of \ref ProblemStatBase::estimate.
void estimate(AdaptInfo& adaptInfo) override { /* do nothing. */ } void estimate(AdaptInfo& /*adaptInfo*/) override { /* do nothing. */ }
/// Implementation of \ref ProblemStatBase::refineMesh. /// Implementation of \ref ProblemStatBase::refineMesh.
Flag adaptGrid(AdaptInfo& adaptInfo) override; Flag adaptGrid(AdaptInfo& adaptInfo) override;
......
...@@ -209,10 +209,7 @@ void ProblemStat<Traits>::createGlobalBasisImpl(std::false_type) ...@@ -209,10 +209,7 @@ void ProblemStat<Traits>::createGlobalBasisImpl(std::false_type)
template <class Traits> template <class Traits>
void ProblemStat<Traits>::initGlobalBasis() void ProblemStat<Traits>::initGlobalBasis() {}
{
boundaryConditions_.init(*globalBasis_, *globalBasis_);
}
template <class Traits> template <class Traits>
...@@ -227,7 +224,7 @@ void ProblemStat<Traits>::createMatricesAndVectors() ...@@ -227,7 +224,7 @@ void ProblemStat<Traits>::createMatricesAndVectors()
rhs_ = std::make_shared<SystemVector>(globalBasis_); rhs_ = std::make_shared<SystemVector>(globalBasis_);
auto localView = globalBasis_->localView(); auto localView = globalBasis_->localView();
for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) -> void for_each_node(localView.tree(), [&,this](auto&&, auto treePath) -> void
{ {
std::string i = to_string(treePath); std::string i = to_string(treePath);
estimates_[i].resize(globalBasis_->gridView().indexSet().size(0)); estimates_[i].resize(globalBasis_->gridView().indexSet().size(0));
...@@ -255,7 +252,7 @@ void ProblemStat<Traits>::createMarker() ...@@ -255,7 +252,7 @@ void ProblemStat<Traits>::createMarker()
{ {
marker_.clear(); marker_.clear();
auto localView = globalBasis_->localView(); auto localView = globalBasis_->localView();
for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) -> void for_each_node(localView.tree(), [&,this](auto&&, auto treePath) -> void
{ {
std::string componentName = name_ + "->marker[" + to_string(treePath) + "]"; std::string componentName = name_ + "->marker[" + to_string(treePath) + "]";
...@@ -358,7 +355,7 @@ addPeriodicBC(BoundaryType id, WorldMatrix const& matrix, WorldVector const& vec ...@@ -358,7 +355,7 @@ addPeriodicBC(BoundaryType id, WorldMatrix const& matrix, WorldVector const& vec
template <class Traits> template <class Traits>
void ProblemStat<Traits>:: void ProblemStat<Traits>::
solve(AdaptInfo& adaptInfo, bool createMatrixData, bool storeMatrixData) solve(AdaptInfo& /*adaptInfo*/, bool createMatrixData, bool storeMatrixData)
{ {
Dune::Timer t; Dune::Timer t;
...@@ -449,7 +446,7 @@ globalRefine(int n) ...@@ -449,7 +446,7 @@ globalRefine(int n)
template <class Traits> template <class Traits>
Flag ProblemStat<Traits>:: Flag ProblemStat<Traits>::
adaptGrid(AdaptInfo& adaptInfo) adaptGrid(AdaptInfo& /*adaptInfo*/)
{ {
Dune::Timer t; Dune::Timer t;
...@@ -470,9 +467,9 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as ...@@ -470,9 +467,9 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as
Dune::Timer t2; Dune::Timer t2;
auto localView = globalBasis_->localView(); auto localView = globalBasis_->localView();
for_each_node(localView.tree(), [&,this](auto const& rowNode, auto rowTp) -> void { for_each_node(localView.tree(), [&](auto&&, auto rowTp) -> void {
for_each_node(localView.tree(), [&,this](auto const& colNode, auto colTp) -> void { for_each_node(localView.tree(), [&](auto&&, auto colTp) -> void {
for (auto bc : boundaryConditions_[rowNode][colNode]) for (auto bc : boundaryConditions_[rowTp][colTp])
bc->init(); bc->init();
}); });
}); });
...@@ -509,10 +506,10 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as ...@@ -509,10 +506,10 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as
t2.reset(); t2.reset();
solution_->resize(sizeInfo(*globalBasis_)); solution_->resize(sizeInfo(*globalBasis_));
for_each_node(localView.tree(), [&,this](auto const& rowNode, auto row_tp) -> void { for_each_node(localView.tree(), [&](auto&&, auto rowTp) -> void {
for_each_node(localView.tree(), [&,this](auto const& colNode, auto col_tp) -> void { for_each_node(localView.tree(), [&](auto&&, auto colTp) -> void {
// finish boundary condition // finish boundary condition
for (auto bc : boundaryConditions_[rowNode][colNode]) for (auto bc : boundaryConditions_[rowTp][colTp])
bc->apply(*systemMatrix_, *solution_, *rhs_); bc->apply(*systemMatrix_, *solution_, *rhs_);
}); });
}); });
......
...@@ -5,6 +5,5 @@ install(FILES ...@@ -5,6 +5,5 @@ install(FILES
RangeType.hpp RangeType.hpp
Traversal.hpp Traversal.hpp
TreeContainer.hpp TreeContainer.hpp
TreeData.hpp
TreePath.hpp TreePath.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/typetree) DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/typetree)
...@@ -18,75 +18,32 @@ ...@@ -18,75 +18,32 @@
namespace AMDiS namespace AMDiS
{ {
namespace Impl /// \brief Vector data-structure with tree-path index access and hierarchic structure
{ /// given by the `Container` template type
/// \brief A factory class creating a hybrid container compatible with a type tree
/**
*
* This class allows to create a nested hybrid container having the same structure
* as a given type tree. Power nodes are represented as std::array's while composite
* nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
* are creating using a given predicate. Once created, the factory provides an
* operator() creating the container for the tree given as argument.
*
* \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
*/
template <class LeafToValue>
class ContainerFactory
{
public:
/// \brief Create ContainerFactory
/** /**
* The given predicate will be stored by value. * This Vector container is parametrized with the actual container type that is stored
* internally. Access to the elements of the container is possible by using a tree-path
* index.
* *
* \param A predicate used to generate the stored values for the leaves * The internal container is constructed by the \ref ContainerFactory, storing for each
*/ * tree node a corresponding array or tuple plus a value. The data-structure to hold
ContainerFactory(LeafToValue leafToValue) * both, the value and the container is defined in \ref ValueAndContainer.
: leafToValue_(std::move(leafToValue)) **/
{}
/// \brief Return a container for storing the node content
template <class Node>
auto operator() (Node const& node) const
{
if constexpr (Node::isLeaf)
return leafToValue_(node);
else
if constexpr (Node::isPower) {
using TransformedChild = decltype((*this)(node.child(0)));
return std::array<TransformedChild, Node::degree()>();
}
else
if constexpr (Node::isComposite) {
return Tools::apply_indices<Node::degree()>(
[&](auto... i) { return Dune::makeTupleVector((*this)(node.child(i))...); });
}
else {
static_assert(Node::isLeaf || Node::isPower || Node::isComposite,
"Node must be one of leaf,power,composite.");
return;
}
}
private:
LeafToValue leafToValue_;
};
/// \brief Wrap nested container to provide a VectorBackend
template <class Container> template <class Container>
class TreeContainerVectorBackend class TreeContainerStorage
{ {
using Self = TreeContainerVectorBackend; using Self = TreeContainerStorage;
template <class C> template <class C>
static constexpr decltype(auto) accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<> const& path) static constexpr decltype(auto)
accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<> const&)
{ {
return container; return container.value();
} }
template <class C, class... T> template <class C, class... T>
static constexpr decltype(auto) accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<T...> const& path) static constexpr decltype(auto)
accessByTreePath(C&& container, Dune::TypeTree::HybridTreePath<T...> const& path)
{ {
auto head = Dune::TypeTree::treePathEntry(path,Dune::Indices::_0); auto head = Dune::TypeTree::treePathEntry(path,Dune::Indices::_0);
return accessByTreePath(container[head], pop_front(path)); return accessByTreePath(container[head], pop_front(path));
...@@ -94,12 +51,16 @@ namespace AMDiS ...@@ -94,12 +51,16 @@ namespace AMDiS
public: public:
/// \brief Default-construct the tree-container /// \brief Default-construct the tree-container
TreeContainerVectorBackend() TreeContainerStorage()
: container_() : container_()
{} {}
TreeContainerStorage(Container const& container)
: container_(container)
{}
/// \brief Construct the tree-container from a given container storage /// \brief Construct the tree-container from a given container storage
TreeContainerVectorBackend(Container&& container) TreeContainerStorage(Container&& container)
: container_(std::move(container)) : container_(std::move(container))
{} {}
...@@ -130,13 +91,13 @@ namespace AMDiS ...@@ -130,13 +91,13 @@ namespace AMDiS
} }
/// \brief Compare two containers for equality /// \brief Compare two containers for equality
bool operator==(TreeContainerVectorBackend const& other) const bool operator==(TreeContainerStorage const& other) const
{ {
return container_ == other.container_; return container_ == other.container_;
} }
/// \brief Compare two containers for inequality /// \brief Compare two containers for inequality
bool operator!=(TreeContainerVectorBackend const& other) const bool operator!=(TreeContainerStorage const& other) const
{ {
return container_ != other.container_; return container_ != other.container_;
} }
...@@ -145,16 +106,186 @@ namespace AMDiS ...@@ -145,16 +106,186 @@ namespace AMDiS
Container container_; Container container_;
}; };
namespace Impl
{
template <class Value, class Container>
class ValueAndContainer
{
public:
template <class V, class C>
ValueAndContainer(V&& value, C&& container)
: value_(FWD(value))
, container_(FWD(container))
{}
ValueAndContainer()
: value_()
, container_()
{}
template <class I>