Alexandria  2.27.0
SDC-CH common library for the Euclid project
NdArray.h
Go to the documentation of this file.
1 
25 #ifndef ALEXANDRIA_NDARRAY_H
26 #define ALEXANDRIA_NDARRAY_H
27 
29 #include <cassert>
30 #include <iostream>
31 #include <numeric>
32 #include <stdexcept>
33 #include <vector>
34 
35 namespace Euclid {
36 namespace NdArray {
37 
45 template <typename T>
46 class NdArray {
47 private:
48  struct ContainerInterface;
49 
50  template <template <class...> class Container = std::vector>
51  struct ContainerWrapper;
52 
53 public:
55 
61  template <bool Const>
62  class Iterator
63  : public std::iterator<std::random_access_iterator_tag, typename std::conditional<Const, const T, T>::type> {
64  private:
66  size_t m_offset;
67  size_t m_row_size;
68  size_t m_stride;
69  size_t m_i;
70 
71  Iterator(ContainerInterface* container_ptr, size_t offset, const std::vector<size_t>& shape,
72  const std::vector<size_t>& strides, size_t start);
73 
74  Iterator(ContainerInterface* container_ptr, size_t offset, size_t row_size, size_t stride, size_t start);
75 
76  friend class NdArray;
77 
78  public:
83 
87  Iterator(const Iterator<false>& other); // cppcheck-suppress noExplicitConstructor
88 
93 
97  const Iterator operator++(int);
98 
102  bool operator==(const Iterator& other) const;
103 
107  bool operator!=(const Iterator& other) const;
108 
115 
122 
128  Iterator& operator+=(size_t n);
129 
135  Iterator operator+(size_t n) const;
136 
143  Iterator& operator-=(size_t n);
144 
151  Iterator operator-(size_t n) const;
152 
158  difference_type operator-(const Iterator& other);
159 
163  value_t& operator[](size_t i);
164 
168  value_t operator[](size_t i) const;
169 
175  bool operator<(const Iterator& other);
176 
182  bool operator>(const Iterator& other);
183  };
184 
187 
191  ~NdArray() = default;
192 
199  explicit NdArray(std::vector<size_t> shape_);
200 
211  template <template <class...> class Container = std::vector>
212  NdArray(std::vector<size_t> shape_, const Container<T>& data);
213 
228  template <template <class...> class Container = std::vector>
229  NdArray(std::vector<size_t> shape_, Container<T>&& data);
230 
249  template <template <class...> class Container = std::vector>
250  NdArray(std::vector<size_t> shape_, std::vector<size_t> strides_, Container<T>&& data);
251 
264  template <typename Iterator>
266 
277  template <typename... Args>
278  NdArray(const std::vector<size_t>& shape_, const std::vector<std::string>& attr_names, Args&&... args);
279 
286  explicit NdArray(const std::initializer_list<size_t>& shape_) : NdArray(std::vector<size_t>{shape_}) {}
287 
294 
298  NdArray(self_type&&) noexcept = default;
299 
305  NdArray& operator=(const NdArray&);
306 
310  NdArray copy() const {
311  return self_type{this};
312  }
313 
319  const std::vector<size_t>& shape() const {
320  return m_details_ptr->m_shape;
321  }
322 
327  size_t shape(std::size_t i) const {
328  return m_details_ptr->m_shape[i];
329  }
330 
332  return m_details_ptr->m_stride_size;
333  }
334 
336  return m_details_ptr->m_stride_size[i];
337  }
338 
352 
363  template <typename... D>
364  self_type& reshape(size_t i, D... rest);
365 
369  const T& front() const;
370 
378  T& at(const std::vector<size_t>& coords);
379 
387  const T& at(const std::vector<size_t>& coords) const;
388 
398  T& at(const std::vector<size_t>& coords, const std::string& attr);
399 
409  const T& at(const std::vector<size_t>& coords, const std::string& attr) const;
410 
421  template <typename... D>
422  T& at(size_t i, D... rest);
423 
434  template <typename... D>
435  const T& at(size_t i, D... rest) const;
436 
442 
448 
454 
460 
464  size_t size() const;
465 
469  bool operator==(const self_type& b) const;
470 
474  bool operator!=(const self_type& b) const;
475 
481 
485  self_type slice(size_t i);
486 
490  const self_type slice(size_t i) const;
491 
495  self_type rslice(size_t i);
496 
500  const self_type rslice(size_t i) const;
501 
502  void next_slice(void);
503 
509 
510 private:
514  char* m_data_ptr;
515 
516  virtual ~ContainerInterface() = default;
517 
519  T get(size_t offset) const {
520  return *reinterpret_cast<T*>(m_data_ptr + offset);
521  }
522 
524  T& get(size_t offset) {
525  return *reinterpret_cast<T*>(m_data_ptr + offset);
526  }
527 
529  virtual size_t size() const = 0;
530 
532  virtual size_t nbytes() const = 0;
533 
535  virtual void resize(const std::vector<size_t>& shape) = 0;
536 
539  };
540 
541  template <template <class...> class Container>
544 
545  Container<T> m_container;
546 
547  ~ContainerWrapper() = default;
548 
550 
552 
553  template <typename... Args>
554  explicit ContainerWrapper(Args&&... args) : m_container(std::forward<Args>(args)...) {
555  m_data_ptr = reinterpret_cast<char*>(m_container.data());
556  }
557 
558  size_t size() const final {
559  return m_container.size();
560  }
561 
562  template <typename T2>
563  auto nbytesImpl(int) const -> decltype(std::declval<Container<T2>>().nbytes()) {
564  return m_container.nbytes();
565  }
566 
567  template <typename T2>
568  size_t nbytesImpl(...) const {
569  return m_container.size() * sizeof(T2);
570  }
571 
572  size_t nbytes() const final {
573  return nbytesImpl<T>(0);
574  }
575 
576  template <typename T2>
578  -> decltype((void)std::declval<Container<T2>>().resize(std::vector<size_t>{}), void()) {
579  m_container.resize(shape);
580  }
581 
582  template <typename T2>
584  -> decltype((void)std::declval<Container<T2>>().resize(size_t{}), void()) {
585  auto new_size = std::accumulate(shape.begin(), shape.end(), 1u, std::multiplies<size_t>());
586  m_container.resize(new_size);
587  }
588 
596  void resize(const std::vector<size_t>& shape) final {
597  resizeImpl<T>(shape);
598  m_data_ptr = reinterpret_cast<char*>(m_container.data());
599  }
600 
602  return Euclid::make_unique<ContainerWrapper>(m_container);
603  }
604  };
605 
606  // NdArray is used inside Table as one of the possible column types
607  // Since the cell_type is a variant, it must be as big as the biggest type (NdArray)
608  // plus a marker for the valid type, plus any alignment requirement.
609  // This indirection makes NdArray only 8 bytes in size!
610  struct Details {
611  size_t m_offset;
612  size_t m_size;
618  };
620 
624  explicit NdArray(const self_type* other);
625 
630  std::vector<size_t> stride, std::vector<std::string> attr_names);
631 
637  size_t get_offset(const std::vector<size_t>& coords) const;
638 
644  size_t get_attr_offset(const std::string& attr) const;
645 
650 
654  template <typename... D>
655  T& at_helper(size_t offset_acc, size_t axis, size_t i, D... rest);
656 
660  T& at_helper(size_t offset_acc, size_t axis);
661 
665  T& at_helper(size_t offset_acc, size_t axis, const std::string& attr);
666 
670  template <typename... D>
671  const T& at_helper(size_t offset_acc, size_t axis, size_t i, D... rest) const;
672 
676  const T& at_helper(size_t offset_acc, size_t axis) const;
677 
681  const T& at_helper(size_t offset_acc, size_t axis, const std::string& attr) const;
682 
683  template <typename... D>
684  self_type& reshape_helper(std::vector<size_t>& acc, size_t i, D... rest);
685 
687 };
688 
692 template <typename T>
694 
695 } // namespace NdArray
696 } // namespace Euclid
697 
698 #define NDARRAY_IMPL
700 #undef NDARRAY_IMPL
701 
702 #endif // ALEXANDRIA_NDARRAY_H
T accumulate(T... args)
T begin(T... args)
Iterator(ContainerInterface *container_ptr, size_t offset, size_t row_size, size_t stride, size_t start)
Iterator & operator+=(size_t n)
Iterator operator+(size_t n) const
bool operator!=(const Iterator &other) const
typename std::conditional< Const, const T, T >::type value_t
Definition: NdArray.h:79
Iterator & operator-=(size_t n)
bool operator>(const Iterator &other)
bool operator<(const Iterator &other)
Iterator(ContainerInterface *container_ptr, size_t offset, const std::vector< size_t > &shape, const std::vector< size_t > &strides, size_t start)
ContainerInterface * m_container_ptr
Definition: NdArray.h:65
Iterator operator-(size_t n) const
bool operator==(const Iterator &other) const
Iterator(const Iterator< false > &other)
value_t operator[](size_t i) const
difference_type operator-(const Iterator &other)
const T & at_helper(size_t offset_acc, size_t axis, const std::string &attr) const
size_t get_offset(const std::vector< size_t > &coords) const
size_t shape(std::size_t i) const
Definition: NdArray.h:327
self_type & reshape(size_t i, D... rest)
const std::vector< std::size_t > & strides() const
Definition: NdArray.h:331
T & at(const std::vector< size_t > &coords, const std::string &attr)
T & at_helper(size_t offset_acc, size_t axis, const std::string &attr)
NdArray(const std::vector< size_t > &shape_, const std::vector< std::string > &attr_names, Args &&... args)
NdArray(const self_type *other)
self_type slice(size_t i)
NdArray(std::vector< size_t > shape_, std::vector< size_t > strides_, Container< T > &&data)
T & at(const std::vector< size_t > &coords)
const T & at(size_t i, D... rest) const
bool operator!=(const self_type &b) const
self_type & reshape_helper(std::vector< size_t > &acc)
T & at(size_t i, D... rest)
T & at_helper(size_t offset_acc, size_t axis, size_t i, D... rest)
self_type rslice(size_t i)
NdArray copy() const
Definition: NdArray.h:310
NdArray(std::vector< size_t > shape_, const Container< T > &data)
std::size_t strides(std::size_t i) const
Definition: NdArray.h:335
NdArray(const std::initializer_list< size_t > &shape_)
Definition: NdArray.h:286
const_iterator begin() const
const T & at(const std::vector< size_t > &coords, const std::string &attr) const
T & at_helper(size_t offset_acc, size_t axis)
const T & at(const std::vector< size_t > &coords) const
const self_type rslice(size_t i) const
NdArray(self_type &&) noexcept=default
const T & front() const
NdArray(std::vector< size_t > shape_, Container< T > &&data)
const std::vector< size_t > & shape() const
Definition: NdArray.h:319
size_t get_attr_offset(const std::string &attr) const
const std::vector< std::string > & attributes() const
self_type & reshape_helper(std::vector< size_t > &acc, size_t i, D... rest)
const T & at_helper(size_t offset_acc, size_t axis) const
bool operator==(const self_type &b) const
NdArray(std::vector< size_t > shape_)
const T & at_helper(size_t offset_acc, size_t axis, size_t i, D... rest) const
std::unique_ptr< Details > m_details_ptr
Definition: NdArray.h:619
NdArray(std::vector< size_t > shape_, Iterator begin, Iterator end)
self_type & reshape(const std::vector< size_t > &new_shape)
const_iterator end() const
NdArray(const self_type &)
const self_type slice(size_t i) const
self_type & concatenate(const self_type &other)
NdArray(std::shared_ptr< ContainerInterface > container, size_t offset, std::vector< size_t > shape, std::vector< size_t > stride, std::vector< std::string > attr_names)
T declval(T... args)
T end(T... args)
std::ostream & operator<<(std::ostream &out, const NdArray< T > &ndarray)
STL namespace.
T & get(size_t offset)
Get a reference to the element at the given absolute offset (in bytes)
Definition: NdArray.h:524
virtual std::unique_ptr< ContainerInterface > copy() const =0
Expected to generate a deep copy of the underlying data.
T get(size_t offset) const
Get the element at the given absolute offset (in bytes)
Definition: NdArray.h:519
virtual void resize(const std::vector< size_t > &shape)=0
Resize container.
virtual size_t nbytes() const =0
Get the size in bytes.
std::unique_ptr< ContainerInterface > copy() const final
Expected to generate a deep copy of the underlying data.
Definition: NdArray.h:601
ContainerWrapper(const ContainerWrapper &)=delete
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 >>().resize(size_t{}), void())
Definition: NdArray.h:583
void resize(const std::vector< size_t > &shape) final
Definition: NdArray.h:596
ContainerWrapper(ContainerWrapper &&)=default
size_t nbytes() const final
Get the size in bytes.
Definition: NdArray.h:572
auto nbytesImpl(int) const -> decltype(std::declval< Container< T2 >>().nbytes())
Definition: NdArray.h:563
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 >>().resize(std::vector< size_t >{}), void())
Definition: NdArray.h:577
std::vector< std::string > m_attr_names
Definition: NdArray.h:616
std::shared_ptr< ContainerInterface > m_container
Definition: NdArray.h:617
std::vector< size_t > m_shape
Definition: NdArray.h:614
std::vector< size_t > m_stride_size
Definition: NdArray.h:615