dune-typetree  2.8-git
powernode.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 
4 #ifndef DUNE_TYPETREE_POWERNODE_HH
5 #define DUNE_TYPETREE_POWERNODE_HH
6 
7 #include <cassert>
8 #include <array>
9 #include <memory>
10 #include <type_traits>
11 
12 #include <dune/common/typetraits.hh>
13 #include <dune/common/std/type_traits.hh>
14 
16 #include <dune/typetree/utility.hh>
19 
20 namespace Dune {
21  namespace TypeTree {
22 
29 #ifndef DOXYGEN
30 
32  template<typename PowerNode, typename T, std::size_t k>
33  struct AssertPowerNodeChildCount
34  : public std::enable_if<std::is_same<
35  typename PowerNode::ChildType,
36  T>::value &&
37  PowerNode::CHILDREN == k,
38  T>
39  {};
40 
41 #endif
42 
48  template<typename T, std::size_t k>
49  class PowerNode
50  {
51 
52  public:
53 
55  static const bool isLeaf = false;
56 
58  static const bool isPower = true;
59 
61  static const bool isComposite = false;
62 
64  static const std::size_t CHILDREN = k;
65 
66  static constexpr auto degree ()
67  {
68  return std::integral_constant<std::size_t,k>{};
69  }
70 
73 
75  typedef T ChildType;
76 
78  typedef std::array<std::shared_ptr<T>,k> NodeStorage;
79 
80 
82  template<std::size_t i>
83  struct Child
84  {
85 
86  static_assert((i < CHILDREN), "child index out of range");
87 
89  typedef T Type;
90 
92  typedef T type;
93  };
94 
97 
99 
102  template<std::size_t i>
103  T& child (index_constant<i> = {})
104  {
105  static_assert((i < CHILDREN), "child index out of range");
106  return *_children[i];
107  }
108 
110 
113  template<std::size_t i>
114  const T& child (index_constant<i> = {}) const
115  {
116  static_assert((i < CHILDREN), "child index out of range");
117  return *_children[i];
118  }
119 
121 
124  template<std::size_t i>
125  std::shared_ptr<T> childStorage (index_constant<i> = {})
126  {
127  static_assert((i < CHILDREN), "child index out of range");
128  return _children[i];
129  }
130 
132 
135  template<std::size_t i>
136  std::shared_ptr<const T> childStorage (index_constant<i> = {}) const
137  {
138  static_assert((i < CHILDREN), "child index out of range");
139  return _children[i];
140  }
141 
143  template<std::size_t i>
144  void setChild (T& t, index_constant<i> = {})
145  {
146  static_assert((i < CHILDREN), "child index out of range");
147  _children[i] = stackobject_to_shared_ptr(t);
148  }
149 
151  template<std::size_t i>
152  void setChild (T&& t, index_constant<i> = {})
153  {
154  static_assert((i < CHILDREN), "child index out of range");
155  _children[i] = convert_arg(std::move(t));
156  }
157 
159  template<std::size_t i>
160  void setChild (std::shared_ptr<T> st, index_constant<i> = {})
161  {
162  static_assert((i < CHILDREN), "child index out of range");
163  _children[i] = std::move(st);
164  }
165 
167 
168 
171 
173 
176  T& child (std::size_t i)
177  {
178  assert(i < CHILDREN && "child index out of range");
179  return *_children[i];
180  }
181 
183 
186  const T& child (std::size_t i) const
187  {
188  assert(i < CHILDREN && "child index out of range");
189  return *_children[i];
190  }
191 
193 
196  std::shared_ptr<T> childStorage (std::size_t i)
197  {
198  assert(i < CHILDREN && "child index out of range");
199  return _children[i];
200  }
201 
203 
206  std::shared_ptr<const T> childStorage (std::size_t i) const
207  {
208  assert(i < CHILDREN && "child index out of range");
209  return _children[i];
210  }
211 
213  void setChild (std::size_t i, T& t)
214  {
215  assert(i < CHILDREN && "child index out of range");
216  _children[i] = stackobject_to_shared_ptr(t);
217  }
218 
220  void setChild (std::size_t i, T&& t)
221  {
222  assert(i < CHILDREN && "child index out of range");
223  _children[i] = convert_arg(std::move(t));
224  }
225 
227  void setChild (std::size_t i, std::shared_ptr<T> st)
228  {
229  assert(i < CHILDREN && "child index out of range");
230  _children[i] = std::move(st);
231  }
232 
233  const NodeStorage& nodeStorage () const
234  {
235  return _children;
236  }
237 
239 
242 
243  // The following two methods require a little bit of SFINAE trickery to work correctly:
244  // We have to make sure that they don't shadow the methods for direct child access because
245  // those get called by the generic child() machinery. If that machinery picks up the methods
246  // defined below, we have an infinite recursion.
247  // So the methods make sure that either
248  //
249  // * there are more than one argument. In that case, we got multiple indices and can forward
250  // to the general machine.
251  //
252  // * the first argument is not a valid flat index, i.e. either a std::size_t or an index_constant.
253  // The argument thus has to be some kind of TreePath instance that we can also pass to the
254  // generic machine.
255  //
256  // The above SFINAE logic works, but there is still a problem with the return type deduction.
257  // We have to do a lazy lookup of the return type after SFINAE has succeeded, otherwise the return
258  // type deduction will trigger the infinite recursion.
259 
261 
265 #ifdef DOXYGEN
266  template<typename... Indices>
267  ImplementationDefined& child (Indices... indices)
268 #else
269  template<typename I0, typename... I,
270  std::enable_if_t<(sizeof...(I) > 0) || IsTreePath<I0>::value, int > = 0>
271  decltype(auto) child (I0 i0, I... i)
272 #endif
273  {
274  static_assert(sizeof...(I) > 0 || impl::_non_empty_tree_path(I0{}),
275  "You cannot use the member function child() with an empty TreePath, use the freestanding version child(node,treePath) instead."
276  );
277  return Dune::TypeTree::child(*this,i0,i...);
278  }
279 
281 
285 #ifdef DOXYGEN
286  template<typename... Indices>
287  const ImplementationDefined& child (Indices... indices)
288 #else
289  template<typename I0, typename... I,
290  std::enable_if_t<(sizeof...(I) > 0) || IsTreePath<I0>::value, int > = 0>
291  decltype(auto) child (I0 i0, I... i) const
292 #endif
293  {
294  static_assert(sizeof...(I) > 0 || impl::_non_empty_tree_path(I0{}),
295  "You cannot use the member function child() with an empty TreePath, use the freestanding version child(node,treePath) instead."
296  );
297  return Dune::TypeTree::child(*this,i0,i...);
298  }
299 
301 
304 
305  protected:
306 
308 
317  {}
318 
320  explicit PowerNode (const NodeStorage& children)
321  : _children(children)
322  {}
323 
325  explicit PowerNode (T& t, bool distinct_objects = true)
326  {
327  if (distinct_objects)
328  {
329  for (typename NodeStorage::iterator it = _children.begin(); it != _children.end(); ++it)
330  *it = std::make_shared<T>(t);
331  }
332  else
333  {
334  std::shared_ptr<T> sp = stackobject_to_shared_ptr(t);
335  std::fill(_children.begin(),_children.end(),sp);
336  }
337  }
338 
339 #ifdef DOXYGEN
340 
342  PowerNode(T& t1, T& t2, ...)
343  {}
344 
345 #else
346 
347  template<typename... Children,
348  std::enable_if_t<
349  std::conjunction<std::is_same<ChildType, std::decay_t<Children>>...>::value
350  ,int> = 0>
351  PowerNode (Children&&... children)
352  {
353  static_assert(CHILDREN == sizeof...(Children), "PowerNode constructor is called with incorrect number of children");
354  _children = NodeStorage{convert_arg(std::forward<Children>(children))...};
355  }
356 
357  template<typename... Children,
358  std::enable_if_t<
359  std::conjunction<std::is_same<ChildType, Children>...>::value
360  ,int> = 0>
361  PowerNode (std::shared_ptr<Children>... children)
362  {
363  static_assert(CHILDREN == sizeof...(Children), "PowerNode constructor is called with incorrect number of children");
364  _children = NodeStorage{children...};
365  }
366 
367 #endif // DOXYGEN
368 
370 
371  private:
372  NodeStorage _children;
373  };
374 
376 
377  } // namespace TypeTree
378 } //namespace Dune
379 
380 #endif // DUNE_TYPETREE_POWERNODE_HH
ImplementationDefined child(Node &&node, Indices... indices)
Extracts the child of a node given by a sequence of compile-time and run-time indices.
Definition: childextraction.hh:126
Definition: accumulate_static.hh:13
Tag designating a power node.
Definition: nodetags.hh:19
Collect k instances of type T within a dune-typetree.
Definition: powernode.hh:50
void setChild(T &t, index_constant< i >={})
Sets the i-th child to the passed-in value.
Definition: powernode.hh:144
ImplementationDefined & child(Indices... indices)
Returns the child given by the list of indices.
Definition: powernode.hh:267
const T & child(std::size_t i) const
Returns the i-th child (const version).
Definition: powernode.hh:186
void setChild(std::shared_ptr< T > st, index_constant< i >={})
Sets the stored value representing the i-th child to the passed-in value.
Definition: powernode.hh:160
PowerNode(T &t1, T &t2,...)
Initialize all children with the passed-in objects.
Definition: powernode.hh:342
const ImplementationDefined & child(Indices... indices)
Returns the child given by the list of indices.
Definition: powernode.hh:287
std::shared_ptr< T > childStorage(index_constant< i >={})
Returns the storage of the i-th child.
Definition: powernode.hh:125
std::array< std::shared_ptr< T >, k > NodeStorage
The type used for storing the children.
Definition: powernode.hh:78
std::shared_ptr< const T > childStorage(index_constant< i >={}) const
Returns the storage of the i-th child (const version).
Definition: powernode.hh:136
PowerNode(T &t, bool distinct_objects=true)
Initialize all children with copies of a storage object constructed from the parameter t.
Definition: powernode.hh:325
PowerNodeTag NodeTag
The type tag that describes a PowerNode.
Definition: powernode.hh:72
static constexpr auto degree()
Definition: powernode.hh:66
static const std::size_t CHILDREN
The number of children.
Definition: powernode.hh:64
const NodeStorage & nodeStorage() const
Definition: powernode.hh:233
void setChild(std::size_t i, std::shared_ptr< T > st)
Sets the stored value representing the i-th child to the passed-in value.
Definition: powernode.hh:227
static const bool isComposite
Mark this class as a non composite in the dune-typetree.
Definition: powernode.hh:61
std::shared_ptr< const T > childStorage(std::size_t i) const
Returns the storage of the i-th child (const version).
Definition: powernode.hh:206
static const bool isLeaf
Mark this class as non leaf in the dune-typetree.
Definition: powernode.hh:55
T & child(index_constant< i >={})
Returns the i-th child.
Definition: powernode.hh:103
static const bool isPower
Mark this class as a power in the dune-typetree.
Definition: powernode.hh:58
PowerNode(const NodeStorage &children)
Initialize the PowerNode with a copy of the passed-in storage type.
Definition: powernode.hh:320
T ChildType
The type of each child.
Definition: powernode.hh:75
T & child(std::size_t i)
Returns the i-th child.
Definition: powernode.hh:176
void setChild(std::size_t i, T &&t)
Store the passed value in i-th child.
Definition: powernode.hh:220
void setChild(T &&t, index_constant< i >={})
Store the passed value in i-th child.
Definition: powernode.hh:152
std::shared_ptr< T > childStorage(std::size_t i)
Returns the storage of the i-th child.
Definition: powernode.hh:196
const T & child(index_constant< i >={}) const
Returns the i-th child (const version).
Definition: powernode.hh:114
PowerNode()
Default constructor.
Definition: powernode.hh:316
void setChild(std::size_t i, T &t)
Sets the i-th child to the passed-in value.
Definition: powernode.hh:213
Access to the type and storage type of the i-th child.
Definition: powernode.hh:84
T type
The type of the child.
Definition: powernode.hh:92
T Type
The type of the child.
Definition: powernode.hh:86
Check if type represents a tree path.
Definition: typetraits.hh:190