dune-typetree  2.5.0
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 
10 #include <dune/common/typetraits.hh>
11 
13 #include <dune/typetree/utility.hh>
15 
16 namespace Dune {
17  namespace TypeTree {
18 
24 #ifndef DOXYGEN
25 
26  namespace {
27 
28  // prototype and end of recursion
29  template<typename T, typename It, typename... Args>
30  void assign_reference_pack_to_shared_ptr_array_unpack(It it, Args&&... args) {}
31 
32  template<typename T, typename It, typename Arg, typename... Args>
33  void assign_reference_pack_to_shared_ptr_array_unpack(It it, Arg&& arg, Args&&... args)
34  {
35  static_assert(std::is_same<T,typename std::remove_const<typename std::remove_reference<Arg>::type>::type>::value,"type mismatch during array conversion");
36  *it = convert_arg(std::forward<Arg>(arg));
37  assign_reference_pack_to_shared_ptr_array_unpack<T>(++it,std::forward<Args>(args)...);
38  }
39 
40  template<typename T, std::size_t n, typename... Args>
41  void assign_reference_pack_to_shared_ptr_array(std::array<shared_ptr<T>,n>& res, Args&&... args)
42  {
43  static_assert(sizeof...(Args) == n, "invalid number of arguments");
44  return assign_reference_pack_to_shared_ptr_array_unpack<T>(res.begin(),std::forward<Args>(args)...);
45  }
46 
47 
48  // prototype and end of recursion
49  template<typename T, typename It, typename... Args>
50  void assign_shared_ptr_pack_to_shared_ptr_array_unpack(It it, Args&&... args) {}
51 
52  template<typename T, typename It, typename Arg, typename... Args>
53  void assign_shared_ptr_pack_to_shared_ptr_array_unpack(It it, Arg&& arg, Args&&... args)
54  {
55  static_assert(std::is_same<T,typename std::remove_reference<Arg>::type::element_type>::value,"type mismatch during array conversion");
56  *it = arg;
57  assign_shared_ptr_pack_to_shared_ptr_array_unpack<T>(++it,args...);
58  }
59 
60  template<typename T, std::size_t n, typename... Args>
61  void assign_shared_ptr_pack_to_shared_ptr_array(std::array<shared_ptr<T>,n>& res, Args&&... args)
62  {
63  static_assert(sizeof...(Args) == n, "invalid number of arguments");
64  return assign_shared_ptr_pack_to_shared_ptr_array_unpack<T>(res.begin(),args...);
65  }
66 
67  } // anonymous namespace
68 
69 #endif
70 
71 #ifndef DOXYGEN
72 
74  template<typename PowerNode, typename T, std::size_t k>
75  struct AssertPowerNodeChildCount
76  : public std::enable_if<std::is_same<
77  typename PowerNode::ChildType,
78  T>::value &&
79  PowerNode::CHILDREN == k,
80  T>
81  {};
82 
83 #endif
84 
90  template<typename T, std::size_t k>
91  class PowerNode
92  {
93 
94  public:
95 
97  static const bool isLeaf = false;
98 
100  static const bool isPower = true;
101 
103  static const bool isComposite = false;
104 
106  static const std::size_t CHILDREN = k;
107 
108  static constexpr std::size_t degree()
109  {
110  return k;
111  }
112 
115 
117  typedef T ChildType;
118 
120  typedef shared_ptr<T> ChildStorageType;
121 
123  typedef shared_ptr<const T> ChildConstStorageType;
124 
126  typedef std::array<ChildStorageType,k> NodeStorage;
127 
128 
130  template<std::size_t i>
131  struct Child
132  {
133 
134  static_assert((i < CHILDREN), "child index out of range");
135 
137  typedef T Type;
138 
140  typedef T type;
141 
143  typedef ChildStorageType Storage;
144 
146  typedef ChildConstStorageType ConstStorage;
147  };
148 
151 
153 
156  template<std::size_t i>
157  T& child (index_constant<i> = {})
158  {
159  static_assert((i < CHILDREN), "child index out of range");
160  return *_children[i];
161  }
162 
164 
167  template<std::size_t i>
168  const T& child (index_constant<i> = {}) const
169  {
170  static_assert((i < CHILDREN), "child index out of range");
171  return *_children[i];
172  }
173 
175 
178  template<std::size_t i>
179  ChildStorageType childStorage(index_constant<i> = {})
180  {
181  static_assert((i < CHILDREN), "child index out of range");
182  return _children[i];
183  }
184 
186 
192  template<std::size_t i>
193  ChildConstStorageType childStorage(index_constant<i> = {}) const
194  {
195  static_assert((i < CHILDREN), "child index out of range");
196  return _children[i];
197  }
198 
200  template<std::size_t i>
201  void setChild (T& t, index_constant<i> = {})
202  {
203  static_assert((i < CHILDREN), "child index out of range");
204  _children[i] = stackobject_to_shared_ptr(t);
205  }
206 
208  template<std::size_t i>
209  void setChild(T&& t, index_constant<i> = {})
210  {
211  static_assert((i < CHILDREN), "child index out of range");
212  _children[i] = convert_arg(std::move(t));
213  }
214 
216  template<std::size_t i>
217  void setChild (ChildStorageType st, index_constant<i> = {})
218  {
219  static_assert((i < CHILDREN), "child index out of range");
220  _children[i] = st;
221  }
222 
224 
225 
228 
230 
233  T& child (std::size_t i)
234  {
235  assert(i < CHILDREN && "child index out of range");
236  return *_children[i];
237  }
238 
240 
243  const T& child (std::size_t i) const
244  {
245  assert(i < CHILDREN && "child index out of range");
246  return *_children[i];
247  }
248 
250 
253  ChildStorageType childStorage(std::size_t i)
254  {
255  assert(i < CHILDREN && "child index out of range");
256  return _children[i];
257  }
258 
260 
266  ChildConstStorageType childStorage (std::size_t i) const
267  {
268  assert(i < CHILDREN && "child index out of range");
269  return (_children[i]);
270  }
271 
273  void setChild (std::size_t i, T& t)
274  {
275  assert(i < CHILDREN && "child index out of range");
276  _children[i] = stackobject_to_shared_ptr(t);
277  }
278 
280  void setChild(std::size_t i, T&& t)
281  {
282  assert(i < CHILDREN && "child index out of range");
283  _children[i] = convert_arg(std::move(t));
284  }
285 
287  void setChild (std::size_t i, ChildStorageType st)
288  {
289  assert(i < CHILDREN && "child index out of range");
290  _children[i] = st;
291  }
292 
293  const NodeStorage& nodeStorage() const
294  {
295  return _children;
296  }
297 
299 
302 
303  // The following two methods require a little bit of SFINAE trickery to work correctly:
304  // We have to make sure that they don't shadow the methods for direct child access because
305  // those get called by the generic child() machinery. If that machinery picks up the methods
306  // defined below, we have an infinite recursion.
307  // So the methods make sure that either
308  //
309  // * there are more than one argument. In that case, we got multiple indices and can forward
310  // to the general machine.
311  //
312  // * the first argument is not a valid flat index, i.e. either a std::size_t or an index_constant.
313  // The argument thus has to be some kind of TreePath instance that we can also pass to the
314  // generic machine.
315  //
316  // The above SFINAE logic works, but there is still a problem with the return type deduction.
317  // We have to do a lazy lookup of the return type after SFINAE has succeeded, otherwise the return
318  // type deduction will trigger the infinite recursion.
319 
321 
325 #ifdef DOXYGEN
326  template<typename... Indices>
327  ImplementationDefined& child(Indices... indices)
328 #else
329  template<typename I0, typename... I>
330  auto child(I0 i0, I... i)
331  -> typename std::enable_if<
332  (sizeof...(I) > 0) || !is_flat_index<I0>{},
333  impl::_lazy_member_child_decltype<PowerNode>
334  >::type::template evaluate<I0,I...>::type
335 #endif
336  {
337  static_assert(sizeof...(I) > 0 || impl::_non_empty_tree_path(I0{}),
338  "You cannot use the member function child() with an empty TreePath, use the freestanding version child(node,treePath) instead."
339  );
340  return Dune::TypeTree::child(*this,i0,i...);
341  }
342 
344 
348 #ifdef DOXYGEN
349  template<typename... Indices>
350  const ImplementationDefined& child(Indices... indices)
351 #else
352  template<typename I0, typename... I>
353  auto child(I0 i0, I... i) const
354  -> typename std::enable_if<
355  (sizeof...(I) > 0) || !is_flat_index<I0>{},
356  impl::_lazy_member_child_decltype<const PowerNode>
357  >::type::template evaluate<I0,I...>::type
358 #endif
359  {
360  static_assert(sizeof...(I) > 0 || impl::_non_empty_tree_path(I0{}),
361  "You cannot use the member function child() with an empty TreePath, use the freestanding version child(node,treePath) instead."
362  );
363  return Dune::TypeTree::child(*this,i0,i...);
364  }
365 
367 
370 
371  protected:
372 
374 
383  {}
384 
386  explicit PowerNode(const NodeStorage& children)
387  : _children(children)
388  {}
389 
391  explicit PowerNode (T& t, bool distinct_objects = true)
392  {
393  if (distinct_objects)
394  {
395  for (typename NodeStorage::iterator it = _children.begin(); it != _children.end(); ++it)
396  *it = std::make_shared<T>(t);
397  }
398  else
399  {
400  shared_ptr<T> sp = stackobject_to_shared_ptr(t);
401  std::fill(_children.begin(),_children.end(),sp);
402  }
403  }
404 
405 #ifdef DOXYGEN
406 
408 
418  PowerNode(T& t1, T& t2, ...)
419  {}
420 
421 #else
422 
423  // this weird signature avoids shadowing other 1-argument constructors
424  template<typename C0, typename C1, typename... Children>
425  PowerNode (C0&& c0, C1&& c1, Children&&... children)
426  {
427  assign_reference_pack_to_shared_ptr_array(_children,std::forward<C0>(c0),std::forward<C1>(c1),std::forward<Children>(children)...);
428  }
429 
430  // this weird signature avoids shadowing other 1-argument constructors
431  template<typename C0, typename C1, typename... Children>
432  PowerNode (shared_ptr<C0> c0, shared_ptr<C1> c1, shared_ptr<Children>... children)
433  {
434  assign_shared_ptr_pack_to_shared_ptr_array(_children,c0,c1,children...);
435  }
436 
437 #endif // DOXYGEN
438 
440 
441  private:
442  NodeStorage _children;
443  };
444 
446 
447  } // namespace TypeTree
448 } //namespace Dune
449 
450 #endif // DUNE_TYPETREE_POWERNODE_HH
T Type
The type of the child.
Definition: powernode.hh:134
const T & child(std::size_t i) const
Returns the i-th child (const version).
Definition: powernode.hh:243
ChildStorageType childStorage(std::size_t i)
Returns the storage of the i-th child.
Definition: powernode.hh:253
void setChild(std::size_t i, T &t)
Sets the i-th child to the passed-in value.
Definition: powernode.hh:273
const NodeStorage & nodeStorage() const
Definition: powernode.hh:293
void setChild(std::size_t i, T &&t)
Store the passed value in i-th child.
Definition: powernode.hh:280
shared_ptr< const T > ChildConstStorageType
The const version of the storage type of each child.
Definition: powernode.hh:123
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:179
const ImplementationDefined & child(Indices... indices)
Returns the child given by the list of indices.
Definition: powernode.hh:350
ChildConstStorageType childStorage(std::size_t i) const
Returns the storage of the i-th child (const version).
Definition: powernode.hh:266
std::array< ChildStorageType, k > NodeStorage
The type used for storing the children.
Definition: powernode.hh:126
void setChild(std::size_t i, ChildStorageType st)
Sets the stored value representing the i-th child to the passed-in value.
Definition: powernode.hh:287
PowerNode(const NodeStorage &children)
Initialize the PowerNode with a copy of the passed-in storage type.
Definition: powernode.hh:386
Collect k instances of type T within a dune-typetree.
Definition: powernode.hh:91
ImplementationDefined & child(Indices... indices)
Returns the child given by the list of indices.
Definition: powernode.hh:327
shared_ptr< T > ChildStorageType
The storage type of each child.
Definition: powernode.hh:120
void setChild(T &t, index_constant< i >={})
Sets the i-th child to the passed-in value.
Definition: powernode.hh:201
T & child(index_constant< i >={})
Returns the i-th child.
Definition: powernode.hh:157
Tag designating a power node.
Definition: nodetags.hh:19
Definition: accumulate_static.hh:13
const T & child(index_constant< i >={}) const
Returns the i-th child (const version).
Definition: powernode.hh:168
PowerNode(T &t1, T &t2,...)
Initialize all children with the passed-in objects.
Definition: powernode.hh:418
PowerNodeTag NodeTag
The type tag that describes a PowerNode.
Definition: powernode.hh:114
PowerNode()
Default constructor.
Definition: powernode.hh:382
static constexpr std::size_t degree()
Definition: powernode.hh:108
void setChild(ChildStorageType st, index_constant< i >={})
Sets the stored value representing the i-th child to the passed-in value.
Definition: powernode.hh:217
ChildStorageType Storage
The storage type of the child.
Definition: powernode.hh:143
T & child(std::size_t i)
Returns the i-th child.
Definition: powernode.hh:233
T ChildType
The type of each child.
Definition: powernode.hh:117
ChildConstStorageType childStorage(index_constant< i >={}) const
Returns the storage of the i-th child (const version).
Definition: powernode.hh:193
typename impl::_is_flat_index< std::decay_t< T > >::type is_flat_index
Type trait that determines whether T is a flat index in the context of child extraction.
Definition: childextraction.hh:366
PowerNode(T &t, bool distinct_objects=true)
Initialize all children with copies of a storage object constructed from the parameter t...
Definition: powernode.hh:391
void setChild(T &&t, index_constant< i >={})
Store the passed value in i-th child.
Definition: powernode.hh:209
ChildStorageType childStorage(index_constant< i >={})
Returns the storage of the i-th child.
Definition: powernode.hh:179
Access to the type and storage type of the i-th child.
Definition: powernode.hh:131
ChildConstStorageType ConstStorage
The const storage type of the child.
Definition: powernode.hh:146
T type
The type of the child.
Definition: powernode.hh:140