Stratax 0.2.0
Loading...
Searching...
No Matches
Tensor.hpp
1#pragma once
2
3#include <stratax/core/containers/Buffer.hpp>
4#include <stratax/core/Concepts.hpp>
5#include <stratax/core/containers/Shape.hpp>
6#include <stratax/core/Exceptions.hpp>
8#include <stratax/core/containers/Strides.hpp>
9#include <stratax/core/ops/Indexing.hpp>
10
11#include <array>
12#include <cstddef>
13#include <initializer_list>
14#include <stdexcept>
15#include <type_traits>
16#include <utility>
17
18namespace stratax::container {
19
28template<typename T>
29requires Numeric<T>
30class Tensor
31{
32private:
33 core::Shape shape_;
34 core::Strides strides_;
35 core::Buffer<T> buffer_;
36
37public:
39 using value_type = T;
40
43
46
49
52
54 template<typename U>
56
63 Tensor() noexcept = default;
64
73 explicit Tensor(const core::Shape& shape)
74 : shape_(shape),
75 strides_(shape_),
76 buffer_(shape_.elements())
77 {
78 }
79
87 Tensor(const core::Shape& shape, const T& value)
88 : shape_(shape),
89 strides_(shape_),
90 buffer_(shape_.elements(), value)
91 {
92 }
93
98 Tensor(const Tensor&) = default;
99
104 Tensor(Tensor&&) noexcept = default;
105
110 Tensor& operator=(const Tensor&) = default;
111
116 Tensor& operator=(Tensor&&) noexcept = default;
117
122 ~Tensor() = default;
123
129 [[nodiscard]] std::size_t size() const noexcept
130 {
131 return buffer_.size();
132 }
133
139 [[nodiscard]] bool empty() const noexcept
140 {
141 return buffer_.empty();
142 }
143
149 [[nodiscard]] std::size_t rank() const noexcept
150 {
151 return shape_.rank();
152 }
153
159 const core::Shape& shape() const noexcept
160 {
161 return shape_;
162 }
163
169 const core::Strides& strides() const noexcept
170 {
171 return strides_;
172 }
173
182 T& operator()(std::size_t index) noexcept
183 {
184 return buffer_[index];
185 }
186
195 const T& operator()(std::size_t index) const noexcept
196 {
197 return buffer_[index];
198 }
199
208 T& operator[](std::size_t index) noexcept
209 {
210 return buffer_[index];
211 }
212
221 const T& operator[](std::size_t index) const noexcept
222 {
223 return buffer_[index];
224 }
225
240 template<typename... Rest>
241 T& operator()(std::size_t first, std::size_t second, Rest... rest)
242 {
243 std::array<std::size_t, sizeof...(Rest) + 2> indices{
244 first,
245 second,
246 static_cast<std::size_t>(rest)...
247 };
248
249 return buffer_[offset(shape_, strides_, indices)];
250 }
251
263 template<typename... Rest>
264 const T& operator()(std::size_t first, std::size_t second, Rest... rest) const
265 {
266 std::array<std::size_t, sizeof...(Rest) + 2> indices{
267 first,
268 second,
269 static_cast<std::size_t>(rest)...
270 };
271
272 return buffer_[offset(shape_, strides_, indices)];
273 }
274
284 T& operator()(const std::vector<std::size_t>& indices)
285 {
286 return buffer_[offset(shape_, strides_, indices)];
287 }
288
298 const T& operator()(const std::vector<std::size_t>& indices) const
299 {
300 return buffer_[offset(shape_, strides_, indices)];
301 }
302
311 T& at(std::ptrdiff_t index)
312 {
313 const std::size_t normalized =
314 core::validation::normalize_index(index, size(), "Tensor flat index out of bounds.");
315 return buffer_[normalized];
316 }
317
326 const T& at(std::ptrdiff_t index) const
327 {
328 const std::size_t normalized =
329 core::validation::normalize_index(index, size(), "Tensor flat index out of bounds.");
330 return buffer_[normalized];
331 }
332
344 template<typename... Rest>
345 requires ((std::is_integral_v<Rest>) && ...)
346 T& at(std::ptrdiff_t first, std::ptrdiff_t second, Rest... rest)
347 {
348 std::array<std::ptrdiff_t, sizeof...(Rest) + 2> raw_indices{
349 first,
350 second,
351 static_cast<std::ptrdiff_t>(rest)...
352 };
353
354 std::array<std::size_t, sizeof...(Rest) + 2> indices{};
355 if (indices.size() != rank())
356 {
357 throw Exceptions::IndexError("Tensor multi-index rank must match tensor rank.");
358 }
359
360 for (std::size_t i = 0; i < indices.size(); ++i)
361 {
362 indices[i] = core::validation::normalize_index(
363 raw_indices[i],
364 shape()(i),
365 "Tensor multi-index component is out of bounds.");
366 }
367
368 try
369 {
370 return buffer_[offset(shape_, strides_, indices)];
371 }
372 catch (const Exceptions::DimensionError&)
373 {
374 throw Exceptions::IndexError("Tensor multi-index rank must match tensor rank.");
375 }
376 catch (const Exceptions::IndexError&)
377 {
378 throw Exceptions::IndexError("Tensor multi-index component is out of bounds.");
379 }
380 }
381
393 template<typename... Rest>
394 requires ((std::is_integral_v<Rest>) && ...)
395 const T& at(std::ptrdiff_t first, std::ptrdiff_t second, Rest... rest) const
396 {
397 std::array<std::ptrdiff_t, sizeof...(Rest) + 2> raw_indices{
398 first,
399 second,
400 static_cast<std::ptrdiff_t>(rest)...
401 };
402
403 std::array<std::size_t, sizeof...(Rest) + 2> indices{};
404 if (indices.size() != rank())
405 {
406 throw Exceptions::IndexError("Tensor multi-index rank must match tensor rank.");
407 }
408
409 for (std::size_t i = 0; i < indices.size(); ++i)
410 {
411 indices[i] = core::validation::normalize_index(
412 raw_indices[i],
413 shape()(i),
414 "Tensor multi-index component is out of bounds.");
415 }
416
417 try
418 {
419 return buffer_[offset(shape_, strides_, indices)];
420 }
421 catch (const Exceptions::DimensionError&)
422 {
423 throw Exceptions::IndexError("Tensor multi-index rank must match tensor rank.");
424 }
425 catch (const Exceptions::IndexError&)
426 {
427 throw Exceptions::IndexError("Tensor multi-index component is out of bounds.");
428 }
429 }
430
437 T& front()
438 {
439 return buffer_.front();
440 }
441
448 const T& front() const
449 {
450 return buffer_.front();
451 }
452
459 T& back()
460 {
461 return buffer_.back();
462 }
463
470 const T& back() const
471 {
472 return buffer_.back();
473 }
474
480 [[nodiscard]] T* data() noexcept
481 {
482 return buffer_.data();
483 }
484
490 [[nodiscard]] const T* data() const noexcept
491 {
492 return buffer_.data();
493 }
494
500 [[nodiscard]] iterator begin() noexcept
501 {
502 return buffer_.begin();
503 }
504
510 [[nodiscard]] const_iterator begin() const noexcept
511 {
512 return buffer_.begin();
513 }
514
520 [[nodiscard]] const_iterator cbegin() const noexcept
521 {
522 return buffer_.cbegin();
523 }
524
530 [[nodiscard]] iterator end() noexcept
531 {
532 return buffer_.end();
533 }
534
540 [[nodiscard]] const_iterator end() const noexcept
541 {
542 return buffer_.end();
543 }
544
550 [[nodiscard]] const_iterator cend() const noexcept
551 {
552 return buffer_.cend();
553 }
554
560 [[nodiscard]] reverse_iterator rbegin() noexcept
561 {
562 return buffer_.rbegin();
563 }
564
570 [[nodiscard]] const_reverse_iterator rbegin() const noexcept
571 {
572 return buffer_.rbegin();
573 }
574
580 [[nodiscard]] const_reverse_iterator crbegin() const noexcept
581 {
582 return buffer_.crbegin();
583 }
584
590 [[nodiscard]] reverse_iterator rend() noexcept
591 {
592 return buffer_.rend();
593 }
594
600 [[nodiscard]] const_reverse_iterator rend() const noexcept
601 {
602 return buffer_.rend();
603 }
604
610 [[nodiscard]] const_reverse_iterator crend() const noexcept
611 {
612 return buffer_.crend();
613 }
614
620 void fill(const T& value)
621 {
622 buffer_.fill(value);
623 }
624
630 void swap(Tensor& other) noexcept
631 {
632 shape_.swap(other.shape_);
633 strides_.swap(other.strides_);
634 buffer_.swap(other.buffer_);
635 }
636};
637
638}
639
Shared runtime validation helpers.
Signals an invalid dimension count or dimension arithmetic failure.
Signals an invalid index access.
void fill(const T &value)
Fills every element with the same value.
Definition Tensor.hpp:620
T & operator()(const std::vector< std::size_t > &indices)
Returns an element by multidimensional index from a vector with bounds checking.
Definition Tensor.hpp:284
void swap(Tensor &other) noexcept
Swaps the contents of two tensors.
Definition Tensor.hpp:630
typename core::Buffer< T >::const_reverse_iterator const_reverse_iterator
Const reverse iterator over tensor elements.
Definition Tensor.hpp:51
T & operator()(std::size_t first, std::size_t second, Rest... rest)
Returns an element by multidimensional index with bounds checking.
Definition Tensor.hpp:241
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Tensor.hpp:580
Tensor(const Tensor &)=default
Creates a copy of another tensor.
const_iterator end() const noexcept
Returns a const iterator one past the last element.
Definition Tensor.hpp:540
const core::Shape & shape() const noexcept
Definition Tensor.hpp:159
T * data() noexcept
Returns the raw data pointer.
Definition Tensor.hpp:480
const T & front() const
Returns the first element as a const reference.
Definition Tensor.hpp:448
const T & operator[](std::size_t index) const noexcept
Returns a flat element without bounds checking.
Definition Tensor.hpp:221
Tensor(const core::Shape &shape, const T &value)
Creates a tensor from a shape and fills it with a value.
Definition Tensor.hpp:87
std::size_t rank() const noexcept
Returns the tensor rank.
Definition Tensor.hpp:149
bool empty() const noexcept
Returns whether the tensor contains no elements.
Definition Tensor.hpp:139
std::size_t size() const noexcept
Definition Tensor.hpp:129
const_iterator cbegin() const noexcept
Returns a const iterator to the first element.
Definition Tensor.hpp:520
T & front()
Returns the first element.
Definition Tensor.hpp:437
typename core::Buffer< T >::reverse_iterator reverse_iterator
Mutable reverse iterator over tensor elements.
Definition Tensor.hpp:48
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator before the first element.
Definition Tensor.hpp:600
const core::Strides & strides() const noexcept
Returns the tensor strides.
Definition Tensor.hpp:169
const_iterator begin() const noexcept
Returns a const iterator to the first element.
Definition Tensor.hpp:510
iterator begin() noexcept
Returns an iterator to the first element.
Definition Tensor.hpp:500
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the last element.
Definition Tensor.hpp:560
Tensor() noexcept=default
Creates an empty tensor with rank 0.
iterator end() noexcept
Returns an iterator one past the last element.
Definition Tensor.hpp:530
T & operator[](std::size_t index) noexcept
Returns a flat element without bounds checking.
Definition Tensor.hpp:208
const T * data() const noexcept
Returns the raw data pointer as a const pointer.
Definition Tensor.hpp:490
const T & operator()(const std::vector< std::size_t > &indices) const
Returns an element by multidimensional index from a vector with bounds checking.
Definition Tensor.hpp:298
T & operator()(std::size_t index) noexcept
Returns a flat element without bounds checking.
Definition Tensor.hpp:182
Tensor< U > rebind
Rebinds the tensor container to another element type.
Definition Tensor.hpp:55
typename core::Buffer< T >::const_iterator const_iterator
Const iterator over tensor elements.
Definition Tensor.hpp:45
typename core::Buffer< T >::iterator iterator
Mutable iterator over tensor elements.
Definition Tensor.hpp:42
T & at(std::ptrdiff_t index)
Returns an element by rank-1 flat index with bounds checking.
Definition Tensor.hpp:311
const T & at(std::ptrdiff_t index) const
Returns an element by rank-1 flat index with bounds checking.
Definition Tensor.hpp:326
T & back()
Returns the last element.
Definition Tensor.hpp:459
const T & at(std::ptrdiff_t first, std::ptrdiff_t second, Rest... rest) const
Returns an element by multi-index with bounds checking.
Definition Tensor.hpp:395
T value_type
Element type stored by the tensor.
Definition Tensor.hpp:39
const T & operator()(std::size_t index) const noexcept
Returns a flat element without bounds checking.
Definition Tensor.hpp:195
reverse_iterator rend() noexcept
Returns a reverse iterator before the first element.
Definition Tensor.hpp:590
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator before the first element.
Definition Tensor.hpp:610
Tensor(Tensor &&) noexcept=default
Transfers ownership from another tensor.
const T & operator()(std::size_t first, std::size_t second, Rest... rest) const
Returns an element by multidimensional index with bounds checking.
Definition Tensor.hpp:264
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Tensor.hpp:570
const_iterator cend() const noexcept
Returns a const iterator one past the last element.
Definition Tensor.hpp:550
const T & back() const
Returns the last element as a const reference.
Definition Tensor.hpp:470
T & at(std::ptrdiff_t first, std::ptrdiff_t second, Rest... rest)
Returns an element by multi-index with bounds checking.
Definition Tensor.hpp:346
Owns contiguous dynamically allocated storage.
Definition Buffer.hpp:38
std::reverse_iterator< iterator > reverse_iterator
Mutable reverse iterator over contiguous buffer elements.
Definition Buffer.hpp:53
const T * const_iterator
Const iterator over contiguous buffer elements.
Definition Buffer.hpp:50
T * iterator
Mutable iterator over contiguous buffer elements.
Definition Buffer.hpp:47
std::reverse_iterator< const_iterator > const_reverse_iterator
Const reverse iterator over contiguous buffer elements.
Definition Buffer.hpp:56
Stores a list of dimension lengths for an array shape.
Definition Shape.hpp:22
Stores strides for a shape in contiguous memory.
Definition Strides.hpp:23