Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
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
35namespace Euclid {
36namespace NdArray {
37
45template <typename T>
46class NdArray {
47private:
48 struct ContainerInterface;
49
50 template <template <class...> class Container = std::vector>
51 struct ContainerWrapper;
52
53public:
55
61 template <bool Const>
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
129
135 Iterator operator+(size_t n) const;
136
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
510private:
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!
620
624 explicit NdArray(const self_type* other);
625
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
692template <typename T>
693std::ostream& operator<<(std::ostream& out, const NdArray<T>& ndarray);
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 & operator-=(size_t n)
Iterator(ContainerInterface *container_ptr, size_t offset, size_t row_size, size_t stride, size_t start)
Iterator operator+(size_t n) const
Iterator & operator+=(size_t n)
bool operator!=(const Iterator &other) const
typename std::conditional< Const, const T, T >::type value_t
Definition NdArray.h:79
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, size_t i, D... rest) const
const T & front() const
const T & at(const std::vector< size_t > &coords) const
const T & at_helper(size_t offset_acc, size_t axis) const
size_t get_offset(const std::vector< size_t > &coords) const
size_t shape(std::size_t i) const
Definition NdArray.h:327
const T & at(const std::vector< size_t > &coords, const std::string &attr) const
T & at(const std::vector< size_t > &coords, const std::string &attr)
self_type & reshape(const std::vector< size_t > &new_shape)
self_type & reshape_helper(std::vector< size_t > &acc)
NdArray(const std::vector< size_t > &shape_, const std::vector< std::string > &attr_names, Args &&... args)
const std::vector< size_t > & shape() const
Definition NdArray.h:319
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)
bool operator!=(const self_type &b) const
self_type rslice(size_t i)
NdArray copy() const
Definition NdArray.h:310
T & at_helper(size_t offset_acc, size_t axis, const std::string &attr)
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
T & at_helper(size_t offset_acc, size_t axis, size_t i, D... rest)
const std::vector< std::string > & attributes() const
const self_type rslice(size_t i) const
NdArray(self_type &&) noexcept=default
NdArray(std::vector< size_t > shape_, Container< T > &&data)
self_type & reshape(size_t i, D... rest)
const T & at(size_t i, D... rest) const
self_type & concatenate(const self_type &other)
size_t get_attr_offset(const std::string &attr) const
T & at_helper(size_t offset_acc, size_t axis)
bool operator==(const self_type &b) const
const std::vector< std::size_t > & strides() const
Definition NdArray.h:331
self_type & reshape_helper(std::vector< size_t > &acc, size_t i, D... rest)
NdArray(std::vector< size_t > shape_)
std::unique_ptr< Details > m_details_ptr
Definition NdArray.h:619
NdArray(std::vector< size_t > shape_, Iterator begin, Iterator end)
T & at(const std::vector< size_t > &coords)
const T & at_helper(size_t offset_acc, size_t axis, const std::string &attr) const
const_iterator end() const
T & at(size_t i, D... rest)
NdArray(const self_type &)
const self_type slice(size_t i) const
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)
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.
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 > >().resize(std::vector< size_t >{}), void())
Definition NdArray.h:577
ContainerWrapper(const ContainerWrapper &)=delete
auto nbytesImpl(int) const -> decltype(std::declval< Container< T2 > >().nbytes())
Definition NdArray.h:563
void resize(const std::vector< size_t > &shape) final
Definition NdArray.h:596
std::unique_ptr< ContainerInterface > copy() const final
Expected to generate a deep copy of the underlying data.
Definition NdArray.h:601
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 > >().resize(size_t{}), void())
Definition NdArray.h:583
ContainerWrapper(ContainerWrapper &&)=default
size_t nbytes() const final
Get the size in bytes.
Definition NdArray.h:572
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