Commit 2a1f33b9 authored by Steffen Müthing's avatar Steffen Müthing

[Interface] Add freestanding functions for node degree

This patch introduces two new functions to obtain the degree of a tree
node:

degree(node) is a normal, freestanding function that will in theory even
work for nodes where the number of children is determined at run time.

StaticDegree<Node> and staticDegree<Node> obtain the degree as a compile
time constant and are thus only usable for nodes where the degree is
fixed at compile time. staticDegree<Node> is a variable template and
thus creates a hard dependency on C++14.

Internally, both functions dispatch to the following function signature:

template<typename Node, typename NodeTag>
constexpr std::size_t degree(const Node* node, NodeTag nodeTag);

Note that this signature uses a pointer to the node; this is necessary
to make it usable in the constexpr context, where the node parameter has
to be constexpr - manufacturing a constexpr reference is not possible in
general.

The default implementation of this function calls the static member
function Node::degree(). If your node implementation requires different
behavior, you can provide an overload for your custom node tag that will
be found via ADL. staticDegree<Node> will only work if this function is
constexpr (it is thus important to make Node::degree() constexpr in your
implementation iff the degree is a compile time constant).
parent b185f2f0
......@@ -46,6 +46,11 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = sizeof...(Children);
static constexpr std::size_t degree()
{
return sizeof...(Children);
}
//! Access to the type and storage type of the i-th child.
template<std::size_t k>
struct Child {
......
......@@ -41,6 +41,11 @@ namespace Dune {
//! The type tag that describes a LeafNode.
typedef LeafNodeTag NodeTag;
static constexpr std::size_t degree()
{
return 0;
}
protected:
//! Default constructor.
......
......@@ -65,6 +65,50 @@ namespace Dune {
template<typename T>
using ImplementationTag = typename std::decay_t<T>::ImplementationTag;
//! Returns the degree of node as run time information.
template<typename Node>
std::size_t degree(const Node& node)
{
return degree(&node,NodeTag<Node>());
}
#ifndef DOXYGEN
//! Default implementation of degree dispatch function.
/**
* This dispatches using a pointer to the node instead of a reference,
* as we can easily create a constexpr pointer to the node, while a constexpr
* reference might not even be possible to manufacture (std::declval is not
* constexpr).
*/
template<typename Node, typename NodeTag>
constexpr std::size_t degree(const Node* node, NodeTag)
{
return Node::degree();
}
#endif DOXYGEN
//! Returns the statically known degree of the given Node type as a std::integral_constant.
/**
* \note If you are only interested in the numeric value, take a look at staticDegree<Node>
* instead.
*/
template<typename Node>
using StaticDegree = std::integral_constant<
std::size_t,
degree(
static_cast<std::decay_t<Node>*>(nullptr),
NodeTag<std::decay_t<Node>>()
)
>;
//! Returns the statically known degree of the given Node type as a constant value.
template<typename Node>
constexpr std::size_t staticDegree = StaticDegree<Node>::value;
//! \} group Nodes
} // namespace TypeTree
......
......@@ -105,6 +105,11 @@ namespace Dune {
//! The number of children.
static const std::size_t CHILDREN = k;
static constexpr std::size_t degree()
{
return k;
}
//! The type tag that describes a PowerNode.
typedef PowerNodeTag NodeTag;
......
......@@ -5,6 +5,7 @@
#define DUNE_TYPETREE_PROXYNODE_HH
#include <type_traits>
#include <dune/typetree/nodeinterface.hh>
#include <dune/typetree/nodetags.hh>
#include <dune/common/shared_ptr.hh>
......@@ -277,7 +278,12 @@ namespace Dune {
static const bool isComposite = Node::isComposite;
//! The number of children.
static const std::size_t CHILDREN = Node::CHILDREN;
static const std::size_t CHILDREN = staticDegree<Node>;
static constexpr std::size_t degree()
{
return staticDegree<Node>;
}
protected:
......
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