Transform.hpp 2.87 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once

#include <type_traits>
#include <utility>
#include <vector>

#include <dune/common/typeutilities.hh>
#include <amdis/common/ForEach.hpp>
#include <amdis/common/StaticSize.hpp>

namespace AMDiS {
namespace Recursive {

template <class>
struct Transform;

17
18
/// \brief Recursive application of a functor `op` to a hierarchic container of
/// containers.
19
20
21
22
/**
 * This utility function applies the given functor `op` to the "leaf" entries in
 * hierarchic containers {in...} and assigns the output to the hierarchic container [out].
 * Therefore, the containers are traversed recursively, using specializations of the
23
24
 * `Transform<Container>::impl` class method. If no such specialization is provided,
 * the function is applied to the whole containers or leaf entries, respectively.
25
26
27
28
29
30
31
32
33
34
35
36
37
 **/
template <class Out, class Op, class... In>
void transform (Out& out, Op&& op, In const&... in)
{
  Transform<std::remove_const_t<Out>>::impl(out,op,in...);
}


template <class>
struct Transform
{
private:
  // ranges with dynamic index access
38
39
  template <class OutIter, class Op, class In0, class... InIter>
  static void impl3 (OutIter d_first, Op&& op, In0 first0, In0 last0, InIter... first)
40
  {
41
42
    while (first0 != last0)
      Recursive::transform(*d_first++, op, *first0++, *first++...);
43
44
45
  }

  // ranges with dynamic index access
46
  template <class Out, class Op, class In0, class... In,
47
    class = decltype(std::begin(std::declval<Out>())),
48
49
50
51
52
    class = decltype(std::begin(std::declval<In0>())),
    class = decltype(std::end(std::declval<In0>())),
    class = decltype((std::begin(std::declval<In>()),...))>
  static void impl2 (Dune::PriorityTag<3>, Out& out, Op&& op, In0 const& in0,
                     In const&... in)
53
  {
54
    impl3(std::begin(out), op, std::begin(in0), std::end(in0), std::begin(in)...);
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  }

  // ranges with static index access
  template <class Out, class Op, class... In,
    class = decltype(std::declval<Out>()[std::integral_constant<std::size_t,0>{}])>
  static void impl2 (Dune::PriorityTag<2>, Out& out, Op&& op, In const&... in)
  {
    Ranges::forIndices<static_size_v<Out>>([&](auto ii) {
      Recursive::transform(out[ii], op, in[ii]...);
    });
  }

  // ranges with static getter access
  template <class Out, class Op, class... In,
    class = decltype(std::get<0>(std::declval<Out>()))>
  static void impl2 (Dune::PriorityTag<1>, Out& out, Op&& op, In const&... in)
  {
    Ranges::forIndices<static_size_v<Out>>([&](auto ii) {
      Recursive::transform(std::get<ii>(out), op, std::get<ii>(in)...);
    });
  }

  // no range
  template <class Out, class Op, class... In>
  static void impl2 (Dune::PriorityTag<0>, Out& out, Op&& op, In const&... in)
  {
    out = op(in...);
  }

public:
  template <class Out, class Op, class... In>
  static void impl (Out& out, Op&& op, In const&... in)
  {
    impl2(Dune::PriorityTag<5>{}, out, op, in...);
  }
};

}} // end namespace AMDiS::Recursive