tensor.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <array> | ||
| 4 | |||
| 5 | template <typename T, int NDIMS> struct tensor_view { | ||
| 6 | static_assert(NDIMS >= 0, "NDIMS must be nonnegative"); | ||
| 7 | |||
| 8 | protected: | ||
| 9 | std::array<int, NDIMS> shape; | ||
| 10 | std::array<int, NDIMS> strides; | ||
| 11 | T* data; | ||
| 12 | |||
| 13 | 54 | tensor_view(std::array<int, NDIMS> shape_, std::array<int, NDIMS> strides_, T* data_) : shape(shape_), strides(strides_), data(data_) {} | |
| 14 | |||
| 15 | public: | ||
| 16 | ✗ | tensor_view() : shape{0}, strides{0}, data(nullptr) {} | |
| 17 | |||
| 18 | protected: | ||
| 19 | ✗ | int flatten_index(std::array<int, NDIMS> idx) const { | |
| 20 | ✗ | int res = 0; | |
| 21 | ✗ | for (int i = 0; i < NDIMS; i++) { res += idx[i] * strides[i]; } | |
| 22 | ✗ | return res; | |
| 23 | } | ||
| 24 | 18 | int flatten_index_checked(std::array<int, NDIMS> idx) const { | |
| 25 | 18 | int res = 0; | |
| 26 |
2/2✓ Branch 30 → 3 taken 36 times.
✓ Branch 30 → 31 taken 18 times.
|
54 | for (int i = 0; i < NDIMS; i++) { |
| 27 | 36 | assert(0 <= idx[i] && idx[i] < shape[i]); | |
| 28 | 36 | res += idx[i] * strides[i]; | |
| 29 | } | ||
| 30 | 18 | return res; | |
| 31 | } | ||
| 32 | |||
| 33 | public: | ||
| 34 | 12 | T& operator[] (std::array<int, NDIMS> idx) const { | |
| 35 | #ifdef _GLIBCXX_DEBUG | ||
| 36 | 12 | return data[flatten_index_checked(idx)]; | |
| 37 | #else | ||
| 38 | return data[flatten_index(idx)]; | ||
| 39 | #endif | ||
| 40 | } | ||
| 41 | 6 | T& at(std::array<int, NDIMS> idx) const { | |
| 42 | 6 | return data[flatten_index_checked(idx)]; | |
| 43 | } | ||
| 44 | |||
| 45 | template <int D = NDIMS> | ||
| 46 | 24 | typename std::enable_if<(0 < D), tensor_view<T, NDIMS-1>>::type operator[] (int idx) const { | |
| 47 |
4/4std::enable_if<(0)<(1), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 0> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 1>::operator[]<1>(int) const:
✓ Branch 15 → 16 taken 6 times.
std::enable_if<(0)<(2), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 1> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 2>::operator[]<2>(int) const:
✓ Branch 17 → 18 taken 6 times.
std::enable_if<(0)<(1), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 0> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1>::operator[]<1>(int) const:
✓ Branch 15 → 16 taken 6 times.
std::enable_if<(0)<(2), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 2>::operator[]<2>(int) const:
✓ Branch 17 → 18 taken 6 times.
|
84 | std::array<int, NDIMS-1> nshape; std::copy(shape.begin()+1, shape.end(), nshape.begin()); |
| 48 |
4/4std::enable_if<(0)<(1), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 0> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 1>::operator[]<1>(int) const:
✓ Branch 33 → 34 taken 6 times.
std::enable_if<(0)<(2), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 1> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 2>::operator[]<2>(int) const:
✓ Branch 37 → 38 taken 6 times.
std::enable_if<(0)<(1), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 0> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1>::operator[]<1>(int) const:
✓ Branch 33 → 34 taken 6 times.
std::enable_if<(0)<(2), tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1> >::type tensor_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 2>::operator[]<2>(int) const:
✓ Branch 37 → 38 taken 6 times.
|
84 | std::array<int, NDIMS-1> nstrides; std::copy(strides.begin()+1, strides.end(), nstrides.begin()); |
| 49 | 48 | T* ndata = data + (strides[0] * idx); | |
| 50 | 60 | return tensor_view<T, NDIMS-1>(nshape, nstrides, ndata); | |
| 51 | } | ||
| 52 | template <int D = NDIMS> | ||
| 53 | ✗ | typename std::enable_if<(0 < D), tensor_view<T, NDIMS-1>>::type at(int idx) const { | |
| 54 | ✗ | assert(0 <= idx && idx < shape[0]); | |
| 55 | ✗ | return operator[](idx); | |
| 56 | } | ||
| 57 | |||
| 58 | template <int D = NDIMS> | ||
| 59 | 12 | typename std::enable_if<(0 == D), T&>::type operator * () const { | |
| 60 | 12 | return *data; | |
| 61 | } | ||
| 62 | |||
| 63 | template <typename U, int D> friend struct tensor_view; | ||
| 64 | template <typename U, int D> friend struct tensor; | ||
| 65 | }; | ||
| 66 | |||
| 67 | template <typename T, int NDIMS> struct tensor { | ||
| 68 | static_assert(NDIMS >= 0, "NDIMS must be nonnegative"); | ||
| 69 | |||
| 70 | protected: | ||
| 71 | std::array<int, NDIMS> shape; | ||
| 72 | std::array<int, NDIMS> strides; | ||
| 73 | int len; | ||
| 74 | T* data; | ||
| 75 | |||
| 76 | public: | ||
| 77 | ✗ | tensor() : shape{0}, strides{0}, len(0), data(nullptr) {} | |
| 78 | |||
| 79 | 1 | explicit tensor(std::array<int, NDIMS> shape_, const T& t = T()) { | |
| 80 | 1 | shape = shape_; | |
| 81 | 1 | len = 1; | |
| 82 |
2/2✓ Branch 29 → 8 taken 2 times.
✓ Branch 29 → 30 taken 1 time.
|
3 | for (int i = NDIMS-1; i >= 0; i--) { |
| 83 | 2 | strides[i] = len; | |
| 84 | 2 | len *= shape[i]; | |
| 85 | } | ||
| 86 |
3/4✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 35 not taken.
✓ Branch 44 → 40 taken 6 times.
✓ Branch 44 → 45 taken 1 time.
|
7 | data = new T[len]; |
| 87 | 1 | std::fill(data, data + len, t); | |
| 88 | 1 | } | |
| 89 | |||
| 90 |
3/4✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 23 not taken.
✓ Branch 32 → 28 taken 12 times.
✓ Branch 32 → 33 taken 2 times.
|
14 | tensor(const tensor& o) : shape(o.shape), strides(o.strides), len(o.len), data(new T[len]) { |
| 91 |
2/2✓ Branch 56 → 38 taken 12 times.
✓ Branch 56 → 57 taken 2 times.
|
14 | for (int i = 0; i < len; i++) { |
| 92 | 24 | data[i] = o.data[i]; | |
| 93 | } | ||
| 94 | 2 | } | |
| 95 | |||
| 96 | ✗ | tensor& operator=(tensor&& o) noexcept { | |
| 97 | using std::swap; | ||
| 98 | ✗ | swap(shape, o.shape); | |
| 99 | ✗ | swap(strides, o.strides); | |
| 100 | ✗ | swap(len, o.len); | |
| 101 | ✗ | swap(data, o.data); | |
| 102 | ✗ | return *this; | |
| 103 | } | ||
| 104 | ✗ | tensor(tensor&& o) : tensor() { | |
| 105 | ✗ | *this = std::move(o); | |
| 106 | } | ||
| 107 | ✗ | tensor& operator=(const tensor& o) { | |
| 108 | ✗ | return *this = tensor(o); | |
| 109 | } | ||
| 110 |
3/4✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 40 not taken.
✓ Branch 20 → 21 taken 18 times.
✓ Branch 20 → 29 taken 3 times.
|
21 | ~tensor() { delete[] data; } |
| 111 | |||
| 112 | using view_t = tensor_view<T, NDIMS>; | ||
| 113 | 24 | view_t view() { | |
| 114 | 24 | return tensor_view<T, NDIMS>(shape, strides, data); | |
| 115 | } | ||
| 116 | ✗ | operator view_t() { | |
| 117 | ✗ | return view(); | |
| 118 | } | ||
| 119 | |||
| 120 | using const_view_t = tensor_view<const T, NDIMS>; | ||
| 121 | 6 | const_view_t view() const { | |
| 122 | 6 | return tensor_view<const T, NDIMS>(shape, strides, data); | |
| 123 | } | ||
| 124 | ✗ | operator const_view_t() const { | |
| 125 | ✗ | return view(); | |
| 126 | } | ||
| 127 | |||
| 128 | 12 | T& operator[] (std::array<int, NDIMS> idx) { return view()[idx]; } | |
| 129 | 6 | T& at(std::array<int, NDIMS> idx) { return view().at(idx); } | |
| 130 | ✗ | const T& operator[] (std::array<int, NDIMS> idx) const { return view()[idx]; } | |
| 131 | ✗ | const T& at(std::array<int, NDIMS> idx) const { return view().at(idx); } | |
| 132 | |||
| 133 | template <int D = NDIMS> | ||
| 134 | 6 | typename std::enable_if<(0 < D), tensor_view<T, NDIMS-1>>::type operator[] (int idx) { | |
| 135 |
1/1✓ Branch 6 → 7 taken 6 times.
|
6 | return view()[idx]; |
| 136 | } | ||
| 137 | template <int D = NDIMS> | ||
| 138 | ✗ | typename std::enable_if<(0 < D), tensor_view<T, NDIMS-1>>::type at(int idx) { | |
| 139 | ✗ | return view().at(idx); | |
| 140 | } | ||
| 141 | |||
| 142 | template <int D = NDIMS> | ||
| 143 | 6 | typename std::enable_if<(0 < D), tensor_view<const T, NDIMS-1>>::type operator[] (int idx) const { | |
| 144 |
1/1✓ Branch 6 → 7 taken 6 times.
|
6 | return view()[idx]; |
| 145 | } | ||
| 146 | template <int D = NDIMS> | ||
| 147 | ✗ | typename std::enable_if<(0 < D), tensor_view<const T, NDIMS-1>>::type at(int idx) const { | |
| 148 | ✗ | return view().at(idx); | |
| 149 | } | ||
| 150 | |||
| 151 | template <int D = NDIMS> | ||
| 152 | ✗ | typename std::enable_if<(0 == D), T&>::type operator * () { | |
| 153 | ✗ | return *view(); | |
| 154 | } | ||
| 155 | template <int D = NDIMS> | ||
| 156 | ✗ | typename std::enable_if<(0 == D), const T&>::type operator * () const { | |
| 157 | ✗ | return *view(); | |
| 158 | } | ||
| 159 | }; | ||
| 160 |