Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
amdis
amdis-core
Commits
ad86d17a
Commit
ad86d17a
authored
Apr 15, 2020
by
Praetorius, Simon
Browse files
Merge branch 'feature/typetree_cleanup' into 'master'
update traversal and tree container based on if constexpr feature See merge request
!182
parents
23df0b03
8c255ac5
Changes
3
Hide whitespace changes
Inline
Side-by-side
amdis/typetree/Traversal.hpp
View file @
ad86d17a
#pragma once
#include
<dune/common/hybridutilities.hh>
#include
<dune/common/rangeutilities.hh>
#include
<dune/typetree/childextraction.hh>
#include
<dune/typetree/nodetags.hh>
#include
<dune/typetree/treepath.hh>
#include
<dune/typetree/visitor.hh>
#include
<amdis/common/ForEach.hpp>
#include
<amdis/common/Logical.hpp>
#include
<amdis/common/Range.hpp>
#include
<amdis/common/TypeTraits.hpp>
// NOTE: backport of dune/typetree/traversal.hpp from Dune 2.7
namespace
AMDiS
{
enum
class
TreePathType
{
DYNAMIC
,
STATIC
};
namespace
Impl
{
// This is a constexpr version of the ternery operator c?t1:t1.
// In contrast to the latter the type of t1 and t2 can be different.
// Notice that std::conditional would not do the trick, because
// it only selects between types.
template
<
bool
c
,
class
T1
,
class
T2
,
std
::
enable_if_t
<
c
,
int
>
=
0
>
constexpr
auto
conditionalValue
(
T1
&&
t1
,
T2
&&
t2
)
{
return
std
::
forward
<
T1
>
(
t1
);
}
template
<
bool
c
,
class
T1
,
class
T2
,
std
::
enable_if_t
<
not
c
,
int
>
=
0
>
constexpr
auto
conditionalValue
(
T1
&&
t1
,
T2
&&
t2
)
{
return
std
::
forward
<
T2
>
(
t2
);
}
/* The signature is the same as for the public applyToTree
* function in Dune::Typetree, despite the additionally passed
* treePath argument. The path passed here is associated to
* the tree and the relative paths of the children (wrt. to tree)
* are appended to this. Hence the behavior of the public function
* is resembled by passing an empty treePath.
*/
/*
* This is the overload for leaf traversal
*/
template
<
class
T
,
class
TP
,
class
V
,
std
::
enable_if_t
<
remove_cvref_t
<
T
>
::
isLeaf
,
int
>
=
0
>
void
apply_to_tree
(
T
&&
tree
,
TP
treePath
,
V
&&
visitor
)
{
visitor
.
leaf
(
tree
,
treePath
);
}
/*
* This is the general overload doing child traversal.
*/
template
<
class
T
,
class
TP
,
class
V
,
std
::
enable_if_t
<
not
remove_cvref_t
<
T
>
::
isLeaf
,
int
>
=
0
>
void
apply_to_tree
(
T
&&
tree
,
TP
treePath
,
V
&&
visitor
)
{
// Do we really want to take care for const-ness of the Tree
// when instantiating VisitChild below? I'd rather expect this:
// using Tree = remove_cvref_t<T>;
// using Visitor = remove_cvref_t<V>;
using
Tree
=
std
::
remove_reference_t
<
T
>
;
using
Visitor
=
std
::
remove_reference_t
<
V
>
;
visitor
.
pre
(
tree
,
treePath
);
// Use statically encoded degree unless tree
// is a power node and dynamic traversal is requested.
constexpr
auto
useDynamicTraversal
=
(
Tree
::
isPower
and
Visitor
::
treePathType
==
TreePathType
::
DYNAMIC
);
auto
degree
=
conditionalValue
<
useDynamicTraversal
>
(
Tree
::
degree
(),
Dune
::
index_constant
<
Tree
::
degree
()
>
{});
auto
indices
=
Dune
::
range
(
degree
);
Dune
::
Hybrid
::
forEach
(
indices
,
[
&
](
auto
i
)
{
auto
childTP
=
Dune
::
TypeTree
::
push_back
(
treePath
,
i
);
auto
&&
child
=
tree
.
child
(
i
);
using
Child
=
TYPEOF
(
child
);
visitor
.
beforeChild
(
tree
,
child
,
treePath
,
i
);
// This requires that visiotor.in(...) can always be instantiated,
// even if there's a single child only.
if
(
i
>
0
)
visitor
.
in
(
tree
,
treePath
);
static
constexpr
auto
visitChild
=
Visitor
::
template
VisitChild
<
Tree
,
Child
,
TP
>
::
value
;
if
constexpr
(
visitChild
)
applyToTree
(
child
,
childTP
,
visitor
);
visitor
.
afterChild
(
tree
,
child
,
treePath
,
i
);
});
visitor
.
post
(
tree
,
treePath
);
}
// Overload for leaf nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>
=
0
>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
/*preFunc*/
,
Leaf
&&
leafFunc
,
Post
&&
/*postFunc*/
)
{
leafFunc
(
tree
,
treePath
);
}
// Overload for non-leaf nodes
// Forward declaration needed for recursion
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>
=
0
>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
);
// Helper for power nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
size_t
...
I
,
std
::
enable_if_t
<
remove_cvref_t
<
Tree
>
::
isPower
,
int
>
=
0
>
void
for_each_node_unfold
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
,
std
::
index_sequence
<
I
...
>
)
{
for
(
std
::
size_t
i
=
0
;
i
<
sizeof
...(
I
);
++
i
)
Impl
::
for_each_node
(
tree
.
child
(
i
),
Dune
::
TypeTree
::
push_back
(
treePath
,
i
),
preFunc
,
leafFunc
,
postFunc
);
}
// Helper for composite nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
size_t
...
I
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isPower
,
int
>
=
0
>
void
for_each_node_unfold
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
,
std
::
index_sequence
<
I
...
>
)
{
(
void
)
std
::
initializer_list
<
int
>
{(
Impl
::
for_each_node
(
tree
.
child
(
Dune
::
index_constant
<
I
>
{}),
Dune
::
TypeTree
::
push_back
(
treePath
,
Dune
::
index_constant
<
I
>
{}),
preFunc
,
leafFunc
,
postFunc
),
0
)...
};
}
/*
* Traverse tree and visit each node. The signature is the same
* as for the public for_each_node function in Dune::Typtree,
* despite the additionally passed treePath argument. The path
* passed here is associated to the tree and the relative
* paths of the children (wrt. to tree) are appended to this.
* Hence the behavior of the public function is resembled
* by passing an empty treePath.
*
* See also the specialization for leaf-nodes.
*/
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
)
{
auto
indices
=
std
::
make_index_sequence
<
TYPEOF
(
tree
)
::
degree
()
>
{};
preFunc
(
tree
,
treePath
);
Impl
::
for_each_node_unfold
(
tree
,
treePath
,
preFunc
,
leafFunc
,
postFunc
,
indices
);
postFunc
(
tree
,
treePath
);
}
}
// namespace Impl
// ********************************************************************************
// Public Interface
// ********************************************************************************
//! Apply visitor to TypeTree.
namespace
AMDiS
{
namespace
Impl
{
/// \brief Helper function that returns the degree of a Tree.
/**
* \code
* #include <amdis/typetree/Traversal.hpp>
* \endcode
* This function applies the given visitor to the given tree. Both visitor and tree may be const
* or non-const (if the compiler supports rvalue references, they may even be a non-const temporary).
* The return type is either `size_t` if it is a dynamic tree or the flag `dynamic`
* is set to `true`, or as the type returned by the `degree()` member function of the
* tree.
*
* \note The visitor must implement the interface laid out by DefaultVisitor (most easily achieved by
* inheriting from it) and specify the required type of tree traversal (static or dynamic) by
* inheriting from either StaticTraversal or DynamicTraversal.
*
* \param tree The tree the visitor will be applied to.
* \param visitor The visitor to apply to the tree.
*/
template
<
typename
Tree
,
typename
Visitor
>
void
apply_to_tree
(
Tree
&&
tree
,
Visitor
&&
visitor
)
* This function allows to change the tree traversal from static to dynamic in case
* of power nodes and uses static traversal for composite and dynamic traversal for
* all dynamic nodes.
**/
template
<
bool
dynamic
=
true
,
class
Tree
>
auto
traversalDegree
(
Tree
const
&
tree
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
apply_to_tree
(
tree
,
root
,
visitor
);
if
constexpr
(
dynamic
&&
Tree
::
isPower
)
return
std
::
size_t
(
tree
.
degree
());
else
if
constexpr
(
Tree
::
isPower
||
Tree
::
isComposite
)
return
std
::
integral_constant
<
std
::
size_t
,
Tree
::
degree
()
>
{};
else
return
tree
.
degree
();
}
/**
* \brief Traverse tree and visit each node
*
* All passed callback functions are called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param preFunc This function is called for each inner node before visiting its children
* \param leafFunc This function is called for each leaf node
* \param postFunc This function is called for each inner node after visiting its children
*/
template
<
class
Tree
,
class
Pre
,
class
Leaf
,
class
Post
>
void
for_each_node
(
Tree
&&
tree
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
)
* Traverse tree and visit each node. The signature is the same
* as for the public for_each_node function in Dune::Typtree,
* despite the additionally passed treePath argument. The path
* passed here is associated to the tree and the relative
* paths of the children (wrt. to tree) are appended to this.
* Hence the behavior of the public function is resembled
* by passing an empty treePath.
**/
template
<
class
Tree
,
class
TreePath
,
class
PreFunc
,
class
LeafFunc
,
class
PostFunc
>
void
for_each_node
(
Tree
&&
tree
,
TreePath
treePath
,
PreFunc
&&
preFunc
,
LeafFunc
&&
leafFunc
,
PostFunc
&&
postFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
preFunc
,
leafFunc
,
postFunc
);
}
/**
* \brief Traverse tree and visit each node
*
* All passed callback functions are called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param innerFunc This function is called for each inner node before visiting its children
* \param leafFunc This function is called for each leaf node
*/
template
<
class
Tree
,
class
Inner
,
class
Leaf
>
void
for_each_node
(
Tree
&&
tree
,
Inner
&&
innerFunc
,
Leaf
&&
leafFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
innerFunc
,
leafFunc
,
NoOp
{});
}
/**
* \brief Traverse tree and visit each node
*
* The passed callback function is called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param nodeFunc This function is called for each node
*/
template
<
class
Tree
,
class
NodeFunc
>
void
for_each_node
(
Tree
&&
tree
,
NodeFunc
&&
nodeFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
nodeFunc
,
nodeFunc
,
NoOp
{});
using
TreeType
=
std
::
decay_t
<
Tree
>
;
if
constexpr
(
TreeType
::
isLeaf
)
{
// If we have a leaf tree just visit it using the leaf function.
leafFunc
(
tree
,
treePath
);
}
else
{
// Otherwise visit the tree with the pre function,
// visit all children using a static or dynamic loop, and
// finally visit the tree with the post function.
preFunc
(
tree
,
treePath
);
Dune
::
Hybrid
::
forEach
(
Dune
::
range
(
traversalDegree
(
tree
)),
[
&
](
auto
i
)
{
auto
childTreePath
=
push_back
(
treePath
,
i
);
Impl
::
for_each_node
(
tree
.
child
(
i
),
childTreePath
,
preFunc
,
leafFunc
,
postFunc
);
});
postFunc
(
tree
,
treePath
);
}
}
/**
* \brief Traverse tree and visit each leaf node
*
* The passed callback function is called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param leafFunc This function is called for each leaf node
*/
template
<
class
Tree
,
class
Leaf
>
void
for_each_leaf_node
(
Tree
&&
tree
,
Leaf
&&
leafFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
NoOp
{},
leafFunc
,
NoOp
{});
}
}
// end namespace Impl
/// \brief Traverse tree and visit each node
/**
* All passed callback functions are called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param preFunc This function is called for each inner node before visiting its children
* \param leafFunc This function is called for each leaf node
* \param postFunc This function is called for each inner node after visiting its children
*/
template
<
class
Tree
,
class
PreFunc
,
class
LeafFunc
,
class
PostFunc
>
void
for_each_node
(
Tree
&&
tree
,
PreFunc
&&
preFunc
,
LeafFunc
&&
leafFunc
,
PostFunc
&&
postFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
preFunc
,
leafFunc
,
postFunc
);
}
/// \brief Traverse tree and visit each node
/**
* All passed callback functions are called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param innerFunc This function is called for each inner node before visiting its children
* \param leafFunc This function is called for each leaf node
*/
template
<
class
Tree
,
class
InnerFunc
,
class
LeafFunc
>
void
for_each_node
(
Tree
&&
tree
,
InnerFunc
&&
innerFunc
,
LeafFunc
&&
leafFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
innerFunc
,
leafFunc
,
NoOp
{});
}
/// \brief Traverse tree and visit each node
/**
* The passed callback function is called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param nodeFunc This function is called for each node
*/
template
<
class
Tree
,
class
NodeFunc
>
void
for_each_node
(
Tree
&&
tree
,
NodeFunc
&&
nodeFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
nodeFunc
,
nodeFunc
,
NoOp
{});
}
/// \brief Traverse tree and visit each leaf node
/**
* The passed callback function is called with the
* node and corresponding treepath as arguments.
*
* \param tree The tree to traverse
* \param leafFunc This function is called for each leaf node
*/
template
<
class
Tree
,
class
LeafFunc
>
void
for_each_leaf_node
(
Tree
&&
tree
,
LeafFunc
&&
leafFunc
)
{
auto
root
=
Dune
::
TypeTree
::
hybridTreePath
();
Impl
::
for_each_node
(
tree
,
root
,
NoOp
{},
leafFunc
,
NoOp
{});
}
}
// end namespace AMDiS
amdis/typetree/TreeContainer.hpp
View file @
ad86d17a
...
...
@@ -20,8 +20,8 @@ namespace AMDiS
{
namespace
Impl
{
/
*
* \brief A factory class creating a hybrid container compatible with a type tree
/
// \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
...
...
@@ -31,44 +31,41 @@ namespace AMDiS
*
* \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
*/
template
<
class
LeafToValue
>
template
<
class
LeafToValue
>
class
ContainerFactory
{
public:
/// \brief Create ContainerFactory
/**
* \brief Create ContainerFactory
*
* The given predicate will be stored by value.
*
* \param A predicate used to generate the stored values for the leaves
*/
ContainerFactory
(
LeafToValue
leafToValue
)
:
leafToValue_
(
leafToValue
)
ContainerFactory
(
LeafToValue
leafToValue
)
:
leafToValue_
(
std
::
move
(
leafToValue
)
)
{}
template
<
class
Node
,
std
::
enable_if_t
<
Node
::
isLeaf
,
int
>
=
0
>
auto
operator
()(
const
Node
&
node
)
{
return
leafToValue_
(
node
);
}
template
<
class
Node
,
std
::
enable_if_t
<
Node
::
isPower
,
int
>
=
0
>
auto
operator
()(
const
Node
&
node
)
{
using
TransformedChild
=
decltype
((
*
this
)(
node
.
child
(
0
)));
return
std
::
array
<
TransformedChild
,
Node
::
degree
()
>
();
}
template
<
class
Node
,
std
::
enable_if_t
<
Node
::
isComposite
,
int
>
=
0
>
auto
operator
()(
const
Node
&
node
)
/// \brief Return a container for storing the node content
template
<
class
Node
>
auto
operator
()
(
Node
const
&
node
)
const
{
return
Tools
::
apply_indices
([
&
](
auto
...
indices
)
{
return
Dune
::
makeTupleVector
((
*
this
)(
node
.
child
(
indices
))...);
},
index_t
<
Node
::
degree
()
>
{});
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:
...
...
@@ -76,67 +73,69 @@ namespace AMDiS
};
/*
* \brief Wrap nested container to provide a VectorBackend
*/
template
<
class
Container
>
/// \brief Wrap nested container to provide a VectorBackend
template
<
class
Container
>
class
TreeContainerVectorBackend
{
using
Self
=
TreeContainerVectorBackend
;
template
<
class
C
>
static
constexpr
decltype
(
auto
)
accessByTreePath
(
C
&&
container
,
const
Dune
::
TypeTree
::
HybridTreePath
<>&
path
)
template
<
class
C
>
static
constexpr
decltype
(
auto
)
accessByTreePath
(
C
&&
container
,
Dune
::
TypeTree
::
HybridTreePath
<>
const
&
path
)
{
return
container
;
}
template
<
class
C
,
class
...
T
>
static
constexpr
decltype
(
auto
)
accessByTreePath
(
C
&&
container
,
const
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>&
path
)
template
<
class
C
,
class
...
T
>
static
constexpr
decltype
(
auto
)
accessByTreePath
(
C
&&
container
,
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>
const
&
path
)
{
auto
head
=
Dune
::
TypeTree
::
treePathEntry
(
path
,
Dune
::
Indices
::
_0
);
return
accessByTreePath
(
container
[
head
],
pop_front
(
path
));
}
public:
TreeContainerVectorBackend
()
=
default
;
/// \brief Default-construct the tree-container
TreeContainerVectorBackend
()
:
container_
()
{}
/// \brief Construct the tree-container from a given container storage
TreeContainerVectorBackend
(
Container
&&
container
)
:
container_
(
std
::
move
(
container
))
{}
TreeContainerVectorBackend
(
const
Self
&
)
=
default
;
TreeContainerVectorBackend
(
Self
&&
)
=
default
;
Self
&
operator
=
(
const
Self
&
)
=
default
;
Self
&
operator
=
(
Self
&&
)
=
default
;
template
<
class
...
T
>
decltype
(
auto
)
operator
[](
const
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>&
path
)
const
/// \brief Access a (const) element of the container by treepath
template
<
class
...
T
>
decltype
(
auto
)
operator
[](
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>
const
&
path
)
const
{
return
accessByTreePath
(
container_
,
path
);
}
template
<
class
...
T
>
decltype
(
auto
)
operator
[](
const
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>&
path
)
/// \brief Access a (mutable) element of the container by treepath
template
<
class
...
T
>
decltype
(
auto
)
operator
[](
Dune
::
TypeTree
::
HybridTreePath
<
T
...
>
const
&
path
)
{
return
accessByTreePath
(
container_
,
path
);
}
const
Container
&
data
()
const
/// \brief Obtain the container (const)
Container
const
&
data
()
const
{
return
container_
;
}
/// \brief Obtain the container (mutable)
Container
&
data
()
{
return
container_
;
}
/// \brief Compare two containers for equality
bool
operator
==
(
TreeContainerVectorBackend
const
&
other
)
const
{
return
container_
==
other
.
container_
;
}
/// \brief Compare two containers for inequality
bool
operator
!=
(
TreeContainerVectorBackend
const
&
other
)
const
{
return
container_
!=
other
.
container_
;
...
...
@@ -146,7 +145,7 @@ namespace AMDiS
Container
container_
;
};
template
<
class
Container
>
template
<
class
Container
>
auto
makeTreeContainerVectorBackend
(
Container
&&
container
)
{
return
TreeContainerVectorBackend
<
remove_cvref_t
<
Container
>>
(
FWD
(
container
));
...
...
@@ -154,67 +153,59 @@ namespace AMDiS
}
// end namespace Impl
/** \addtogroup TypeTree
* \{
*/
/**
* \brief Create container havin the same structure as the given 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. For convenience the created container is
* not returned directly. Instead, the returned object stores the container and
* provides operator[] access using a HybridTreePath.
*
* \param tree The tree which should be mapper to a container
* \param leafToValue A predicate used to generate the stored values for the leaves
*
* \returns A container matching the tree structure
*/
template
<
class
Tree
,
class
LeafToValue
>
auto
makeTreeContainer
(
const
Tree
&
tree
,
LeafToValue
&&
leafToValue
)
{
auto
f
=
std
::
ref
(
leafToValue
);
auto
factory
=
Impl
::
ContainerFactory
<
decltype
(
f
)
>
(
f
);
return
Impl
::
makeTreeContainerVectorBackend
(
factory
(
tree
));
}
/**
* \brief Create container havin the same structure as the given 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 of the given type Value. For convenience the created container is
* not returned directly. Instead, the returned object stores the container and
* provides operator[] access using a HybridTreePath.
*
* \tparam Value Type of the values to be stored for the leafs. Should be default constructible.
* \param leafToValue A predicate used to generate the stored values for the leaves
*
* \returns A container matching the tree structure
*/
template
<
class
Value
,
class
Tree
>
auto
makeTreeContainer
(
const
Tree
&
tree
)
{
return
makeTreeContainer
(
tree
,
[](
const
auto
&
)
{
return
Value
{};});
}
template
<
template
<
class
>
class
NodeData
,
class
Tree
>
auto
makeTreeContainer
(
const
Tree
&
tree
)
{
return
makeTreeContainer
(
tree
,
[](
const
auto
&
node
)
{
return
NodeData
<
TYPEOF
(
node
)
>
{};});
}
/// \brief Create container havin the same structure as the given 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. For convenience the created container is
* not returned directly. Instead, the returned object stores the container and
* provides operator[] access using a HybridTreePath.
*
* \param tree The tree which should be mapper to a container
* \param leafToValue A predicate used to generate the stored values for the leaves
*
* \returns A container matching the tree structure
*/
template
<
class
Tree
,
class
LeafToValue
>