Commit 37986650 authored by Simon Praetorius's avatar Simon Praetorius

Merge branch 'feature/dynamic_traversal' into 'master'

Add possibility for dynamic tree traversal

See merge request !85
parents d3a1cbca 428e0336
Pipeline #34241 passed with stage
in 4 minutes and 19 seconds
......@@ -4,6 +4,7 @@ Changes
TypeTree 2.8-git
----------------
- Allow tree traversal for nodes with runtime degree that are not necessarily power nodes.
- The `forEachNode()` traversal function with multiple callbacks is deprecated. Use the
more general `applyToTree()` instead.
- Removed the type aliases for the storage type `Storage` and `ConstStorage` in the
......
......@@ -6,6 +6,7 @@
#include <tuple>
#include <memory>
#include <type_traits>
#include <dune/typetree/nodetags.hh>
#include <dune/typetree/childextraction.hh>
......@@ -47,9 +48,9 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = sizeof...(Children);
static constexpr std::size_t degree ()
static constexpr auto degree ()
{
return sizeof...(Children);
return std::integral_constant<std::size_t,sizeof...(Children)>{};
}
//! Access to the type and storage type of the i-th child.
......
......@@ -115,9 +115,9 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = filter_result::size;
static constexpr std::size_t degree ()
static constexpr auto degree ()
{
return filter_result::size;
return std::integral_constant<std::size_t,filter_result::size>{};
}
//! Access to the type and storage type of the i-th child.
......
......@@ -6,6 +6,7 @@
#include <dune/typetree/nodetags.hh>
#include <cstddef>
#include <type_traits>
namespace Dune {
namespace TypeTree {
......@@ -41,9 +42,9 @@ namespace Dune {
//! The type tag that describes a LeafNode.
typedef LeafNodeTag NodeTag;
static constexpr std::size_t degree()
static constexpr auto degree()
{
return 0;
return std::integral_constant<std::size_t,0>{};
}
protected:
......
......@@ -57,32 +57,51 @@ namespace Dune {
using Visitor = std::remove_reference_t<V>;
visitor.pre(tree1, tree2, treePath);
// Use statically encoded degree unless both trees
// are power nodes and dynamic traversal is requested.
constexpr auto useDynamicTraversal = (Tree1::isPower and Tree2::isPower and Visitor::treePathType==TreePathType::dynamic);
auto degree = conditionalValue<useDynamicTraversal>(Tree1::degree(), Dune::index_constant<Tree1::degree()>{});
auto indices = Dune::range(degree);
Dune::Hybrid::forEach(indices, [&](auto i) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
auto&& child1 = tree1.child(i);
auto&& child2 = tree2.child(i);
using Child1 = std::decay_t<decltype(child1)>;
using Child2 = std::decay_t<decltype(child2)>;
visitor.beforeChild(tree1, child1, tree2, child2, treePath, i);
// This requires that visiotor.in(...) can always be instantiated,
// even if there's a single child only.
if (i>0)
visitor.in(tree1, tree2, treePath);
static const auto visitChild = Visitor::template VisitChild<Tree1,Child1,Tree2,Child2,TreePath>::value;
Dune::Hybrid::ifElse(Dune::Std::bool_constant<visitChild>{}, [&] (auto id) {
applyToTreePair(child1, child2, childTreePath, visitor);
// check which type of traversal is supported by the trees
using allowDynamicTraversal = std::conjunction<
Dune::Std::is_detected<DynamicTraversalConcept,Tree1>,
Dune::Std::is_detected<DynamicTraversalConcept,Tree2>>;
using allowStaticTraversal = std::conjunction<
Dune::Std::is_detected<StaticTraversalConcept,Tree1>,
Dune::Std::is_detected<StaticTraversalConcept,Tree2>>;
// both trees must support either dynamic or static traversal
static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
// the visitor may specify preferred dynamic traversal
using preferDynamicTraversal = std::bool_constant<Visitor::treePathType == TreePathType::dynamic>;
// create a dynamic or static index range
auto indices = [&]{
if constexpr(preferDynamicTraversal::value && allowDynamicTraversal::value)
return Dune::range(std::size_t(tree1.degree()));
else
return Dune::range(tree1.degree());
}();
if constexpr(allowDynamicTraversal::value || allowStaticTraversal::value) {
Dune::Hybrid::forEach(indices, [&](auto i) {
auto&& child1 = tree1.child(i);
auto&& child2 = tree2.child(i);
using Child1 = std::decay_t<decltype(child1)>;
using Child2 = std::decay_t<decltype(child2)>;
visitor.beforeChild(tree1, child1, tree2, child2, treePath, i);
// This requires that visitor.in(...) can always be instantiated,
// even if there's a single child only.
if (i>0)
visitor.in(tree1, tree2, treePath);
constexpr bool visitChild = Visitor::template VisitChild<Tree1,Child1,Tree2,Child2,TreePath>::value;
if constexpr(visitChild) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
applyToTreePair(child1, child2, childTreePath, visitor);
}
visitor.afterChild(tree1, child1, tree2, child2, treePath, i);
});
visitor.afterChild(tree1, child1, tree2, child2, treePath, i);
});
}
visitor.post(tree1, tree2, treePath);
}
......
......@@ -63,9 +63,9 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = k;
static constexpr std::size_t degree ()
static constexpr auto degree ()
{
return k;
return std::integral_constant<std::size_t,k>{};
}
//! The type tag that describes a PowerNode.
......
......@@ -9,6 +9,7 @@
#include <dune/typetree/nodetags.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/indices.hh>
#include <dune/common/std/type_traits.hh>
namespace Dune {
namespace TypeTree {
......@@ -242,9 +243,14 @@ namespace Dune {
class ProxyNode
: public ProxyNodeBase<Node,NodeTag<Node>>
{
static const bool proxiedNodeIsConst = std::is_const<typename std::remove_reference<Node>::type>::value;
template <class N>
using HasStaticDegree = index_constant<N::degree()>;
template <class N>
static constexpr bool hasStaticDegree = Std::is_detected<HasStaticDegree, N>::value;
// accessor mixins need to be friends for access to proxiedNode()
friend class StaticChildAccessors<Node>;
friend class DynamicChildAccessors<Node>;
......@@ -267,9 +273,18 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = StaticDegree<Node>::value;
static constexpr std::size_t degree ()
template <class N = Node,
std::enable_if_t<hasStaticDegree<N>, int> = 0>
static constexpr auto degree ()
{
return N::degree();
}
template <class N = Node,
std::enable_if_t<not hasStaticDegree<N>, int> = 0>
auto degree () const
{
return StaticDegree<Node>::value;
return proxiedNode().degree();
}
......
......@@ -6,9 +6,8 @@
#include <utility>
#include <dune/common/std/type_traits.hh>
#include <dune/common/std/type_traits.hh>
#include <dune/common/hybridutilities.hh>
#include <dune/common/std/type_traits.hh>
#include <dune/typetree/childextraction.hh>
#include <dune/typetree/nodetags.hh>
......@@ -27,28 +26,26 @@ namespace Dune {
/// A functor with no operation
struct NoOp
{
template <class... T>
template<class... T>
constexpr void operator()(T&&...) const { /* do nothing */ }
};
#endif
namespace Detail {
// This is a constexpr version of the ternary 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);
}
// SFINAE template check that Tree has a degree() function and a child() function accepting integer indices
template<class Tree>
using DynamicTraversalConcept = decltype((
std::declval<Tree>().degree(),
std::declval<Tree>().child(0u)
));
// SFINAE template check that Tree has static (constexpr) function Tree::degree()
template<class Tree>
using StaticTraversalConcept = decltype((
std::integral_constant<std::size_t, Tree::degree()>{}
));
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);
}
template<class Tree, TreePathType::Type pathType, class Prefix,
std::enable_if_t<Tree::isLeaf, int> = 0>
......@@ -111,34 +108,47 @@ namespace Dune {
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);
Hybrid::forEach(indices, [&](auto i) {
auto&& child = tree.child(i);
using Child = std::decay_t<decltype(child)>;
visitor.beforeChild(tree, child, treePath, i);
// This requires that visitor.in(...) can always be instantiated,
// even if there's a single child only.
if (i>0)
visitor.in(tree, treePath);
static const auto visitChild = Visitor::template VisitChild<Tree,Child,TreePath>::value;
if constexpr (visitChild) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
applyToTree(child, childTreePath, visitor);
}
// check which type of traversal is supported by the tree
using allowDynamicTraversal = Dune::Std::is_detected<DynamicTraversalConcept,Tree>;
using allowStaticTraversal = Dune::Std::is_detected<StaticTraversalConcept,Tree>;
visitor.afterChild(tree, child, treePath, i);
});
visitor.post(tree, treePath);
}
// the tree must support either dynamic or static traversal
static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
// the visitor may specify preferred dynamic traversal
using preferDynamicTraversal = std::bool_constant<Visitor::treePathType == TreePathType::dynamic>;
// create a dynamic or static index range
auto indices = [&]{
if constexpr(preferDynamicTraversal::value && allowDynamicTraversal::value)
return Dune::range(std::size_t(tree.degree()));
else
return Dune::range(tree.degree());
}();
if constexpr(allowDynamicTraversal::value || allowStaticTraversal::value) {
Hybrid::forEach(indices, [&](auto i) {
auto&& child = tree.child(i);
using Child = std::decay_t<decltype(child)>;
visitor.beforeChild(tree, child, treePath, i);
// This requires that visitor.in(...) can always be instantiated,
// even if there's a single child only.
if (i>0)
visitor.in(tree, treePath);
constexpr bool visitChild = Visitor::template VisitChild<Tree,Child,TreePath>::value;
if constexpr(visitChild) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
applyToTree(child, childTreePath, visitor);
}
visitor.afterChild(tree, child, treePath, i);
});
}
visitor.post(tree, treePath);
}
/* Traverse tree and visit each node. The signature is the same
* as for the public forEachNode function in Dune::Typtree,
......@@ -148,23 +158,31 @@ namespace Dune {
* 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 forEachNode(Tree&& tree, TreePath treePath, PreFunc&& preFunc, LeafFunc&& leafFunc, PostFunc&& postFunc)
template<class T, class TreePath, class PreFunc, class LeafFunc, class PostFunc>
void forEachNode(T&& tree, TreePath treePath, PreFunc&& preFunc, LeafFunc&& leafFunc, PostFunc&& postFunc)
{
using TreeType = std::decay_t<Tree>;
if constexpr(TreeType::isLeaf) {
using Tree = std::decay_t<T>;
if constexpr(Tree::isLeaf) {
leafFunc(tree, treePath);
} else {
preFunc(tree, treePath);
if constexpr(TreeType::isPower) {
// check which type of traversal is supported by the tree, prefer dynamic traversal
using allowDynamicTraversal = Dune::Std::is_detected<DynamicTraversalConcept,Tree>;
using allowStaticTraversal = Dune::Std::is_detected<StaticTraversalConcept,Tree>;
// the tree must support either dynamic or static traversal
static_assert(allowDynamicTraversal::value || allowStaticTraversal::value);
if constexpr(allowDynamicTraversal::value) {
// Specialization for dynamic traversal
for (std::size_t i = 0; i < TreeType::degree(); ++i) {
for (std::size_t i = 0; i < tree.degree(); ++i) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
forEachNode(tree.child(i), childTreePath, preFunc, leafFunc, postFunc);
}
} else {
} else if constexpr(allowStaticTraversal::value) {
// Specialization for static traversal
auto indices = std::make_index_sequence<TreeType::degree()>{};
auto indices = std::make_index_sequence<Tree::degree()>{};
Hybrid::forEach(indices, [&](auto i) {
auto childTreePath = Dune::TypeTree::push_back(treePath, i);
forEachNode(tree.child(i), childTreePath, preFunc, leafFunc, postFunc);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment