SyDEVS  v0.6.7
Multiscale Simulation and Systems Modeling Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
arraynd_base.h
Go to the documentation of this file.
1 #pragma once
2 #ifndef SYDEVS_ARRAYND_BASE_H_
3 #define SYDEVS_ARRAYND_BASE_H_
4 
5 #include <sydevs/core/range.h>
6 #include <functional>
7 #include <algorithm>
8 #include <memory>
9 #include <vector>
10 #include <array>
11 
12 namespace sydevs {
13 
14 
24 template<typename T, int64 ndims>
26 {
27 friend class arraynd_base<T, ndims-1>;
28 friend class arraynd_base<T, ndims+1>;
29 public:
30  ~arraynd_base() = default;
31 
32  std::array<int64, ndims> dims() const;
33  std::array<int64, ndims> strides() const;
34 
35  bool empty() const;
36  int64 size() const;
37  int64 offset() const;
38 
39  const T* data() const;
40  T* data();
41 
42  bool is_contiguous() const;
43  bool is_view() const;
44  bool is_readonly() const;
45 
46  const T& operator()(const std::array<int64, ndims>& indices) const;
47  T& operator()(const std::array<int64, ndims>& indices);
48 
49  const T& operator()(const arraynd_base<int64, 1>& indices) const;
50  T& operator()(const arraynd_base<int64, 1>& indices);
51 
52  template<typename... Indices>
53  const T& operator()(Indices... indices) const;
54 
55  template<typename... Indices>
56  T& operator()(Indices... indices);
57 
58  void fill(const T& value);
59  void assign(const arraynd_base<T, ndims>& rhs);
60  void assign_from_function(std::function<T(const std::array<int64, ndims>& indices)> func);
61 
76  bool traverse(std::function<bool(const std::array<int64, ndims>& indices, const T& value)> func) const;
77 
78 protected:
79  arraynd_base();
80  arraynd_base(const std::array<int64, ndims>& dims, const T& value);
81  arraynd_base(const std::array<int64, ndims>& dims, const std::vector<T>& data);
82  arraynd_base(const std::array<int64, ndims>& dims, std::function<T(const std::array<int64, ndims>& indices)> func);
83 
84  arraynd_base(const arraynd_base<T, ndims+1>& rhs, int64 index, bool is_readonly);
86 
88 
91 
94 
95  static void transpose(arraynd_base<T, ndims>& arr);
96  static void swap_axes(arraynd_base<T, ndims>& arr, int64 idim0, int64 idim1);
97  static void subdivide_axis(const arraynd_base<T, ndims>& arr0, arraynd_base<T, ndims + 1>& arr, int64 idim, const std::array<int64, 2>& dims);
98  static void absorb_axis(const arraynd_base<T, ndims>& arr0, arraynd_base<T, ndims-1>& arr, int64 idim);
99 
100 private:
101  void compute_strides_and_size();
102 
103  void fill_recursively(const T& value, std::array<int64, ndims>& indices, int64 idim, int64 offset);
104  void assign_recursively(const arraynd_base<T, ndims>& rhs, std::array<int64, ndims>& indices, int64 idim, int64 offset);
105  void assign_from_function_recursively(std::function<T(const std::array<int64, ndims>& indices)> func, std::array<int64, ndims>& indices, int64 idim, int64 offset);
106  bool traverse_recursively(std::function<bool(const std::array<int64, ndims>& indices, const T& value)> func, std::array<int64, ndims>& indices, int64 idim, int64 offset) const;
107 
108  std::array<int64, ndims> dims_;
109  std::array<int64, ndims> strides_;
110  int64 size_;
111  int64 offset_;
112  int64 rotation_;
113  bool is_view_;
114  bool is_readonly_;
115  std::shared_ptr<T> data_ptr_;
116 };
117 
118 
119 template<typename T, int64 ndims>
121  : dims_()
122  , strides_()
123  , size_(0)
124  , offset_(0)
125  , rotation_(0)
126  , is_view_(false)
127  , is_readonly_(false)
128  , data_ptr_(nullptr)
129 {
130  static_assert(ndims >= 1, "ndims must be at least 1");
131  for (int idim = 0; idim < ndims; ++idim) {
132  dims_[idim] = 0;
133  }
134  compute_strides_and_size();
135  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
136 }
137 
138 
139 template<typename T, int64 ndims>
140 arraynd_base<T, ndims>::arraynd_base(const std::array<int64, ndims>& dims, const T& value)
141  : dims_(dims)
142  , strides_()
143  , size_(0)
144  , offset_(0)
145  , rotation_(0)
146  , is_view_(false)
147  , is_readonly_(false)
148  , data_ptr_(nullptr)
149 {
150  static_assert(ndims >= 1, "ndims must be at least 1");
151  compute_strides_and_size();
152  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
153  fill(value);
154 }
155 
156 
157 template<typename T, int64 ndims>
158 arraynd_base<T, ndims>::arraynd_base(const std::array<int64, ndims>& dims, const std::vector<T>& data)
159  : dims_(dims)
160  , strides_()
161  , size_(0)
162  , offset_(0)
163  , rotation_(0)
164  , is_view_(false)
165  , is_readonly_(false)
166  , data_ptr_(nullptr)
167 {
168  static_assert(ndims >= 1, "ndims must be at least 1");
169  compute_strides_and_size();
170  if (data.size() != size_) throw std::domain_error("Length of multidimensional array data must match product of array dimensions");
171  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
172  for (int64 i = 0; i < size_; ++i){
173  data_ptr_.get()[i] = data[i];
174  }
175 }
176 
177 
178 template<typename T, int64 ndims>
179 arraynd_base<T, ndims>::arraynd_base(const std::array<int64, ndims>& dims, std::function<T(const std::array<int64, ndims>& indices)> func)
180  : dims_(dims)
181  , strides_()
182  , size_(0)
183  , offset_(0)
184  , rotation_(0)
185  , is_view_(false)
186  , is_readonly_(false)
187  , data_ptr_(nullptr)
188 {
189  static_assert(ndims >= 1, "ndims must be at least 1");
190  compute_strides_and_size();
191  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
192  assign_from_function(func);
193 }
194 
195 
196 template<typename T, int64 ndims>
197 std::array<int64, ndims> arraynd_base<T, ndims>::dims() const
198 {
199  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
200  return dims_;
201 }
202 
203 
204 template<typename T, int64 ndims>
205 std::array<int64, ndims> arraynd_base<T, ndims>::strides() const
206 {
207  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
208  return strides_;
209 }
210 
211 
212 template<typename T, int64 ndims>
214 {
215  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
216  return size_ == 0;
217 }
218 
219 
220 template<typename T, int64 ndims>
222 {
223  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
224  return size_;
225 }
226 
227 
228 template<typename T, int64 ndims>
230 {
231  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
232  return offset_;
233 }
234 
235 
236 template<typename T, int64 ndims>
238 {
239  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
240  return data_ptr_.get();
241 }
242 
243 
244 template<typename T, int64 ndims>
246 {
247  if (is_readonly_) throw std::logic_error("Attempt to obtain a non-const reference to readonly multidimensional array data");
248  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
249  return data_ptr_.get();
250 }
251 
252 
253 template<typename T, int64 ndims>
255 {
256  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
257  auto contiguous_so_far = true;
258  auto size = 1;
259  for (int64 idim = ndims - 1; contiguous_so_far && idim >= 0; --idim) {
260  if (strides_[idim] != size) {
261  contiguous_so_far = false;
262  }
263  else {
264  size *= dims_[idim];
265  }
266  }
267  return contiguous_so_far;
268 }
269 
270 
271 template<typename T, int64 ndims>
273 {
274  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
275  return is_view_;
276 }
277 
278 
279 template<typename T, int64 ndims>
281 {
282  return is_readonly_;
283 }
284 
285 
286 template<typename T, int64 ndims>
287 const T& arraynd_base<T, ndims>::operator()(const std::array<int64, ndims>& indices) const
288 {
289  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
290  int64 offset = offset_;
291  for (int64 idim = 0; idim < ndims; ++idim) {
292  if (indices[idim] < 0 || indices[idim] >= dims_[idim]) throw std::out_of_range("Invalid multidimensional array index");
293  offset += indices[idim]*strides_[idim];
294  }
295  return data_ptr_.get()[offset];
296 }
297 
298 
299 template<typename T, int64 ndims>
300 T& arraynd_base<T, ndims>::operator()(const std::array<int64, ndims>& indices)
301 {
302  if (is_readonly_) throw std::logic_error("Attempt to obtain a non-const reference to readonly multidimensional array data");
303  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
304  int64 offset = offset_;
305  for (int64 idim = 0; idim < ndims; ++idim) {
306  if (indices[idim] < 0 || indices[idim] >= dims_[idim]) throw std::out_of_range("Invalid multidimensional array index");
307  offset += indices[idim]*strides_[idim];
308  }
309  return data_ptr_.get()[offset];
310 }
311 
312 
313 template<typename T, int64 ndims>
315 {
316  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
317  if (indices.size() != ndims) throw std::logic_error("Size of indexing array does not match the number of multidimensional array dimensions");
318  int64 offset = offset_;
319  for (int64 idim = 0; idim < ndims; ++idim) {
320  if (indices({idim}) < 0 || indices({idim}) >= dims_[idim]) throw std::out_of_range("Invalid multidimensional array index");
321  offset += indices({idim})*strides_[idim];
322  }
323  return data_ptr_.get()[offset];
324 }
325 
326 
327 template<typename T, int64 ndims>
329 {
330  if (is_readonly_) throw std::logic_error("Attempt to obtain a non-const reference to readonly multidimensional array data");
331  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
332  if (indices.size() != ndims) throw std::logic_error("Size of indexing array does not match the number of multidimensional array dimensions");
333  int64 offset = offset_;
334  for (int64 idim = 0; idim < ndims; ++idim) {
335  if (indices({idim}) < 0 || indices({idim}) >= dims_[idim]) throw std::out_of_range("Invalid multidimensional array index");
336  offset += indices({idim})*strides_[idim];
337  }
338  return data_ptr_.get()[offset];
339 }
340 
341 
342 template<typename T, int64 ndims>
343 template<typename... Indices>
344 const T& arraynd_base<T, ndims>::operator()(Indices... indices) const
345 {
346  return (*this)({indices...});
347 }
348 
349 
350 template<typename T, int64 ndims>
351 template<typename... Indices>
353 {
354  return (*this)({indices...});
355 }
356 
357 
358 template<typename T, int64 ndims>
359 void arraynd_base<T, ndims>::fill(const T& value)
360 {
361  if (is_readonly_) throw std::logic_error("Attempt to modify readonly multidimensional array data");
362  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
363  auto indices = std::array<int64, ndims>();
364  fill_recursively(value, indices, 0, offset_);
365 }
366 
367 
368 template<typename T, int64 ndims>
370 {
371  if (is_readonly_) throw std::logic_error("Attempt to modify readonly multidimensional array data");
372  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
373  for (int64 idim = 0; idim < ndims; ++idim) {
374  if (dims_[idim] != rhs.dims()[idim]) throw std::logic_error("Multidimensional array dimensions do not match");
375  }
376  auto indices = std::array<int64, ndims>();
377  assign_recursively(rhs, indices, 0, offset_);
378 }
379 
380 
381 template<typename T, int64 ndims>
382 void arraynd_base<T, ndims>::assign_from_function(std::function<T(const std::array<int64, ndims>& indices)> func)
383 {
384  if (is_readonly_) throw std::logic_error("Attempt to modify readonly multidimensional array data");
385  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
386  auto indices = std::array<int64, ndims>();
387  assign_from_function_recursively(func, indices, 0, offset_);
388 }
389 
390 
391 template<typename T, int64 ndims>
392 bool arraynd_base<T, ndims>::traverse(std::function<bool(const std::array<int64, ndims>& indices, const T& value)> func) const
393 {
394  if (rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
395  auto indices = std::array<int64, ndims>();
396  return traverse_recursively(func, indices, 0, offset_);
397 }
398 
399 
400 template<typename T, int64 ndims>
402  : dims_()
403  , strides_()
404  , size_(0)
405  , offset_(0)
406  , rotation_(rhs.rotation_)
407  , is_view_(true)
408  , is_readonly_(is_readonly)
409  , data_ptr_(rhs.data_ptr_)
410 {
411  if (index < 0 || index >= rhs.dims_[0]) throw std::out_of_range("Invalid multidimensional array index");
412  size_ = 1;
413  for (int64 idim = 0; idim < ndims; ++idim) {
414  dims_[idim] = rhs.dims_[idim + 1];
415  strides_[idim] = rhs.strides_[idim + 1];
416  size_ *= dims_[idim];
417  }
418  offset_ = rhs.offset_ + index*rhs.strides_[0];
419  if (rotation_ > 0) {
420  --rotation_;
421  }
422 }
423 
424 
425 template<typename T, int64 ndims>
427  : dims_()
428  , strides_()
429  , size_(0)
430  , offset_(0)
431  , rotation_(rhs.rotation_)
432  , is_view_(true)
433  , is_readonly_(is_readonly)
434  , data_ptr_(rhs.data_ptr_)
435 {
436  if (r.start() < 0 || r.start() >= rhs.dims_[0]) throw std::out_of_range("Multidimensional array range must start inside array");
437  if (r.stride() == 0) throw std::invalid_argument("Multidimensional array range must have a nonzero stride");
438  size_ = 1;
439  for (int64 idim = 0; idim < ndims - 1; ++idim) {
440  dims_[idim] = rhs.dims_[idim + 1];
441  strides_[idim] = rhs.strides_[idim + 1];
442  size_ *= dims_[idim];
443  }
444  int64 stop = (r.stop() < 0) ? 0 :
445  (r.stop() > rhs.dims_[0] - 1) ? rhs.dims_[0] - 1 :
446  r.stop();
447  int64 gap = stop - r.start();
448  dims_[ndims - 1] = 0;
449  if (gap == 0 || (gap > 0 && r.stride() > 0) || (gap < 0 && r.stride() < 0)) {
450  dims_[ndims - 1] = (gap + r.stride())/r.stride();
451  }
452  strides_[ndims - 1] = rhs.strides_[0]*r.stride();
453  size_ *= dims_[ndims - 1];
454  offset_ = rhs.offset_ + r.start()*rhs.strides_[0];
455  if (rotation_ == 0) {
456  rotation_ = ndims - 1;
457  }
458  else {
459  --rotation_;
460  }
461 }
462 
463 
464 template<typename T, int64 ndims>
465 arraynd_base<T, ndims>::arraynd_base(const arraynd_base<T, ndims>& rhs, bool is_view, bool is_readonly)
466  : dims_(rhs.dims_)
467  , strides_(rhs.strides_)
468  , size_(rhs.size_)
469  , offset_(rhs.offset_)
470  , rotation_(rhs.rotation_)
471  , is_view_(is_view)
472  , is_readonly_(is_readonly)
473  , data_ptr_(nullptr)
474 {
475  if (is_view_) {
476  data_ptr_ = rhs.data_ptr_;
477  }
478  else {
479  compute_strides_and_size();
480  offset_ = 0;
481  rotation_ = 0;
482  is_readonly_ = false;
483  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
484  assign(rhs);
485  }
486 }
487 
488 
489 template<typename T, int64 ndims>
491  : dims_(rhs.dims_)
492  , strides_(rhs.strides_)
493  , size_(rhs.size_)
494  , offset_(rhs.offset_)
495  , rotation_(rhs.rotation_)
496  , is_view_(rhs.is_view_)
497  , is_readonly_(rhs.is_readonly_)
498  , data_ptr_(nullptr)
499 {
500  if (is_view_) {
501  data_ptr_ = rhs.data_ptr_;
502  }
503  else {
504  compute_strides_and_size();
505  offset_ = 0;
506  rotation_ = 0;
507  is_readonly_ = false;
508  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
509  assign(rhs);
510  }
511 }
512 
513 
514 template<typename T, int64 ndims>
516 {
517  if (is_view_) {
518  assign(rhs);
519  }
520  else {
521  dims_ = rhs.dims_;
522  is_view_ = rhs.is_view_;
523  if (is_view_) {
524  strides_ = rhs.strides_;
525  size_ = rhs.size_;
526  offset_ = rhs.offset_;
527  rotation_ = rhs.rotation_;
528  is_readonly_ = rhs.is_readonly_;
529  data_ptr_ = rhs.data_ptr_;
530  }
531  else {
532  compute_strides_and_size();
533  offset_ = 0;
534  rotation_ = 0;
535  is_readonly_ = false;
536  data_ptr_ = std::shared_ptr<T>(new T[size_], std::default_delete<T[]>());
537  assign(rhs);
538  }
539  }
540  return *this;
541 }
542 
543 
544 template<typename T, int64 ndims>
546 {
547  if (arr.rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
548  std::reverse(arr.dims_.begin(), arr.dims_.end());
549  std::reverse(arr.strides_.begin(), arr.strides_.end());
550 }
551 
552 
553 template<typename T, int64 ndims>
555 {
556  if (arr.rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
557  if (idim0 < 0 || idim0 >= ndims || idim1 < 0 || idim1 >= ndims) throw std::out_of_range("Invalid multidimensional array index");
558  std::swap(arr.dims_[idim0], arr.dims_[idim1]);
559  std::swap(arr.strides_[idim0], arr.strides_[idim1]);
560 }
561 
562 
563 template<typename T, int64 ndims>
564 void arraynd_base<T, ndims>::subdivide_axis(const arraynd_base<T, ndims>& arr0, arraynd_base<T, ndims + 1>& arr, int64 idim, const std::array<int64, 2>& dims)
565 {
566  if (arr0.rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
567  if (!arr0.is_contiguous()) throw std::domain_error("Attempt to subdivide an axis of a non-contiguous multi-dimensional array");
568  if (idim < 0 || idim >= ndims) throw std::out_of_range("Invalid multidimensional array index");
569  if (dims[0]*dims[1] != arr0.dims_[idim]) throw std::domain_error("Product of post-subdivision multidimensional array dimensions does not match pre-subdivision dimension");
570  for (int64 i = 0; i < idim; ++i) {
571  arr.dims_[i] = arr0.dims_[i];
572  arr.strides_[i] = arr0.strides_[i];
573  }
574  arr.dims_[idim] = dims[0];
575  arr.dims_[idim + 1] = dims[1];
576  arr.strides_[idim] = arr0.strides_[idim]*dims[1];
577  arr.strides_[idim + 1] = arr0.strides_[idim];
578  for (int64 i = idim + 2; i < ndims + 1; ++i) {
579  arr.dims_[i] = arr0.dims_[i - 1];
580  arr.strides_[i] = arr0.strides_[i - 1];
581  }
582  arr.size_ = arr0.size_;
583  arr.offset_ = arr0.offset_;
584  arr.rotation_ = 0;
585  arr.is_view_ = true;
586  arr.is_readonly_ = arr0.is_readonly_;
587  arr.data_ptr_ = arr0.data_ptr_;
588 }
589 
590 
591 template<typename T, int64 ndims>
593 {
594  if (arr0.rotation_ > 0) throw std::logic_error("Attempt to use a partially sliced multidimensional array (try completing the slicing operation by invoking operator[](range) as needed)");
595  if (!arr0.is_contiguous()) throw std::domain_error("Attempt to absorb an axis of a non-contiguous multi-dimensional array");
596  if (idim < 0 || idim >= ndims) throw std::out_of_range("Invalid multidimensional array index");
597  if (idim == 0) throw std::domain_error("Attempt to absorb the first axis of a multidimensional array (the second axis must be absorbed into the first)");
598  for (int64 i = 0; i < idim - 1; ++i) {
599  arr.dims_[i] = arr0.dims_[i];
600  arr.strides_[i] = arr0.strides_[i];
601  }
602  arr.dims_[idim - 1] = arr0.dims_[idim - 1]*arr0.dims_[idim];
603  arr.strides_[idim - 1] = arr0.strides_[idim];
604  for (int64 i = idim; i < ndims - 1; ++i) {
605  arr.dims_[i] = arr0.dims_[i + 1];
606  arr.strides_[i] = arr0.strides_[i + 1];
607  }
608  arr.size_ = arr0.size_;
609  arr.offset_ = arr0.offset_;
610  arr.rotation_ = 0;
611  arr.is_view_ = true;
612  arr.is_readonly_ = arr0.is_readonly_;
613  arr.data_ptr_ = arr0.data_ptr_;
614 }
615 
616 
617 template<typename T, int64 ndims>
619 {
620  size_ = 1;
621  for (int64 idim = ndims - 1; idim >= 0; --idim) {
622  strides_[idim] = size_;
623  size_ *= dims_[idim];
624  }
625 }
626 
627 
628 template<typename T, int64 ndims>
629 void arraynd_base<T, ndims>::fill_recursively(const T& value, std::array<int64, ndims>& indices, int64 idim, int64 offset)
630 {
631  if (idim == ndims - 1) {
632  for (int64 i = 0; i < dims_[idim]; ++i) {
633  indices[idim] = i;
634  data_ptr_.get()[offset + i*strides_[idim]] = value;
635  }
636  }
637  else {
638  for (int64 i = 0; i < dims_[idim]; ++i) {
639  indices[idim] = i;
640  fill_recursively(value, indices, idim + 1, offset + i*strides_[idim]);
641  }
642  }
643 }
644 
645 
646 template<typename T, int64 ndims>
647 void arraynd_base<T, ndims>::assign_recursively(const arraynd_base<T, ndims>& rhs, std::array<int64, ndims>& indices, int64 idim, int64 offset)
648 {
649  if (idim == ndims - 1) {
650  for (int64 i = 0; i < dims_[idim]; ++i) {
651  indices[idim] = i;
652  data_ptr_.get()[offset + i*strides_[idim]] = rhs(indices);
653  }
654  }
655  else {
656  for (int64 i = 0; i < dims_[idim]; ++i) {
657  indices[idim] = i;
658  assign_recursively(rhs, indices, idim + 1, offset + i*strides_[idim]);
659  }
660  }
661 }
662 
663 
664 template<typename T, int64 ndims>
665 void arraynd_base<T, ndims>::assign_from_function_recursively(std::function<T(const std::array<int64, ndims>& indices)> func, std::array<int64, ndims>& indices, int64 idim, int64 offset)
666 {
667  if (idim == ndims - 1) {
668  for (int64 i = 0; i < dims_[idim]; ++i) {
669  indices[idim] = i;
670  data_ptr_.get()[offset + i*strides_[idim]] = func(indices);
671  }
672  }
673  else {
674  for (int64 i = 0; i < dims_[idim]; ++i) {
675  indices[idim] = i;
676  assign_from_function_recursively(func, indices, idim + 1, offset + i*strides_[idim]);
677  }
678  }
679 }
680 
681 
682 template<typename T, int64 ndims>
683 bool arraynd_base<T, ndims>::traverse_recursively(std::function<bool(const std::array<int64, ndims>& indices, const T& value)> func, std::array<int64, ndims>& indices, int64 idim, int64 offset) const
684 {
685  auto proceed = true;
686  if (idim == ndims - 1) {
687  for (int64 i = 0; proceed && i < dims_[idim]; ++i) {
688  indices[idim] = i;
689  proceed = func(indices, data_ptr_.get()[offset + i*strides_[idim]]);
690  }
691  }
692  else {
693  for (int64 i = 0; proceed && i < dims_[idim]; ++i) {
694  indices[idim] = i;
695  proceed = traverse_recursively(func, indices, idim + 1, offset + i*strides_[idim]);
696  }
697  }
698  return proceed;
699 }
700 
701 
702 } // namespace
703 
704 #endif
void assign(const arraynd_base< T, ndims > &rhs)
Replaces every element with the corresponding value in rhs.
Definition: arraynd_base.h:369
bool is_readonly() const
Returns true if the data is readonly, in which case attempts to modify it raise a std::logic_error...
Definition: arraynd_base.h:280
A data type which represents a range of array indices along a single dimension.
Definition: range.h:51
std::array< int64, ndims > dims() const
Returns the lengths of each dimension.
Definition: arraynd_base.h:197
bool is_view() const
Returns true if this multidimensional array is a view of another, meaning that data is shared...
Definition: arraynd_base.h:272
std::array< int64, ndims > strides() const
Returns the number of element-size steps in memory between successive elements for each dimension...
Definition: arraynd_base.h:205
static void transpose(arraynd_base< T, ndims > &arr)
Definition: arraynd_base.h:545
const T * data() const
Returns a pointer to the element data (const).
Definition: arraynd_base.h:237
const T & operator()(const std::array< int64, ndims > &indices) const
Returns a reference to an element (const).
Definition: arraynd_base.h:287
bool traverse(std::function< bool(const std::array< int64, ndims > &indices, const T &value)> func) const
Traverses the multidimensional array in row-major order, calling func at every element.
Definition: arraynd_base.h:392
void assign_from_function(std::function< T(const std::array< int64, ndims > &indices)> func)
Replaces every element with the result of func evaluated at the cooresponding indices.
Definition: arraynd_base.h:382
void fill(const T &value)
Replaces every element with value.
Definition: arraynd_base.h:359
bool is_contiguous() const
Returns true if a row-major traversal of the multidimensional array accesses each element of data in ...
Definition: arraynd_base.h:254
A base class template for a multidimensional array with elements of type T arranged in a lattice of n...
Definition: arraynd_base.h:25
bool empty() const
Returns true if there is at least one element.
Definition: arraynd_base.h:213
int64 size() const
Returns the total number of elements.
Definition: arraynd_base.h:221
int64 offset() const
Returns the number of element-size steps in memory before the first element.
Definition: arraynd_base.h:229
arraynd_base()
Definition: arraynd_base.h:120
constexpr int64 stop() const
Returns the last possible index in the sequence.
Definition: range.h:117
static void subdivide_axis(const arraynd_base< T, ndims > &arr0, arraynd_base< T, ndims+1 > &arr, int64 idim, const std::array< int64, 2 > &dims)
Definition: arraynd_base.h:564
arraynd_base< T, ndims > & operator=(const arraynd_base< T, ndims > &rhs)
Definition: arraynd_base.h:515
static void swap_axes(arraynd_base< T, ndims > &arr, int64 idim0, int64 idim1)
Definition: arraynd_base.h:554
constexpr int64 stride() const
Returns the increment between sequence indices.
Definition: range.h:123
int64_t int64
Definition: number_types.h:14
constexpr int64 start() const
Returns the first index in the sequence.
Definition: range.h:111
~arraynd_base()=default
Destructor.
static void absorb_axis(const arraynd_base< T, ndims > &arr0, arraynd_base< T, ndims-1 > &arr, int64 idim)
Definition: arraynd_base.h:592