GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 65.6% 63 / 0 / 96
Functions: 100.0% 22 / 0 / 22
Branches: 89.3% 25 / 4 / 32

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/4
std::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/4
std::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