Stratax 0.3.1
Loading...
Searching...
No Matches
Shape.hpp
1#pragma once
2
3#include <algorithm>
4#include <cstddef>
5#include <initializer_list>
6#include <ostream>
7#include <vector>
8#include <limits>
9
10#include <stratax/core/Buffer.hpp>
11#include <stratax/exceptions/Exceptions.hpp>
12#include <stratax/indexing/Normalize.hpp>
13
14namespace stratax::core {
15
32class Shape
33{
34private:
36
37public:
39 using value_type = std::size_t;
41 using size_type = std::size_t;
43 using difference_type = std::ptrdiff_t;
50
55 Shape() noexcept = default;
56
64 Shape(std::initializer_list<value_type> dims)
65 : dims_(dims)
66 {}
67
75 Shape(const std::vector<value_type>& dims)
76 : dims_(dims.size())
77 {
78 std::copy(dims.begin(), dims.end(), dims_.begin());
79 }
80
91 [[nodiscard]] size_type elements() const
92 {
93 if (empty())
94 {
95 return 0;
96 }
97 size_type prod = 1;
98 for (value_type dim : dims_)
99 {
100 if (dim == 0)
101 {
102 return 0;
103 }
104
105 if (prod > std::numeric_limits<size_type>::max() / dim)
106 {
107 throw Exceptions::DimensionError("Shape element count overflow.");
108 }
109
110 prod *= dim;
111 }
112
113 return prod;
114 }
115
121 [[nodiscard]] size_type rank() const noexcept
122 {
123 return dims_.size();
124 }
125
138 [[nodiscard]] Shape strides() const
139 {
140 if (empty())
141 {
142 return {};
143 }
144
145 std::vector<value_type> stride_values(rank());
146 stride_values[rank() - 1] = 1;
147
148 for (size_type i = rank() - 1; i > 0; --i)
149 {
150 if (dims_[i] != 0 &&
151 stride_values[i] > std::numeric_limits<value_type>::max() / dims_[i])
152 {
153 throw Exceptions::DimensionError("Shape stride overflow.");
154 }
155
156 stride_values[i - 1] = stride_values[i] * dims_[i];
157 }
158
159 return Shape(stride_values);
160 }
161
169 [[nodiscard]] const_reference operator[](size_type index) const noexcept
170 {
171 return dims_[index];
172 }
173
185 [[nodiscard]] const_reference at(difference_type index) const
186 {
187 return dims_[stratax::indexing::normalize_index(index, rank())];
188 }
189
195 [[nodiscard]] bool empty() const noexcept
196 {
197 return dims_.empty();
198 }
199
206 [[nodiscard]] bool operator==(const Shape& other) const noexcept
207 {
208 if (rank() != other.rank())
209 {
210 return false;
211 }
212 for (size_type i = 0; i < rank(); ++i)
213 {
214 if (dims_[i] != other.dims_[i])
215 {
216 return false;
217 }
218 }
219 return true;
220 }
221
223 const_iterator begin() const noexcept
224 {
225 return dims_.begin();
226 }
228 const_iterator end() const noexcept
229 {
230 return dims_.end();
231 }
233 const_iterator cbegin() const noexcept
234 {
235 return dims_.cbegin();
236 }
238 const_iterator cend() const noexcept
239 {
240 return dims_.cend();
241 }
244 {
245 return dims_.rbegin();
246 }
249 {
250 return dims_.crbegin();
251 }
254 {
255 return dims_.rend();
256 }
259 {
260 return dims_.crend();
261 }
262
268 void swap(Shape& other) noexcept
269 {
270 dims_.swap(other.dims_);
271 }
272
273};
274
286inline std::ostream& operator<<(std::ostream& os, const Shape& shape)
287{
288 os << "(";
289
290 bool first = true;
291 for (Shape::value_type dim : shape)
292 {
293 if (!first)
294 os << ", ";
295
296 os << dim;
297 first = false;
298 }
299
300 if (shape.rank() == 1)
301 {
302 os << ",";
303 }
304
305 os << ")";
306
307 return os;
308}
309
310}
Fixed-size owner of aligned, contiguous element storage.
Definition Buffer.hpp:51
const_pointer const_iterator
Read-only contiguous random-access iterator type.
Definition Buffer.hpp:74
reverse_iterator rend() noexcept
Returns the past-the-end iterator for mutable reverse traversal.
Definition Buffer.hpp:463
void swap(Buffer &other) noexcept
Swaps storage and size with another buffer.
Definition Buffer.hpp:523
size_type size() const noexcept
Returns the number of stored elements.
Definition Buffer.hpp:486
const_reverse_iterator crend() const noexcept
Returns the past-the-end iterator for const reverse traversal.
Definition Buffer.hpp:475
const_iterator cend() const noexcept
Returns a const iterator one past the final element.
Definition Buffer.hpp:439
bool empty() const noexcept
Returns whether the buffer has no elements.
Definition Buffer.hpp:494
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the final element.
Definition Buffer.hpp:457
reverse_iterator rbegin() noexcept
Returns a mutable reverse iterator to the final element.
Definition Buffer.hpp:445
iterator begin() noexcept
Returns a mutable iterator to the first element.
Definition Buffer.hpp:409
const_iterator cbegin() const noexcept
Returns a const iterator to the first element.
Definition Buffer.hpp:421
std::reverse_iterator< const_iterator > const_reverse_iterator
Read-only iterator that traverses elements in reverse order.
Definition Buffer.hpp:78
iterator end() noexcept
Returns a mutable iterator one past the final element.
Definition Buffer.hpp:427
Stores the dimensions of a multidimensional array.
Definition Shape.hpp:33
Shape(const std::vector< value_type > &dims)
Constructs a shape by copying a vector of dimensions.
Definition Shape.hpp:75
size_type elements() const
Computes the total number of elements described by the shape.
Definition Shape.hpp:91
std::size_t size_type
Unsigned type used for ranks and dimension indices.
Definition Shape.hpp:41
size_type rank() const noexcept
Returns the number of dimensions.
Definition Shape.hpp:121
const_reference at(difference_type index) const
Returns a dimension using checked, Python-style indexing.
Definition Shape.hpp:185
const_iterator cend() const noexcept
Returns a const iterator past the final dimension.
Definition Shape.hpp:238
bool empty() const noexcept
Reports whether the shape has rank zero.
Definition Shape.hpp:195
const value_type & const_reference
Read-only reference to a dimension.
Definition Shape.hpp:45
bool operator==(const Shape &other) const noexcept
Compares two shapes dimension by dimension.
Definition Shape.hpp:206
void swap(Shape &other) noexcept
Exchanges dimension storage with another shape.
Definition Shape.hpp:268
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the final dimension.
Definition Shape.hpp:248
const_iterator begin() const noexcept
Returns a const iterator to the first dimension.
Definition Shape.hpp:223
Shape strides() const
Computes canonical row-major strides for this shape.
Definition Shape.hpp:138
const_iterator end() const noexcept
Returns a const iterator past the final dimension.
Definition Shape.hpp:228
Shape() noexcept=default
Constructs an empty, rank-zero shape.
const_reference operator[](size_type index) const noexcept
Returns a dimension without bounds checking.
Definition Shape.hpp:169
Buffer< value_type >::const_reverse_iterator const_reverse_iterator
Read-only iterator over dimensions in reverse order.
Definition Shape.hpp:49
const_reverse_iterator crend() const noexcept
Returns the past-the-end const reverse iterator.
Definition Shape.hpp:258
std::size_t value_type
Type used to represent each dimension.
Definition Shape.hpp:39
const_iterator cbegin() const noexcept
Returns a const iterator to the first dimension.
Definition Shape.hpp:233
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the final dimension.
Definition Shape.hpp:243
Buffer< value_type >::const_iterator const_iterator
Read-only contiguous iterator over dimensions.
Definition Shape.hpp:47
const_reverse_iterator rend() const noexcept
Returns the past-the-end reverse iterator.
Definition Shape.hpp:253
std::ptrdiff_t difference_type
Signed type used for checked indices and iterator distances.
Definition Shape.hpp:43