atlas
NativeArrayView.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 
49 
50 #pragma once
51 
52 #include <array>
53 #include <cstddef>
54 #include <initializer_list>
55 #include <iostream>
56 #include <type_traits>
57 
58 #include "atlas/array/ArrayUtil.h"
59 #include "atlas/array/ArrayViewDefs.h"
60 #include "atlas/array/LocalView.h"
61 #include "atlas/array/Range.h"
62 #include "atlas/array/helpers/ArraySlicer.h"
63 #include "atlas/library/config.h"
64 
65 //------------------------------------------------------------------------------------------------------
66 
67 namespace atlas {
68 namespace array {
69 
70 //------------------------------------------------------------------------------------------------------
71 
96 
97 template <typename Value, int Rank>
98 class ArrayView {
99  template <typename T>
100  using is_non_const_value_type = typename std::is_same<T, typename std::remove_const<Value>::type>;
101 
102 #define ENABLE_IF_NON_CONST \
103  template <bool EnableBool = true, \
104  typename std::enable_if<( !std::is_const<Value>::value && EnableBool ), int>::type* = nullptr>
105 
106 #define ENABLE_IF_CONST_WITH_NON_CONST( T ) \
107  template <typename T, \
108  typename std::enable_if<( std::is_const<Value>::value && is_non_const_value_type<T>::value ), \
109  int>::type* = nullptr>
110 
111 public:
112  // -- Type definitions
113  using value_type = Value;
114  using non_const_value_type = typename std::remove_const<Value>::type;
115  static constexpr bool is_const = std::is_const<Value>::value;
116  static constexpr bool is_non_const = !std::is_const<Value>::value;
117  static constexpr int RANK{Rank};
118 
119 private:
120  using slicer_t = typename helpers::ArraySlicer<ArrayView<Value, Rank>>;
121  using const_slicer_t = typename helpers::ArraySlicer<const ArrayView<const Value, Rank>>;
122 
123  template <typename... Args>
124  struct slice_t {
125  using type = typename slicer_t::template Slice<Args...>::type;
126  };
127 
128  template <typename... Args>
129  struct const_slice_t {
130  using type = typename const_slicer_t::template Slice<Args...>::type;
131  };
132 
133 public:
134  // -- Constructors
135 
136  ArrayView( const ArrayView& other ) :
137  data_( other.data_ ), size_( other.size_ ), shape_( other.shape_ ), strides_( other.strides_ ) {}
138 
139  ENABLE_IF_CONST_WITH_NON_CONST( value_type )
140  ArrayView( const ArrayView<value_type, Rank>& other ) : data_( other.data() ), size_( other.size() ) {
141  for ( idx_t j = 0; j < Rank; ++j ) {
142  shape_[j] = other.shape( j );
143  strides_[j] = other.stride( j );
144  }
145  }
146 
147 #ifndef DOXYGEN_SHOULD_SKIP_THIS
148  // This constructor should not be used directly, but only through a array::make_view() function.
149  ArrayView( value_type* data, const ArrayShape& shape, const ArrayStrides& strides ) : data_( data ) {
150  size_ = 1;
151  for ( int j = 0; j < Rank; ++j ) {
152  shape_[j] = shape[j];
153  strides_[j] = strides[j];
154  size_ *= size_t( shape_[j] );
155  }
156  }
157 #endif
158 
159  ENABLE_IF_CONST_WITH_NON_CONST( value_type )
160  operator const ArrayView<value_type, Rank>&() const { return *(const ArrayView<value_type, Rank>*)( this ); }
161 
162 
163  // -- Access methods
164 
166  template <typename... Idx>
167  value_type& operator()( Idx... idx ) {
168  check_bounds( idx... );
169  return data_[index( idx... )];
170  }
171 
173  template <typename... Ints>
174  const value_type& operator()( Ints... idx ) const {
175  return data_[index( idx... )];
176  }
177 
181 #ifndef DOXYGEN_SHOULD_SKIP_THIS
182  template <typename Int, bool EnableBool = true>
183  typename std::enable_if<( Rank == 1 && EnableBool ), const value_type&>::type operator[]( Int idx ) const {
184 #else
185  // Doxygen API is cleaner!
186  template <typename Int>
187  value_type operator[]( Int idx ) const {
188 #endif
189  check_bounds( idx );
190  return data_[idx * strides_[0]];
191  }
192 
196 #ifndef DOXYGEN_SHOULD_SKIP_THIS
197  template <typename Int, bool EnableBool = true>
198  typename std::enable_if<( Rank == 1 && EnableBool ), value_type&>::type operator[]( Int idx ) {
199 #else
200  // Doxygen API is cleaner!
201  template <typename Int>
202  value_type operator[]( Int idx ) {
203 #endif
204  check_bounds( idx );
205  return data_[idx * strides_[0]];
206  }
207 
218  template <unsigned int Dim>
219  idx_t shape() const {
220  return shape_[Dim];
221  }
222 
224  template <unsigned int Dim>
225  idx_t stride() const {
226  return strides_[Dim];
227  }
228 
230  size_t size() const { return size_; }
231 
233  static constexpr idx_t rank() { return Rank; }
234 
235  const idx_t* strides() const { return strides_.data(); }
236 
237  const idx_t* shape() const { return shape_.data(); }
238 
240  template <typename Int>
241  idx_t shape( Int idx ) const {
242  return shape_[idx];
243  }
244 
246  template <typename Int>
247  idx_t stride( Int idx ) const {
248  return strides_[idx];
249  }
250 
252  value_type const* data() const { return data_; }
253 
255  value_type* data() { return data_; }
256 
257  bool valid() const { return true; }
258 
263  bool contiguous() const { return ( size_ == size_t( shape_[0] ) * size_t( strides_[0] ) ? true : false ); }
264 
265  ENABLE_IF_NON_CONST
266  void assign( const value_type& value );
267 
268  ENABLE_IF_NON_CONST
269  void assign( const std::initializer_list<value_type>& list );
270 
271  void dump( std::ostream& os ) const;
272 
291  template <typename... Args>
292 #ifndef DOXYGEN_SHOULD_SKIP_THIS
293  typename slice_t<Args...>::type slice( Args... args ) {
294 #else
295  // C++14 will allow auto return type
296  auto slice( Args... args ) {
297 #endif
298  return slicer_t( *this ).apply( args... );
299  }
300 
301 
303  template <typename... Args>
304 #ifndef DOXYGEN_SHOULD_SKIP_THIS
305  typename const_slice_t<Args...>::type slice( Args... args ) const {
306 #else
307  // C++14 will allow auto return type
308  auto slice( Args... args ) const {
309 #endif
310  return const_slicer_t( *this ).apply( args... );
311  }
312 
313 private:
314  // -- Private methods
315 
316  template <int Dim, typename Int, typename... Ints>
317  constexpr idx_t index_part( Int idx, Ints... next_idx ) const {
318  return idx * strides_[Dim] + index_part<Dim + 1>( next_idx... );
319  }
320 
321  template <int Dim, typename Int>
322  constexpr idx_t index_part( Int last_idx ) const {
323  return last_idx * strides_[Dim];
324  }
325 
326  template <typename... Ints>
327  constexpr idx_t index( Ints... idx ) const {
328  return index_part<0>( idx... );
329  }
330 
331 #if ATLAS_ARRAYVIEW_BOUNDS_CHECKING
332  template <typename... Ints>
333  void check_bounds( Ints... idx ) const {
334  static_assert( sizeof...( idx ) == Rank, "Expected number of indices is different from rank of array" );
335  return check_bounds_part<0>( idx... );
336  }
337 #else
338  template <typename... Ints>
339  void check_bounds( Ints... idx ) const {
340  static_assert( sizeof...( idx ) == Rank, "Expected number of indices is different from rank of array" );
341  }
342 #endif
343 
344  template <typename... Ints>
345  void check_bounds_force( Ints... idx ) const {
346  static_assert( sizeof...( idx ) == Rank, "Expected number of indices is different from rank of array" );
347  return check_bounds_part<0>( idx... );
348  }
349 
350  template <int Dim, typename Int, typename... Ints>
351  void check_bounds_part( Int idx, Ints... next_idx ) const {
352  if ( idx_t( idx ) >= shape_[Dim] ) {
353  throw_OutOfRange( "ArrayView", array_dim<Dim>(), idx, shape_[Dim] );
354  }
355  check_bounds_part<Dim + 1>( next_idx... );
356  }
357 
358  template <int Dim, typename Int>
359  void check_bounds_part( Int last_idx ) const {
360  if ( idx_t( last_idx ) >= shape_[Dim] ) {
361  throw_OutOfRange( "ArrayView", array_dim<Dim>(), last_idx, shape_[Dim] );
362  }
363  }
364 
365  // -- Private data
366 
367  value_type* data_;
368  size_t size_;
369  std::array<idx_t, Rank> shape_;
370  std::array<idx_t, Rank> strides_;
371 };
372 
373 //------------------------------------------------------------------------------------------------------
374 
375 #undef ENABLE_IF_NON_CONST
376 #undef ENABLE_IF_CONST_WITH_NON_CONST
377 
378 } // namespace array
379 } // namespace atlas
idx_t stride() const
Return stride for values in dimension Dim (template argument)
Definition: NativeArrayView.h:225
static constexpr idx_t rank()
Return the number of dimensions.
Definition: NativeArrayView.h:233
size_t size() const
Return total number of values (accumulated over all dimensions)
Definition: NativeArrayView.h:230
idx_t stride(Int idx) const
Return stride for values in dimension idx.
Definition: NativeArrayView.h:247
idx_t shape() const
Return number of values in dimension Dim (template argument)
Definition: NativeArrayView.h:219
const_slice_t< Args... >::type slice(Args... args) const
Obtain a slice from this view: view.slice( Range, Range, ... )
Definition: NativeArrayView.h:305
slice_t< Args... >::type slice(Args... args)
Obtain a slice from this view: view.slice( Range, Range, ...
Definition: NativeArrayView.h:293
const value_type & operator()(Ints... idx) const
Multidimensional index operator: view(i,j,k,...)
Definition: NativeArrayView.h:174
std::enable_if<(Rank==1 &&EnableBool), value_type & >::type operator[](Int idx)
Access to data using square bracket [idx] operator {m-label m-warning} Rank==1
Definition: NativeArrayView.h:198
idx_t shape(Int idx) const
Return number of values in dimension idx.
Definition: NativeArrayView.h:241
Definition: test_array_slicer.cc:22
bool contiguous() const
Return true when all values are contiguous in memory.
Definition: NativeArrayView.h:263
value_type & operator()(Idx... idx)
Multidimensional index operator: view(i,j,k,...)
Definition: NativeArrayView.h:167
value_type const * data() const
Access to internal data. {m-label m-danger} dangerous
Definition: NativeArrayView.h:252
Contains all atlas classes and methods.
Definition: atlas-grids.cc:33
long idx_t
Integer type for indices in connectivity tables.
Definition: config.h:42
std::enable_if<(Rank==1 &&EnableBool), const value_type & >::type operator[](Int idx) const
Access to data using square bracket [idx] operator {m-label m-warning} Rank==1.
Definition: NativeArrayView.h:183
Definition: ArrayViewDefs.h:20
This file contains the LocalView class, a class that allows to wrap any contiguous raw data into a vi...
value_type * data()
Access to internal data. {m-label m-danger} dangerous
Definition: NativeArrayView.h:255