Alexandria 2.25.0
SDC-CH common library for the Euclid project
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
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:
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
113
120
127
133 Iterator operator+(size_t n) const;
134
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
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
435
441
447
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
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
502
503private:
504 size_t m_offset;
508
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
539 };
540
541 template <template <class...> class Container>
544
545 Container<T> m_container;
546
547 ~ContainerWrapper() = default;
548
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
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
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
665template <typename T>
667
668} // namespace NdArray
669} // namespace Euclid
670
671#define NDARRAY_IMPL
673#undef NDARRAY_IMPL
674
675#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:77
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
std::vector< std::string > m_attr_names
Definition: NdArray.h:506
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:325
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:317
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)
Iterator< true > const_iterator
Definition: NdArray.h:183
bool operator!=(const self_type &b) const
self_type rslice(size_t i)
std::shared_ptr< ContainerInterface > m_container
Definition: NdArray.h:592
NdArray copy() const
Definition: NdArray.h:308
std::vector< size_t > m_shape
Definition: NdArray.h:505
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:333
NdArray(const std::initializer_list< size_t > &shape_)
Definition: NdArray.h:284
const_iterator begin() const
T & at_helper(size_t offset_acc, size_t axis, size_t i, D... rest)
std::vector< size_t > m_stride_size
Definition: NdArray.h:505
NdArray(const self_type &)=default
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)
Iterator< false > iterator
Definition: NdArray.h:184
bool operator==(const self_type &b) const
const std::vector< std::size_t > & strides() const
Definition: NdArray.h:329
self_type & reshape_helper(std::vector< size_t > &acc, size_t i, D... rest)
NdArray(std::vector< size_t > shape_)
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)
virtual ~NdArray()=default
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)
NdArray< T > self_type
Definition: NdArray.h:54
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:522
virtual std::unique_ptr< ContainerInterface > copy() const =0
Expected to generate a deep copy of the underlying data.
size_t nbytes() const
Get the size in bytes.
Definition: NdArray.h:530
T get(size_t offset) const
Get the element at the given absolute offset (in bytes)
Definition: NdArray.h:517
virtual void resize(const std::vector< size_t > &shape)=0
Resize container.
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 > >().resize(std::vector< size_t >{}), void())
Definition: NdArray.h:563
ContainerWrapper(ContainerWrapper &&) noexcept=default
ContainerWrapper(const ContainerWrapper &)=delete
void resize(const std::vector< size_t > &shape) final
Definition: NdArray.h:582
std::unique_ptr< ContainerInterface > copy() const final
Expected to generate a deep copy of the underlying data.
Definition: NdArray.h:587
auto resizeImpl(const std::vector< size_t > &shape) -> decltype((void) std::declval< Container< T2 > >().resize(size_t{}), void())
Definition: NdArray.h:569