"Fossies" - the Fresh Open Source Software Archive

Member "dune-typetree-2.8.0/dune/typetree/treecontainer.hh" (31 Aug 2021, 11030 Bytes) of package /linux/misc/dune/dune-typetree-2.8.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "treecontainer.hh" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.8.0_vs_2.9.0.

    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_TREECONTAINER_HH
    5 #define DUNE_TYPETREE_TREECONTAINER_HH
    6 
    7 #include <type_traits>
    8 #include <utility>
    9 #include <functional>
   10 #include <array>
   11 
   12 #include <dune/common/indices.hh>
   13 #include <dune/common/hybridutilities.hh>
   14 #include <dune/common/rangeutilities.hh>
   15 #include <dune/common/tuplevector.hh>
   16 
   17 #include <dune/typetree/treepath.hh>
   18 
   19 namespace Dune {
   20   namespace TypeTree {
   21 
   22     namespace Detail {
   23 
   24       /*
   25        * \brief A factory class creating a hybrid container compatible with a type tree
   26        *
   27        * This class allows to create a nested hybrid container having the same structure
   28        * as a given type tree. Power nodes are represented as std::array's while composite
   29        * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
   30        * are creating using a given predicate. Once created, the factory provides an
   31        * operator() creating the container for the tree given as argument.
   32        *
   33        * \tparam LeafToValue Type of a predicate that determines the stored values at the leafs
   34        */
   35       template<class LeafToValue>
   36       class ContainerFactory
   37       {
   38         template<class N>
   39         using DynamicDegreeConcept = decltype((std::size_t(std::declval<N>().degree()), true));
   40 
   41         template<class N>
   42         using StaticDegreeConcept = decltype((std::integral_constant<std::size_t, N::degree()>{}, true));
   43 
   44         template<class N>
   45         using DynamicChildAccessConcept = decltype((std::declval<N>().child(0u), true));
   46 
   47       public:
   48 
   49         /**
   50          * \brief Create ContainerFactory
   51          *
   52          * The given predicate will be stored by value.
   53          *
   54          * \param A predicate used to generate the stored values for the leaves
   55          */
   56         ContainerFactory(LeafToValue leafToValue) :
   57           leafToValue_(leafToValue)
   58         {}
   59 
   60         template<class Node>
   61         auto operator()(const Node& node)
   62         {
   63           return (*this)(node, Dune::PriorityTag<5>{});
   64         }
   65 
   66       private:
   67 
   68         template<class Node,
   69           std::enable_if_t<Node::isLeaf, bool> = true>
   70         auto operator()(const Node& node, Dune::PriorityTag<4>)
   71         {
   72           return leafToValue_(node);
   73         }
   74 
   75         template<class Node,
   76           StaticDegreeConcept<Node> = true,
   77           DynamicChildAccessConcept<Node> = true>
   78         auto operator()(const Node& node, Dune::PriorityTag<3>)
   79         {
   80           return Dune::unpackIntegerSequence([&](auto... indices) {
   81               return std::array{(*this)(node.child(indices))...};
   82             }, std::make_index_sequence<std::size_t(Node::degree())>());
   83         }
   84 
   85         template<class Node,
   86           DynamicDegreeConcept<Node> = true,
   87           DynamicChildAccessConcept<Node> = true>
   88         auto operator()(const Node& node, Dune::PriorityTag<2>)
   89         {
   90           using TransformedChild = decltype((*this)(node.child(0)));
   91           std::vector<TransformedChild> container;
   92           container.reserve(node.degree());
   93           for (std::size_t i = 0; i < node.degree(); ++i)
   94             container.emplace_back((*this)(node.child(i)));
   95           return container;
   96         }
   97 
   98         template<class Node,
   99           StaticDegreeConcept<Node> = true>
  100         auto operator()(const Node& node, Dune::PriorityTag<1>)
  101         {
  102           return Dune::unpackIntegerSequence([&](auto... indices) {
  103               return Dune::makeTupleVector((*this)(node.child(indices))...);
  104             }, std::make_index_sequence<std::size_t(Node::degree())>());
  105         }
  106 
  107       private:
  108         LeafToValue leafToValue_;
  109       };
  110 
  111 
  112       /*
  113        * \brief Wrap nested container to provide a VectorBackend
  114        */
  115       template<class Container>
  116       class TreeContainerVectorBackend
  117       {
  118         template<class C>
  119         static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<>& path)
  120         {
  121           return container;
  122         }
  123 
  124         template<class C, class... T>
  125         static constexpr decltype(auto) accessByTreePath(C&& container, const HybridTreePath<T...>& path)
  126         {
  127           auto head = path[Dune::Indices::_0];
  128           auto tailPath = Dune::unpackIntegerSequence([&](auto... i){
  129                         return treePath(path[i+1]...);
  130                       }, std::make_index_sequence<sizeof...(T)-1>());
  131           return accessByTreePath(container[head], tailPath);
  132         }
  133 
  134         template<class C, class Tree,
  135           std::enable_if_t<Tree::isLeaf, bool> = true>
  136         static void resizeImpl(C& /*container*/, const Tree& /*tree*/, Dune::PriorityTag<2>)
  137         {
  138           /* do nothing */
  139         }
  140 
  141         template<class C, class Tree,
  142           class = decltype(std::declval<C>().resize(0u))>
  143         static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<1>)
  144         {
  145           container.resize(tree.degree());
  146           Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
  147             resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
  148           });
  149         }
  150 
  151         template<class C, class Tree>
  152         static void resizeImpl(C& container, const Tree& tree, Dune::PriorityTag<0>)
  153         {
  154           Dune::Hybrid::forEach(Dune::range(tree.degree()), [&](auto i) {
  155             resizeImpl(container[i], tree.child(i), Dune::PriorityTag<5>{});
  156           });
  157         }
  158 
  159         template<class T>
  160         using TypeTreeConcept = decltype((
  161           std::declval<T>().degree(),
  162           T::isLeaf,
  163           T::isPower,
  164           T::isComposite,
  165         true));
  166 
  167       public:
  168         //! Move the passed container into the internal storage
  169         TreeContainerVectorBackend(Container&& container) :
  170           container_(std::move(container))
  171         {}
  172 
  173         //! Default construct the container and perform a resize depending on the tree-node degrees.
  174         template <class Tree, TypeTreeConcept<Tree> = true>
  175         TreeContainerVectorBackend(const Tree& tree) :
  176           TreeContainerVectorBackend()
  177         {
  178           this->resize(tree);
  179         }
  180 
  181         //! Default constructor. The stored container might need to be resized before usage.
  182         template <class C = Container,
  183           std::enable_if_t<std::is_default_constructible_v<C>, bool> = true>
  184         TreeContainerVectorBackend() :
  185           container_()
  186         {}
  187 
  188         template<class... T>
  189         decltype(auto) operator[](const HybridTreePath<T...>&  path) const
  190         {
  191           return accessByTreePath(container_, path);
  192         }
  193 
  194         template<class... T>
  195         decltype(auto) operator[](const HybridTreePath<T...>&  path)
  196         {
  197           return accessByTreePath(container_, path);
  198         }
  199 
  200         //! Resize the (nested) container depending on the degree of the tree nodes
  201         template<class Tree, TypeTreeConcept<Tree> = true>
  202         void resize(const Tree& tree)
  203         {
  204           resizeImpl(container_, tree, Dune::PriorityTag<5>{});
  205         }
  206 
  207         const Container& data() const
  208         {
  209           return container_;
  210         }
  211 
  212         Container& data()
  213         {
  214           return container_;
  215         }
  216 
  217       private:
  218         Container container_;
  219       };
  220 
  221       template<class Container>
  222       auto makeTreeContainerVectorBackend(Container&& container)
  223       {
  224         return TreeContainerVectorBackend<std::decay_t<Container>>(std::forward<Container>(container));
  225       }
  226 
  227       /*
  228        * \brief A simple lambda for creating default constructible values from a node
  229        *
  230        * This simply returns LeafToValue<Node>{} for a given Node. It's needed
  231        * because using a lambda expression in a using declaration is not allowed
  232        * because it's an unevaluated context.
  233        */
  234       template<template<class Node> class LeafToValue>
  235       struct LeafToDefaultConstructibleValue
  236       {
  237         template<class Node>
  238         auto operator()(const Node& node) const
  239         {
  240           return LeafToValue<Node>{};
  241         }
  242       };
  243 
  244     } // namespace Detail
  245 
  246     /** \addtogroup TypeTree
  247      *  \{
  248      */
  249 
  250     /**
  251      * \brief Create container havin the same structure as the given tree
  252      *
  253      * This class allows to create a nested hybrid container having the same structure
  254      * as a given type tree. Power nodes are represented as std::array's while composite
  255      * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
  256      * are creating using a given predicate. For convenience the created container is
  257      * not returned directly. Instead, the returned object stores the container and
  258      * provides operator[] access using a HybridTreePath.
  259      *
  260      * \param tree The tree which should be mapper to a container
  261      * \param leafToValue A predicate used to generate the stored values for the leaves
  262      *
  263      * \returns A container matching the tree structure
  264      */
  265     template<class Tree, class LeafToValue>
  266     auto makeTreeContainer(const Tree& tree, LeafToValue&& leafToValue)
  267     {
  268       auto f = std::ref(leafToValue);
  269       auto factory = Detail::ContainerFactory<decltype(f)>(f);
  270       return Detail::makeTreeContainerVectorBackend(factory(tree));
  271     }
  272 
  273     /**
  274      * \brief Create container havin the same structure as the given tree
  275      *
  276      * This class allows to create a nested hybrid container having the same structure
  277      * as a given type tree. Power nodes are represented as std::array's while composite
  278      * nodes are represented as Dune::TupleVector's. The stored values for the leaf nodes
  279      * are of the given type Value. For convenience the created container is
  280      * not returned directly. Instead, the returned object stores the container and
  281      * provides operator[] access using a HybridTreePath.
  282      *
  283      * \tparam Value Type of the values to be stored for the leafs. Should be default constructible.
  284      * \param leafToValue A predicate used to generate the stored values for the leaves
  285      *
  286      * \returns A container matching the tree structure
  287      */
  288     template<class Value, class Tree>
  289     auto makeTreeContainer(const Tree& tree)
  290     {
  291       return makeTreeContainer(tree, [](const auto&) {return Value{};});
  292     }
  293 
  294     /**
  295      * \brief Alias to container type generated by makeTreeContainer for given tree type and uniform value type
  296      */
  297     template<class Value, class Tree>
  298     using UniformTreeContainer = std::decay_t<decltype(makeTreeContainer<Value>(std::declval<const Tree&>()))>;
  299 
  300     /**
  301      * \brief Alias to container type generated by makeTreeContainer for give tree type and when using LeafToValue to create values
  302      */
  303     template<template<class Node> class LeafToValue, class Tree>
  304     using TreeContainer = std::decay_t<decltype(makeTreeContainer(std::declval<const Tree&>(), std::declval<Detail::LeafToDefaultConstructibleValue<LeafToValue>>()))>;
  305 
  306     //! \} group TypeTree
  307 
  308   } // namespace TypeTree
  309 } //namespace Dune
  310 
  311 #endif // DUNE_TYPETREE_TREECONTAINER_HH