"Fossies" - the Fresh Open Source Software Archive

Member "dune-typetree-2.8.0/dune/typetree/transformation.hh" (31 Aug 2021, 23610 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 "transformation.hh" see the Fossies "Dox" file reference documentation.

    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_TRANSFORMATION_HH
    5 #define DUNE_TYPETREE_TRANSFORMATION_HH
    6 
    7 #include <array>
    8 #include <tuple>
    9 #include <memory>
   10 #include <utility>
   11 
   12 #include <dune/common/hybridutilities.hh>
   13 #include <dune/common/exceptions.hh>
   14 #include <dune/common/typetraits.hh>
   15 #include <dune/typetree/typetraits.hh>
   16 #include <dune/typetree/nodeinterface.hh>
   17 #include <dune/typetree/nodetags.hh>
   18 #include <dune/typetree/utility.hh>
   19 
   20 
   21 namespace Dune {
   22   namespace TypeTree {
   23 
   24     /** \addtogroup Transformation
   25      *  \ingroup TypeTree
   26      *  \{
   27      */
   28 
   29 #ifdef DOXYGEN
   30 
   31     //! Register transformation descriptor to transform SourceNode with Transformation.
   32     /**
   33      * The tree transformation engine expects this function to return a struct describing
   34      * how to perform the Transformation for the type SourceNode, which has ImplementationTag Tag.
   35      * This function has to be specialized for every combination of Transformation and Tag that
   36      * the transformation engine should support.
   37      *
   38      * \note The arguments are given as pointers to avoid problems with incomplete types.
   39      *
   40      * \note The specialization does not have to placed in the namespace Dune::TypeTree,
   41      *       it can simply reside in the same namespace as either the SourceNode or the Tag.
   42      *
   43      * \note This function will never be really called, the engine only extracts the return type.
   44      *       It is thus not necessary to actually implement the function, it is sufficient to
   45      *       declare it.
   46      *
   47      * \tparam SourceNode     The type of the node in the source tree that should be transformed.
   48      * \tparam Transformation The type of the transformation to apply to the source node.
   49      * \tparam Tag            The implementation tag of the source node.
   50      */
   51     template<typename SourceNode, typename Transformation, typename Tag>
   52     void registerNodeTransformation(SourceNode*, Transformation*, Tag*);
   53 
   54 #else // DOXYGEN
   55 
   56       /**
   57        * \tparam S   C++ type of source node.
   58        * \tparam T   Tag identifying the transformation.
   59        * \tparam Tag Tag identifying the source type.
   60        *
   61        * Tag may be identical for different implementation of the same concept
   62        * (i.e. all leaf GridFunctionSpace), but this is not required.  This
   63        * allows you to handle different leaf GridFunctionSpace implementation
   64        * differently.  Tag should be extracted from S::ImplementationTag.
   65        */
   66     template<typename S, typename T, typename Tag>
   67     struct LookupNodeTransformation
   68     {
   69 
   70       typedef decltype(registerNodeTransformation(declptr<S>(),declptr<T>(),declptr<Tag>())) lookup_type;
   71 
   72       typedef typename evaluate_if_meta_function<
   73         lookup_type
   74         >::type type;
   75 
   76       static_assert((!std::is_same<type,void>::value), "Unable to find valid transformation descriptor");
   77     };
   78 
   79 #endif // DOXYGEN
   80 
   81 
   82     //! Transform a TypeTree.
   83     /**
   84      * This struct can be used to apply a transformation to a given TypeTree. It exports the type of
   85      * the resulting (transformed) tree and contains methods to actually transform tree instances.
   86      *
   87      * \tparam SourceTree     = The TypeTree that should be transformed.
   88      * \tparam Transformation = The Transformation to apply to the TypeTree.
   89      * \tparam Tag            = This parameter is an implementation detail and must always be set to its default value.
   90      * \tparam recursive      = This parameter is an implementation detail and must always be set to its default value.
   91      */
   92     template<typename SourceTree, typename Transformation, typename Tag = StartTag, bool recursive = true>
   93     struct TransformTree
   94     {
   95 
   96 #ifndef DOXYGEN
   97 
   98       typedef typename LookupNodeTransformation<SourceTree,Transformation,typename SourceTree::ImplementationTag>::type NodeTransformation;
   99 
  100       // the type of the new tree that will result from this transformation
  101       typedef typename TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transformed_type transformed_type;
  102 
  103       // the storage type of the new tree that will result from this transformation
  104       typedef typename TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transformed_storage_type transformed_storage_type;
  105 
  106 #endif // DOXYGEN
  107 
  108       //! The type of the transformed tree.
  109       typedef transformed_type type;
  110 
  111       typedef type Type;
  112 
  113       //! Apply transformation to an existing tree s.
  114       static transformed_type transform(const SourceTree& s, const Transformation& t = Transformation())
  115       {
  116         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(s,t);
  117       }
  118 
  119       //! Apply transformation to an existing tree s.
  120       static transformed_type transform(const SourceTree& s, Transformation& t)
  121       {
  122         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(s,t);
  123       }
  124 
  125       //! Apply transformation to an existing tree s.
  126       static transformed_type transform(std::shared_ptr<const SourceTree> sp, const Transformation& t = Transformation())
  127       {
  128         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(sp,t);
  129       }
  130 
  131       //! Apply transformation to an existing tree s.
  132       static transformed_type transform(std::shared_ptr<const SourceTree> sp, Transformation& t)
  133       {
  134         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform(sp,t);
  135       }
  136 
  137       //! Apply transformation to storage type of an existing tree, returning a heap-allocated storage type
  138       //! instance of the transformed tree.
  139       static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, const Transformation& t = Transformation())
  140       {
  141         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
  142       }
  143 
  144       //! Apply transformation to storage type of an existing tree, returning a heap-allocated storage type
  145       //! instance of the transformed tree.
  146       static transformed_storage_type transform_storage(std::shared_ptr<const SourceTree> sp, Transformation& t)
  147       {
  148         return TransformTree<SourceTree,Transformation,NodeTag<SourceTree>,NodeTransformation::recursive>::transform_storage(sp,t);
  149       }
  150 
  151 
  152     };
  153 
  154 #ifndef DOXYGEN // internal per-node implementations of the transformation algorithm
  155 
  156     // handle a leaf node - this is easy
  157     template<typename S, typename T, bool recursive>
  158     struct TransformTree<S,T,LeafNodeTag,recursive>
  159     {
  160       // get transformed type from specification
  161       typedef typename LookupNodeTransformation<S,T,ImplementationTag<S>>::type NodeTransformation;
  162 
  163       typedef typename NodeTransformation::transformed_type transformed_type;
  164       typedef typename NodeTransformation::transformed_storage_type transformed_storage_type;
  165 
  166       // delegate instance transformation to per-node specification
  167       static transformed_type transform(const S& s, T& t)
  168       {
  169         return NodeTransformation::transform(s,t);
  170       }
  171 
  172       // delegate instance transformation to per-node specification
  173       static transformed_type transform(const S& s, const T& t)
  174       {
  175         return NodeTransformation::transform(s,t);
  176       }
  177 
  178       // delegate instance transformation to per-node specification
  179       static transformed_type transform(std::shared_ptr<const S> sp, T& t)
  180       {
  181         return NodeTransformation::transform(sp,t);
  182       }
  183 
  184       // delegate instance transformation to per-node specification
  185       static transformed_type transform(std::shared_ptr<const S> sp, const T& t)
  186       {
  187         return NodeTransformation::transform(sp,t);
  188       }
  189 
  190       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
  191       {
  192         return NodeTransformation::transform_storage(sp,t);
  193       }
  194 
  195       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
  196       {
  197         return NodeTransformation::transform_storage(sp,t);
  198       }
  199 
  200     };
  201 
  202 
  203     // common implementation for non-recursive transformation of non-leaf nodes
  204     template<typename S, typename T>
  205     struct TransformTreeNonRecursive
  206     {
  207       // get transformed type from specification
  208       typedef typename LookupNodeTransformation<S,T,ImplementationTag<S>>::type NodeTransformation;
  209 
  210       typedef typename NodeTransformation::transformed_type transformed_type;
  211       typedef typename NodeTransformation::transformed_storage_type transformed_storage_type;
  212 
  213       // delegate instance transformation to per-node specification
  214       static transformed_type transform(const S& s, T& t)
  215       {
  216         return NodeTransformation::transform(s,t);
  217       }
  218 
  219       // delegate instance transformation to per-node specification
  220       static transformed_type transform(const S& s, const T& t)
  221       {
  222         return NodeTransformation::transform(s,t);
  223       }
  224 
  225       // delegate instance transformation to per-node specification
  226       static transformed_type transform(std::shared_ptr<const S> sp, T& t)
  227       {
  228         return NodeTransformation::transform(sp,t);
  229       }
  230 
  231       // delegate instance transformation to per-node specification
  232       static transformed_type transform(std::shared_ptr<const S> sp, const T& t)
  233       {
  234         return NodeTransformation::transform(sp,t);
  235       }
  236 
  237       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
  238       {
  239         return NodeTransformation::transform_storage(sp,t);
  240       }
  241 
  242       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
  243       {
  244         return NodeTransformation::transform_storage(sp,t);
  245       }
  246 
  247     };
  248 
  249 
  250     namespace Impl {
  251 
  252       // Helper class to handle recursive power nodes
  253       template<class Source, class Transformation, class Tag>
  254       class RecursivePowerTransformTree
  255       {
  256         // We only know two types of tags!
  257         static_assert(std::is_same_v<Tag,PowerNodeTag> or std::is_same_v<Tag,DynamicPowerNodeTag>);
  258 
  259         using ChildType = typename Source::ChildType;
  260 
  261         // in case degree is dynamic, provid a vector correctly initialized
  262         template<class NodeStorage>
  263         static auto node_storage_provider(const std::size_t& degree)
  264         {
  265           return std::vector<NodeStorage>(degree);
  266         }
  267 
  268         // in case degree is static, provid an array
  269         template<class NodeStorage, class StaticIndex>
  270         static auto node_storage_provider(StaticIndex)
  271         {
  272           return std::array<NodeStorage,std::size_t(StaticIndex{})>();
  273         }
  274 
  275       public:
  276         // get transformed type from specification
  277         // Handling this transformation in a way that makes the per-node specification easy to write
  278         // is a little involved:
  279         // The problem is that the transformed power node must be parameterized on the transformed child
  280         // type. So we need to transform the child type and pass the transformed child type to an inner
  281         // template of the node transformation struct called result (see example of such a specification
  282         // further down).
  283         using NodeTransformation = typename LookupNodeTransformation<Source,Transformation,ImplementationTag<Source>>::type;
  284         using ChildNodeTransformation = typename LookupNodeTransformation<ChildType,Transformation,ImplementationTag<ChildType>>::type;
  285 
  286       private:
  287         // Since every child is same type, is enough to get transformation once
  288         using ChildTreeTransformation = TransformTree<ChildType,
  289                                                       Transformation,
  290                                                       NodeTag<ChildType>,
  291                                                       ChildNodeTransformation::recursive>;
  292 
  293         // Get transformed type of children
  294         using transformed_child_type = typename ChildTreeTransformation::transformed_type;
  295         using transformed_child_storage_type = typename ChildTreeTransformation::transformed_storage_type;
  296       public:
  297         // Apply transformation from children to current node
  298         using transformed_type = typename NodeTransformation::template result<transformed_child_type>::type;
  299         using transformed_storage_type = typename NodeTransformation::template result<transformed_child_type>::storage_type;
  300 
  301         // Transform an instance of source tree.
  302         static transformed_type transform(const Source& source, Transformation& transformation)
  303         {
  304           auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source.degree());
  305           for (std::size_t k = 0; k < source.degree(); ++k) {
  306             children_storage[k] = ChildTreeTransformation::transform_storage(source.childStorage(k),transformation);
  307           }
  308           return NodeTransformation::transform(source,transformation,children_storage);
  309         }
  310 
  311         // Transform an instance of source tree.
  312         static transformed_type transform(const Source& source, const Transformation& transformation)
  313         {
  314           auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source.degree());
  315           for (std::size_t k = 0; k < source.degree(); ++k) {
  316             children_storage[k] = ChildTreeTransformation::transform_storage(source.childStorage(k),transformation);
  317           }
  318           return NodeTransformation::transform(source,transformation,children_storage);
  319         }
  320 
  321         // Transform an instance of source tree.
  322         static transformed_type transform(std::shared_ptr<const Source> source_ptr, Transformation& transformation)
  323         {
  324           auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source_ptr->degree());
  325           for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
  326             children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
  327           }
  328           return NodeTransformation::transform(source_ptr,transformation,children_storage);
  329         }
  330 
  331         // Transform an instance of source tree.
  332         static transformed_type transform(std::shared_ptr<const Source> source_ptr, const Transformation& transformation)
  333         {
  334           auto children_storage = node_storage_provider<std::shared_ptr<transformed_child_type>>(source_ptr->degree());
  335           for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
  336             children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
  337           }
  338           return NodeTransformation::transform(source_ptr,transformation,children_storage);
  339         }
  340 
  341         // Transform an instance of source tree ptr.
  342         static transformed_storage_type transform_storage(std::shared_ptr<const Source> source_ptr, Transformation& transformation)
  343         {
  344           auto children_storage = node_storage_provider<transformed_child_storage_type>(source_ptr->degree());
  345           for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
  346             children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
  347           }
  348           return NodeTransformation::transform_storage(source_ptr,transformation,children_storage);
  349         }
  350 
  351         // Transform an instance of source tree ptr.
  352         static transformed_storage_type transform_storage(std::shared_ptr<const Source> source_ptr, const Transformation& transformation)
  353         {
  354           auto children_storage = node_storage_provider<transformed_child_storage_type>(source_ptr->degree());
  355           for (std::size_t k = 0; k < source_ptr->degree(); ++k) {
  356             children_storage[k] = ChildTreeTransformation::transform_storage(source_ptr->childStorage(k),transformation);
  357           }
  358           return NodeTransformation::transform_storage(source_ptr,transformation,children_storage);
  359         }
  360 
  361       };
  362     } // namespace Impl
  363 
  364     // Recursive version of the PowerNode transformation for static nodes.
  365     template<typename Source, typename Transformation>
  366     struct TransformTree<Source,Transformation,PowerNodeTag,true>
  367       : public Impl::RecursivePowerTransformTree<Source,Transformation,PowerNodeTag>
  368     {};
  369 
  370     // Recursive version of the DynamicPowerNode transformation for static nodes.
  371     template<typename Source, typename Transformation>
  372     struct TransformTree<Source,Transformation,DynamicPowerNodeTag,true>
  373       : public Impl::RecursivePowerTransformTree<Source,Transformation,DynamicPowerNodeTag>
  374     {};
  375 
  376     // non-recursive version of the PowerNode transformation.
  377     template<typename S, typename T>
  378     struct TransformTree<S,T,PowerNodeTag,false>
  379       : public TransformTreeNonRecursive<S,T>
  380     {};
  381 
  382     // non-recursive version of the DynamicPowerNodeTag transformation.
  383     template<typename S, typename T>
  384     struct TransformTree<S,T,DynamicPowerNodeTag,false>
  385       : public TransformTreeNonRecursive<S,T>
  386     {};
  387 
  388     // helper struct that does the actual transformation for a composite node. We need this additional struct
  389     // to extract the template argument list with the types of all children from the node, which we cannot do
  390     // directly in the transformation<> template, as the type passed to transformation<> will usually be a
  391     // derived type and will normally have more template arguments than just the children. This declaration
  392     // just introduces the type of the helper struct, we always instantiate the specialization defined below;
  393     template<typename S, typename Children, typename T>
  394     struct transform_composite_node;
  395 
  396     // specialized version of the helper struct which extracts the template argument list with the children from
  397     // its second template parameter, which has to be CompositeNode::ChildTypes. Apart from that, the struct is
  398     // similar to the one for a PowerNode, but it obviously delegates transformation of the children to the TMP.
  399     template<typename S, typename T, typename... C>
  400     struct transform_composite_node<S,std::tuple<C...>,T>
  401     {
  402 
  403       // transformed type, using the same nested struct trick as the PowerNode
  404       typedef ImplementationTag<S> Tag;
  405       typedef typename LookupNodeTransformation<S,T,Tag>::type NodeTransformation;
  406       typedef typename NodeTransformation::template result<typename TransformTree<C,
  407                                                                                   T,
  408                                                                                   NodeTag<C>,
  409                                                                                   LookupNodeTransformation<C,T,ImplementationTag<C>>::type::recursive
  410                                                                                   >::transformed_type...
  411                                                            >::type transformed_type;
  412 
  413       typedef typename NodeTransformation::template result<typename TransformTree<C,
  414                                                                                   T,
  415                                                                                   NodeTag<C>,
  416                                                                                   LookupNodeTransformation<C,T,ImplementationTag<C>>::type::recursive
  417                                                                                   >::transformed_type...
  418                                                            >::storage_type transformed_storage_type;
  419 
  420       // Retrieve the transformation descriptor for the child with index i.
  421       // This little helper improves really improves the readability of the
  422       // transformation functions.
  423       template<std::size_t i>
  424       struct ChildTransformation
  425         : public TransformTree<typename S::template Child<i>::Type,
  426                                T,
  427                                NodeTag<typename S::template Child<i>::Type>,
  428                                LookupNodeTransformation<
  429                                  typename S::template Child<i>::Type,
  430                                  T,
  431                                  ImplementationTag<typename S::template Child<i>::Type>
  432                                  >::type::recursive
  433                                >
  434       {};
  435 
  436       template<std::size_t i, typename Tuple, typename Value>
  437       static void setElement(Tuple& tuple, Value&& value)
  438       {
  439         std::get<i>(tuple) = std::forward<Value>(value);
  440       }
  441 
  442       template<typename Trafo, std::size_t... i>
  443       static transformed_type transform(const S& s, Trafo&& t, std::index_sequence<i...> indices)
  444       {
  445         std::tuple<typename ChildTransformation<i>::transformed_storage_type...> storage;
  446         Dune::Hybrid::Impl::evaluateFoldExpression<int>({(setElement<i>(storage, ChildTransformation<i>::transform_storage(s.template childStorage<i>(), std::forward<Trafo>(t))),0)...});
  447         return NodeTransformation::transform(s, std::forward<Trafo>(t), std::get<i>(storage)...);
  448       }
  449 
  450       template<typename Trafo, std::size_t... i>
  451       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, Trafo&& t, std::index_sequence<i...> indices)
  452       {
  453         std::tuple<typename ChildTransformation<i>::transformed_storage_type...> storage;
  454         Dune::Hybrid::Impl::evaluateFoldExpression<int>({(setElement<i>(storage, ChildTransformation<i>::transform_storage(sp->template childStorage<i>(), std::forward<Trafo>(t))),0)...});
  455         return NodeTransformation::transform_storage(sp, std::forward<Trafo>(t), std::get<i>(storage)...);
  456       }
  457     };
  458 
  459 
  460     // the specialization of transformation<> for the CompositeNode. This just extracts the
  461     // CompositeNode::ChildTypes member and forwards to the helper struct
  462     template<typename S, typename T>
  463     struct TransformTree<S,T,CompositeNodeTag,true>
  464     {
  465 
  466     private:
  467 
  468       typedef typename S::ChildTypes ChildTypes;
  469 
  470       static auto child_indices()
  471       {
  472         return std::make_index_sequence<S::CHILDREN>();
  473       }
  474 
  475     public:
  476 
  477       typedef typename transform_composite_node<S,ChildTypes,T>::transformed_type transformed_type;
  478       typedef typename transform_composite_node<S,ChildTypes,T>::transformed_storage_type transformed_storage_type;
  479 
  480       static transformed_type transform(const S& s, T& t)
  481       {
  482         return transform_composite_node<S,ChildTypes,T>::transform(s,t,child_indices());
  483       }
  484 
  485       static transformed_type transform(const S& s, const T& t)
  486       {
  487         return transform_composite_node<S,ChildTypes,T>::transform(s,t,child_indices());
  488       }
  489 
  490       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, T& t)
  491       {
  492         return transform_composite_node<S,ChildTypes,T>::transform_storage(sp,t,child_indices());
  493       }
  494 
  495       static transformed_storage_type transform_storage(std::shared_ptr<const S> sp, const T& t)
  496       {
  497         return transform_composite_node<S,ChildTypes,T>::transform_storage(sp,t,child_indices());
  498       }
  499 
  500     };
  501 
  502     // non-recursive version of the CompositeNode transformation.
  503     template<typename S, typename T>
  504     struct TransformTree<S,T,CompositeNodeTag,false>
  505       : public TransformTreeNonRecursive<S,T>
  506     {};
  507 
  508 #endif // DOXYGEN
  509 
  510     //! \} group Traversal
  511 
  512   } // namespace TypeTree
  513 } //namespace Dune
  514 
  515 #endif // DUNE_TYPETREE_TRANSFORMATION_HH