atlas
ArraySlicer.h
1 /*
2  * (C) Copyright 2013 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation
8  * nor does it submit to any jurisdiction.
9  */
10 
11 #pragma once
12 
13 #include <array>
14 
15 #include "atlas/array/ArrayViewDefs.h"
16 #include "atlas/array/Range.h"
17 #include "atlas/library/config.h"
18 
19 namespace atlas {
20 namespace array {
21 
22 template <typename Value, int Rank>
23 class LocalView;
24 
25 template <typename Value>
26 struct Reference {
27  Value& value;
28  operator Value&() { return value; }
29  template <typename T>
30  void operator=( const T a ) {
31  value = a;
32  }
33  template <typename T>
34  Reference<Value>& operator+( const T a ) {
35  value += a;
36  return *this;
37  }
38  template <typename T>
39  Reference<Value>& operator-( const T a ) {
40  value -= a;
41  return *this;
42  }
43  Reference<Value>& operator--() {
44  --value;
45  return *this;
46  }
47  Reference<Value>& operator++() {
48  ++value;
49  return *this;
50  }
51 };
52 
53 template <typename Value, int Rank>
55  using type = typename std::conditional<( Rank == 0 ), Reference<Value>, LocalView<Value, Rank>>::type;
56 };
57 
58 //------------------------------------------------------------------------------
59 
60 namespace helpers {
61 
62 template <int Dim>
64 
65 template <int Rank, typename... Args>
67 
68 template <>
69 struct deduce_slice_rank<1> {
70  template <typename Last>
71  static constexpr int apply() {
72  return std::is_base_of<RangeBase, Last>::value;
73  }
74 };
75 template <typename... Args>
76 struct SliceRank_impl<1, Args...> {
77  static constexpr int value{deduce_slice_rank<1>::apply<Args...>()};
78 };
79 
80 #define ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( RANK ) \
81  template <> \
82  struct deduce_slice_rank<RANK> { \
83  template <typename First, typename... Args> \
84  static constexpr int apply() { \
85  return std::is_base_of<RangeBase, First>::value + deduce_slice_rank<RANK - 1>::apply<Args...>(); \
86  } \
87  }; \
88  template <typename... Args> \
89  struct SliceRank_impl<RANK, Args...> { \
90  static constexpr int value{deduce_slice_rank<RANK>::apply<Args...>()}; \
91  }
92 
93 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 2 );
94 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 3 );
95 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 4 );
96 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 5 );
97 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 6 );
98 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 7 );
99 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 8 );
100 ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION( 9 );
101 #undef ATLAS_ARRAY_SLICER_EXPLICIT_TEMPLATE_SPECIALISATION
102 
103 template <typename... Args>
104 struct SliceRank {
105  static constexpr int value{SliceRank_impl<sizeof...( Args ), Args...>::value};
106 };
107 
108 // template <typename Value, int Rank, Intent AccessMode>
109 template <typename View>
110 class ArraySlicer {
111 public:
112  ArraySlicer( View& view ) : view_( view ) {}
113 
114  template <typename... Args>
115  struct Slice {
116  using type = typename get_slice_type<typename View::value_type, SliceRank<Args...>::value>::type;
117  };
118 
119  template <typename... Args>
120  typename Slice<Args...>::type apply( const Args... args ) const {
121  using slicer_t = Slicer<typename Slice<Args...>::type, ( SliceRank<Args...>::value == 0 )>;
122  static_assert(
123  View::RANK <= sizeof...( Args ),
124  "Not enough arguments passed to slice() function. Pehaps you forgot to add a array::Range::all()" );
125  return slicer_t::apply( view_, args... );
126  }
127 
128 private:
129  template <typename... Args>
130  struct array {
131  using type = typename std::array<idx_t, SliceRank<Args...>::value>;
132  };
133 
134  template <typename ReturnType, bool ToScalar = false>
135  struct Slicer {
136  template <typename... Args>
137  static ReturnType apply( View& view, const Args... args ) {
138  return ReturnType( view.data() + offset( view, args... ), shape( view, args... ).data(),
139  strides( view, args... ).data() );
140  }
141  };
142 
143  template <typename ReturnType>
144  struct Slicer<ReturnType, true> {
145  template <typename... Args>
146  static ReturnType apply( View& view, const Args... args ) {
147  return ReturnType{*( view.data() + offset( view, args... ) )};
148  }
149  };
150 
151  template <typename Int>
152  static idx_t offset_part( View& view, int& i_view, Int idx ) {
153  return idx * view.stride( i_view++ );
154  }
155 
156  static idx_t offset_part( View& view, int& i_view, Range range ) { return range.start() * view.stride( i_view++ ); }
157 
158  static idx_t offset_part( View& view, int& i_view, RangeAll range ) {
159  return range.start() * view.stride( i_view++ );
160  }
161 
162  static idx_t offset_part( View& view, int& i_view, RangeTo range ) {
163  return range.start() * view.stride( i_view++ );
164  }
165 
166  static idx_t offset_part( View& view, int& i_view, RangeFrom range ) {
167  return range.start() * view.stride( i_view++ );
168  }
169 
170  static idx_t offset_part( View&, int& /*i_view*/, RangeDummy ) { return 0; }
171 
172  template <int Dim, typename Int, typename... Ints>
173  static idx_t offset_remaining( View& view, int& i_view, const Int idx, const Ints... next_idx ) {
174  const idx_t p = offset_part( view, i_view, idx );
175  return p + offset_remaining<Dim + 1>( view, i_view, next_idx... );
176  }
177 
178  template <int Dim, typename Int>
179  static idx_t offset_remaining( View& view, int& i_view, const Int last_idx ) {
180  return offset_part( view, i_view, last_idx );
181  }
182 
183  template <typename... Args>
184  static idx_t offset( View& view, const Args... args ) {
185  int i_view( 0 );
186  return offset_remaining<0>( view, i_view, args... );
187  }
188 
189  template <int Dim, typename Shape, typename Int>
190  static void update_shape( View&, Shape&, int& i_view, int& /*i_slice*/, const Int& /*index*/ ) {
191  // do nothing
192  ++i_view;
193  }
194  template <int Dim, typename Shape>
195  static void update_shape( View&, Shape& shape, int& i_view, int& i_slice, const Range range ) {
196  shape[i_slice] = range.end() - range.start();
197  ++i_slice;
198  ++i_view;
199  }
200  template <int Dim, typename Shape>
201  static void update_shape( View& view, Shape& shape, int& i_view, int& i_slice, const RangeAll range ) {
202  shape[i_slice] = range.end( view, i_view ) - range.start();
203  ++i_slice;
204  ++i_view;
205  }
206  template <int Dim, typename Shape>
207  static void update_shape( View& view, Shape& shape, int& i_view, int& i_slice, const RangeFrom range ) {
208  shape[i_slice] = range.end( view, i_view ) - range.start();
209  ++i_slice;
210  ++i_view;
211  }
212  template <int Dim, typename Shape>
213  static void update_shape( View&, Shape& shape, int& i_view, int& i_slice, const RangeTo range ) {
214  shape[i_slice] = range.end() - range.start();
215  ++i_slice;
216  ++i_view;
217  }
218 
219  template <int Dim, typename Shape>
220  static void update_shape( View&, Shape& shape, int& /*i_view*/, int& i_slice, const RangeDummy ) {
221  shape[i_slice] = 1;
222  ++i_slice;
223  // no update of i_view for dummy-dimension
224  }
225 
226  template <int Dim, typename Shape, typename Int, typename... Ints>
227  static void shape_part( View& view, Shape& shape, int& i_view, int& i_slice, const Int idx,
228  const Ints... next_idx ) {
229  update_shape<Dim>( view, shape, i_view, i_slice, idx );
230  shape_part<Dim + 1>( view, shape, i_view, i_slice, next_idx... );
231  }
232 
233  template <int Dim, typename Shape, typename Int>
234  static void shape_part( View& view, Shape& shape, int& i_view, int& i_slice, const Int idx ) {
235  update_shape<Dim>( view, shape, i_view, i_slice, idx );
236  }
237 
238  template <typename... Args>
239  static typename array<Args...>::type shape( View& view, const Args... args ) {
240  typename array<Args...>::type result;
241  int i_slice( 0 );
242  int i_view( 0 );
243  shape_part<0>( view, result, i_view, i_slice, args... );
244  return result;
245  }
246 
247  template <int Dim, typename Strides, typename Int>
248  static void update_strides( View&, Strides&, int& i_view, int& /*i_slice*/, const Int& /*idx*/ ) {
249  // do nothing
250  ++i_view;
251  }
252  template <int Dim, typename Strides>
253  static void update_strides( View& view, Strides& strides, int& i_view, int& i_slice, const Range& /*range*/ ) {
254  strides[i_slice] = view.stride( i_view );
255  ++i_slice;
256  ++i_view;
257  }
258  template <int Dim, typename Strides>
259  static void update_strides( View& view, Strides& strides, int& i_view, int& i_slice, const RangeFrom& /*range*/ ) {
260  strides[i_slice] = view.stride( i_view );
261  ++i_slice;
262  ++i_view;
263  }
264  template <int Dim, typename Strides>
265  static void update_strides( View& view, Strides& strides, int& i_view, int& i_slice, const RangeTo& /*range*/ ) {
266  strides[i_slice] = view.stride( i_view );
267  ++i_slice;
268  ++i_view;
269  }
270  template <int Dim, typename Strides>
271  static void update_strides( View& view, Strides& strides, int& i_view, int& i_slice, const RangeAll& /*range*/ ) {
272  strides[i_slice] = view.stride( i_view );
273  ++i_slice;
274  ++i_view;
275  }
276  template <int Dim, typename Strides>
277  static void update_strides( View& /*view*/, Strides& strides, int& /*i_view*/, int& i_slice,
278  const RangeDummy& /*range*/ ) {
279  strides[i_slice] = 0;
280  ++i_slice;
281  }
282 
283  template <int Dim, typename Strides, typename Int, typename... Ints>
284  static void strides_part( View& view, Strides& strides, int& i_view, int& i_slice, const Int idx,
285  const Ints... next_idx ) {
286  update_strides<Dim>( view, strides, i_view, i_slice, idx );
287  strides_part<Dim + 1>( view, strides, i_view, i_slice, next_idx... );
288  }
289 
290  template <int Dim, typename Strides, typename Int>
291  static void strides_part( View& view, Strides& strides, int& i_view, int& i_slice, const Int idx ) {
292  update_strides<Dim>( view, strides, i_view, i_slice, idx );
293  }
294 
295  template <typename... Args>
296  static typename array<Args...>::type strides( View& view, const Args... args ) {
297  typename array<Args...>::type result;
298  int i_slice( 0 );
299  int i_view( 0 );
300  strides_part<0>( view, result, i_view, i_slice, args... );
301  return result;
302  }
303 
304 private:
305  View& view_;
306 };
307 
308 //------------------------------------------------------------------------------
309 
310 } // namespace helpers
311 } // namespace array
312 } // namespace atlas
Definition: ArraySlicer.h:66
Definition: Range.h:29
Definition: ArraySlicer.h:110
Definition: ArraySlicer.h:26
Definition: ArraySlicer.h:104
Definition: Range.h:51
Definition: Range.h:65
Definition: ArraySlicer.h:63
Multi-dimensional access existing POD array pointer.
Definition: ArraySlicer.h:23
Contains all atlas classes and methods.
Definition: atlas-grids.cc:33
Definition: ArraySlicer.h:54
long idx_t
Integer type for indices in connectivity tables.
Definition: config.h:42
Definition: ArrayViewDefs.h:20
Definition: Range.h:89
Definition: Range.h:80
Definition: ArraySlicer.h:115