Tannic
A C++ Tensor Library
Loading...
Searching...
No Matches
shape.hpp
Go to the documentation of this file.
1// Copyright 2025 Eric Hermosis
2//
3// This file is part of the Tannic Tensor Library.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17
18#ifndef SHAPE_HPP
19#define SHAPE_HPP
20
44#include <type_traits>
45#include <array>
46#include <cstdint>
47#include <cassert>
48#include <initializer_list>
49#include <ostream>
50
51#include "concepts.hpp"
52#include "indexing.hpp"
53#include "exceptions.hpp"
54
55namespace tannic {
56
79class Shape {
80public:
81 static constexpr uint8_t limit = 8;
82
83public:
84 using rank_type = uint8_t;
85 using size_type = size_t;
86
90 constexpr Shape() noexcept = default;
91
92
105 constexpr Shape(std::initializer_list<size_type> shape) {
106 assert(shape.size() < limit && "Rank limit exceeded");
107 rank_ = static_cast<size_type>(shape.size());
108 size_type dimension = 0;
109 for (auto size : shape) {
110 sizes_[dimension++] = size;
111 }
112 if (rank_> limit)
113 throw Exception("Shape rank limit exceeded");
114 }
115
116
132 template<Integral... Sizes>
133 constexpr Shape(Sizes... sizes)
134 : sizes_{static_cast<size_type>(sizes)...}
135 , rank_(sizeof...(sizes)) {
136 if (rank_> limit)
137 throw Exception("Shape rank limit exceeded");
138 }
139
140
146 template<Iterable Sizes>
147 constexpr Shape(Sizes&& sizes) {
148 size_type dimension = 0;
149 for (auto size : sizes) {
150 sizes_[dimension++] = static_cast<size_type>(size);
151 }
152 rank_ = dimension;
153 if (rank_> limit)
154 throw Exception("Shape rank limit exceeded");
155 }
156
157
175 template<Iterator Iterator>
177 size_type dimension = 0;
178 for (Iterator iterator = begin; iterator != end; ++iterator) {
179 sizes_[dimension++] = static_cast<size_type>(*iterator);
180 }
181 rank_ = dimension;
182 if (rank_> limit)
183 throw Exception("Shape rank limit exceeded");
184 }
185
186public:
191 constexpr size_type* address() noexcept {
192 return sizes_.data();
193 }
194
199 constexpr size_type const* address() const noexcept {
200 return sizes_.data();
201 }
202
207 constexpr rank_type rank() const noexcept {
208 return rank_;
209 }
210
211
214
215 constexpr auto begin() {
216 return sizes_.begin();
217 }
218
219 constexpr auto end() {
220 return sizes_.begin() + rank_;
221 }
222
223 constexpr auto begin() const {
224 return sizes_.begin();
225 }
226
227 constexpr auto end() const {
228 return sizes_.begin() + rank_;
229 }
230
231 constexpr auto cbegin() const {
232 return sizes_.cbegin();
233 }
234
235 constexpr auto cend() const {
236 return sizes_.cbegin() + rank_;
237 }
239
244 constexpr auto front() const noexcept {
245 return sizes_.front();
246 }
247
253 constexpr auto back() const {
254 if (rank_ == 0)
255 throw Exception("Cannot call back() on an empty Shape");
256 return sizes_[rank_ - 1];
257 }
258
265 template<Integral Index>
266 constexpr auto const& operator[](Index index) const {
267 return sizes_[indexing::normalize(index, rank())];
268 }
269
276 template<Integral Index>
277 constexpr auto& operator[](Index index) {
278 return sizes_[indexing::normalize(index, rank())];
279 }
280
281
286 constexpr void expand(size_type size) {
287 if (rank_ + 1 > limit)
288 throw Exception("Shape rank limit exceeded");
289 sizes_[rank_] = size;
290 rank_ += 1;
291 }
292
293
294private:
295 rank_type rank_{0};
296 std::array<size_type, limit> sizes_{};
297};
298
305constexpr bool operator==(Shape const& first, Shape const& second) {
306 if (first.rank() != second.rank()) return false;
307 for (Shape::size_type dimension = 0; dimension < first.rank(); ++dimension) {
308 if (first[dimension] != second[dimension]) return false;
309 }
310 return true;
311}
312
313inline std::ostream& operator<<(std::ostream& os, Shape const& shape) {
314 os << "Shape(";
315 for (Shape::rank_type dimension = 0; dimension < shape.rank(); ++dimension) {
316 os << static_cast<unsigned int>(shape[dimension]);
317 if (dimension + 1 < shape.rank()) {
318 os << ", ";
319 }
320 }
321 os << ")";
322 return os;
323}
324
325
326} // namespace tannic
327
328#endif // SHAPE_HPP
A simple generic exception type for the Tannic Tensor Library.
Definition: exceptions.hpp:44
Represents the shape (dimensions) of an tensor-like expression.
Definition: shape.hpp:79
constexpr auto end() const
Definition: shape.hpp:227
constexpr rank_type rank() const noexcept
Returns the number of dimensions (rank).
Definition: shape.hpp:207
constexpr auto begin()
Definition: shape.hpp:215
constexpr Shape(Sizes... sizes)
Constructs a shape from a list of size arguments.
Definition: shape.hpp:133
size_t size_type
Type used for size and shape dimensions.
Definition: shape.hpp:85
constexpr Shape(Iterator begin, Iterator end)
Constructs a shape from a pair of iterators.
Definition: shape.hpp:176
constexpr auto cbegin() const
Definition: shape.hpp:231
constexpr auto cend() const
Definition: shape.hpp:235
constexpr auto const & operator[](Index index) const
Accesses a dimension by index (const).
Definition: shape.hpp:266
constexpr void expand(size_type size)
Expands the shape's last dimension with a given size.
Definition: shape.hpp:286
constexpr size_type * address() noexcept
Returns a pointer to the internal size data (non-const).
Definition: shape.hpp:191
constexpr auto end()
Definition: shape.hpp:219
constexpr Shape() noexcept=default
Default constructor.
constexpr auto front() const noexcept
Returns the first dimension size.
Definition: shape.hpp:244
constexpr auto begin() const
Definition: shape.hpp:223
constexpr auto & operator[](Index index)
Accesses a dimension by index (non-const).
Definition: shape.hpp:277
constexpr auto back() const
Returns the last dimension size.
Definition: shape.hpp:253
constexpr Shape(Sizes &&sizes)
Constructs a shape from any iterable container of sizes.
Definition: shape.hpp:147
uint8_t rank_type
Type used for rank (number of dimensions).
Definition: shape.hpp:84
static constexpr uint8_t limit
Definition: shape.hpp:81
constexpr size_type const * address() const noexcept
Returns a pointer to the internal size data (const).
Definition: shape.hpp:199
Requires a type to be an integral type (e.g., int, std::size_t).
Definition: concepts.hpp:147
Requires a type to satisfy the C++20 std::input_iterator concept.
Definition: concepts.hpp:140
constexpr Index normalize(Index index, Size bound)
Normalize a possibly-negative index into the valid range [0, bound).
Definition: indexing.hpp:87
Definition: buffer.hpp:41
std::ostream & operator<<(std::ostream &os, Shape const &shape)
Definition: shape.hpp:313