Alexandria  2.25.0
SDC-CH common library for the Euclid project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdArray.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2022 Euclid Science Ground Segment
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 3.0 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
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>
52 
53 public:
54  typedef NdArray<T> self_type;
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:
67  size_t m_i;
68 
69  Iterator(ContainerInterface* container_ptr, size_t offset, const std::vector<size_t>& shape,
70  const std::vector<size_t>& strides, size_t start);
71 
72  Iterator(ContainerInterface* container_ptr, size_t offset, size_t row_size, size_t stride, size_t start);
73 
74  friend class NdArray;
75 
76  public:
81 
85  Iterator(const Iterator<false>& other); // cppcheck-suppress noExplicitConstructor
86 
91 
95  const Iterator operator++(int);
96 
100  bool operator==(const Iterator& other) const;
101 
105  bool operator!=(const Iterator& other) const;
106 
112  value_t& operator*();
113 
119  value_t operator*() const;
120 
126  Iterator& operator+=(size_t n);
127 
133  Iterator operator+(size_t n) const;
134 
141  Iterator& operator-=(size_t n);
142 
149  Iterator operator-(size_t n) const;
150 
156  difference_type operator-(const Iterator& other);
157 
161  value_t& operator[](size_t i);
162 
166  value_t operator[](size_t i) const;
167 
173  bool operator<(const Iterator& other);
174 
180  bool operator>(const Iterator& other);
181  };
182 
185 
189  virtual ~NdArray() = default;
190 
197  explicit NdArray(std::vector<size_t> shape_);
198 
209  template <template <class...> class Container = std::vector>
210  NdArray(std::vector<size_t> shape_, const Container<T>& data);
211 
226  template <template <class...> class Container = std::vector>
227  NdArray(std::vector<size_t> shape_, Container<T>&& data);
228 
247  template <template <class...> class Container = std::vector>
248  NdArray(std::vector<size_t> shape_, std::vector<size_t> strides_, Container<T>&& data);
249 
262  template <typename Iterator>
264 
275  template <typename... Args>
276  NdArray(const std::vector<size_t>& shape_, const std::vector<std::string>& attr_names, Args&&... args);
277 
284  explicit NdArray(const std::initializer_list<size_t>& shape_) : NdArray(std::vector<size_t>{shape_}) {}
285 
291  NdArray(const self_type&) = default;
292 
296  NdArray(self_type&&) noexcept = default;
297 
303  NdArray& operator=(const NdArray&) = default;
304 
308  NdArray copy() const {
309  return self_type{this};
310  }
311 
317  const std::vector<size_t>& shape() const {
318  return m_shape;
319  }
320 
325  size_t shape(std::size_t i) const {
326  return m_shape[i];
327  }
328 
330  return m_stride_size;
331  }
332 
334  return m_stride_size[i];
335  }
336 
349  self_type& reshape(const std::vector<size_t>& new_shape);
350 
361  template <typename... D>
362  self_type& reshape(size_t i, D... rest);
363 
371  T& at(const std::vector<size_t>& coords);
372 
380  const T& at(const std::vector<size_t>& coords) const;
381 
391  T& at(const std::vector<size_t>& coords, const std::string& attr);
392 
402  const T& at(const std::vector<size_t>& coords, const std::string& attr) const;
403 
414  template <typename... D>
415  T& at(size_t i, D... rest);
416 
427  template <typename... D>
428  const T& at(size_t i, D... rest) const;
429 
434  iterator begin();
435 
440  iterator end();
441 
446  const_iterator begin() const;
447 
452  const_iterator end() const;
453 
457  size_t size() const;
458 
462  bool operator==(const self_type& b) const;
463 
467  bool operator!=(const self_type& b) const;
468 
473  self_type& concatenate(const self_type& other);
474 
478  self_type slice(size_t i);
479 
483  const self_type slice(size_t i) const;
484 
488  self_type rslice(size_t i);
489 
493  const self_type rslice(size_t i) const;
494 
495  void next_slice(void);
496 
501  const std::vector<std::string>& attributes() const;
502 
503 private:
504  size_t m_offset;
508 
512  char* m_data_ptr;
513 
514  virtual ~ContainerInterface() = default;
515 
517  T get(size_t offset) const {
518  return *reinterpret_cast<T*>(m_data_ptr + offset);
519  }
520 
522  T& get(size_t offset) {
523  return *reinterpret_cast<T*>(m_data_ptr + offset);
524  }
525 
527  virtual size_t size() const = 0;
528 
530  size_t nbytes() const {
531  return size() * sizeof(T);
532  }
533 
535  virtual void resize(const std::vector<size_t>& shape) = 0;
536 
538  virtual std::unique_ptr<ContainerInterface> copy() const = 0;
539  };
540 
541  template <template <class...> class Container>
542  struct ContainerWrapper : public ContainerInterface {
544 
545  Container<T> m_container;
546 
547  ~ContainerWrapper() = default;
548 
549  ContainerWrapper(const ContainerWrapper&) = delete;
550 
551  ContainerWrapper(ContainerWrapper&&) noexcept = default;
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>
564  -> decltype((void)std::declval<Container<T2>>().resize(std::vector<size_t>{}), void()) {
565  m_container.resize(shape);
566  }
567 
568  template <typename T2>
570  -> decltype((void)std::declval<Container<T2>>().resize(size_t{}), void()) {
571  auto new_size = std::accumulate(shape.begin(), shape.end(), 1u, std::multiplies<size_t>());
572  m_container.resize(new_size);
573  }
574 
582  void resize(const std::vector<size_t>& shape) final {
583  resizeImpl<T>(shape);
584  m_data_ptr = reinterpret_cast<char*>(m_container.data());
585  }
586 
588  return Euclid::make_unique<ContainerWrapper>(m_container);
589  }
590  };
591 
593 
597  explicit NdArray(const self_type* other);
598 
603  std::vector<size_t> stride, std::vector<std::string> attr_names);
604 
610  size_t get_offset(const std::vector<size_t>& coords) const;
611 
617  size_t get_attr_offset(const std::string& attr) const;
618 
622  void update_strides();
623 
627  template <typename... D>
628  T& at_helper(size_t offset_acc, size_t axis, size_t i, D... rest);
629 
633  T& at_helper(size_t offset_acc, size_t axis);
634 
638  T& at_helper(size_t offset_acc, size_t axis, const std::string& attr);
639 
643  template <typename... D>
644  const T& at_helper(size_t offset_acc, size_t axis, size_t i, D... rest) const;
645 
649  const T& at_helper(size_t offset_acc, size_t axis) const;
650 
654  const T& at_helper(size_t offset_acc, size_t axis, const std::string& attr) const;
655 
656  template <typename... D>
657  self_type& reshape_helper(std::vector<size_t>& acc, size_t i, D... rest);
658 
660 };
661 
665 template <typename T>
666 std::ostream& operator<<(std::ostream& out, const NdArray<T>& ndarray);
667 
668 } // namespace NdArray
669 } // namespace Euclid
670 
671 #define NDARRAY_IMPL
673 #undef NDARRAY_IMPL
674 
675 #endif // ALEXANDRIA_NDARRAY_H
const std::vector< std::size_t > & strides() const
Definition: NdArray.h:329
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 >>().resize(size_t
Definition: NdArray.h:569
bool operator>(const Iterator &other)
ContainerWrapper(const ContainerWrapper &)=delete
NdArray(std::vector< size_t > shape_)
Iterator & operator-=(size_t n)
std::vector< size_t > m_shape
Definition: NdArray.h:505
self_type & reshape_helper(std::vector< size_t > &acc, size_t i, D...rest)
bool operator==(const self_type &b) const
size_t size() const
virtual void resize(const std::vector< size_t > &shape)=0
Resize container.
bool operator!=(const self_type &b) const
self_type slice(size_t i)
const std::vector< size_t > & shape() const
Definition: NdArray.h:317
const std::vector< std::string > & attributes() const
T end(T...args)
T & at_helper(size_t offset_acc, size_t axis, size_t i, D...rest)
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 >>().resize(std::vector< size_t >
Definition: NdArray.h:563
size_t get_attr_offset(const std::string &attr) const
size_t shape(std::size_t i) const
Definition: NdArray.h:325
Iterator< false > iterator
Definition: NdArray.h:184
Iterator operator+(size_t n) const
STL class.
size_t nbytes() const
Get the size in bytes.
Definition: NdArray.h:530
std::unique_ptr< ContainerInterface > copy() const final
Expected to generate a deep copy of the underlying data.
Definition: NdArray.h:587
self_type & concatenate(const self_type &other)
std::vector< size_t > m_stride_size
Definition: NdArray.h:505
NdArray(const std::initializer_list< size_t > &shape_)
Definition: NdArray.h:284
virtual ~NdArray()=default
Iterator operator-(size_t n) const
T declval(T...args)
Iterator & operator+=(size_t n)
bool operator<(const Iterator &other)
NdArray copy() const
Definition: NdArray.h:308
bool operator!=(const Iterator &other) const
std::shared_ptr< ContainerInterface > m_container
Definition: NdArray.h:592
self_type rslice(size_t i)
self_type & reshape(const std::vector< size_t > &new_shape)
T & at(const std::vector< size_t > &coords)
STL class.
Iterator< true > const_iterator
Definition: NdArray.h:183
STL class.
T begin(T...args)
std::size_t strides(std::size_t i) const
Definition: NdArray.h:333
void resize(const std::vector< size_t > &shape) final
Definition: NdArray.h:582
typename std::conditional< Const, const T, T >::type value_t
Definition: NdArray.h:77
NdArray< T > self_type
Definition: NdArray.h:51
Iterator(ContainerInterface *container_ptr, size_t offset, const std::vector< size_t > &shape, const std::vector< size_t > &strides, size_t start)
size_t get_offset(const std::vector< size_t > &coords) const
std::vector< std::string > m_attr_names
Definition: NdArray.h:506
bool operator==(const Iterator &other) const
T accumulate(T...args)
ContainerInterface * m_container_ptr
Definition: NdArray.h:65
STL class.
virtual std::unique_ptr< ContainerInterface > copy() const =0
Expected to generate a deep copy of the underlying data.