33#ifndef LIBTCOD_MATRIX_HPP_
34#define LIBTCOD_MATRIX_HPP_
43template <
typename ArrayType>
44[[nodiscard]]
static std::string array_as_string(
const ArrayType& arr) {
45 std::string result{
"{"};
46 for (
const auto& it : arr) {
47 result += std::to_string(it);
48 if (&it != &arr.back()) {
64template <
typename T,
size_t Dimensions>
67 using size_type = int;
68 using shape_type = std::array<size_type, Dimensions>;
69 using stride_type = std::array<size_type, Dimensions>;
70 using index_type = std::array<size_type, Dimensions>;
72 using const_reference =
const T&;
76 constexpr MatrixView(
const shape_type& shape_xy,
const stride_type& strides_xy, T* data) noexcept
77 : shape_xy_{shape_xy}, strides_xy_{strides_xy}, data_{
reinterpret_cast<data_ptr
>(data)} {};
80 [[nodiscard]]
constexpr reference
operator[](
const index_type& index)
noexcept {
81 return *
reinterpret_cast<T*
>(data_ + get_offset(index));
84 [[nodiscard]]
constexpr const_reference
operator[](
const index_type& index)
const noexcept {
85 return *
reinterpret_cast<const T*
>(data_ + get_offset(index));
88 [[nodiscard]]
constexpr reference
at(
const index_type& index) {
89 return *
reinterpret_cast<T*
>(data_ + check_range(index));
92 [[nodiscard]]
constexpr const_reference
at(
const index_type& index)
const {
93 return *
reinterpret_cast<const T*
>(data_ + check_range(index));
97 [[nodiscard]]
constexpr bool in_bounds(
const index_type& index)
const noexcept {
98 for (
size_t dimension = 0; dimension < Dimensions; ++dimension) {
99 if (!(0 <= index.at(dimension) && index.at(dimension) < shape_xy_.at(dimension)))
return false;
106 using data_ptr =
typename std::conditional<std::is_const<T>::value,
const unsigned char*,
unsigned char*>::type;
108 [[nodiscard]]
constexpr size_t get_offset(
const index_type& index)
const noexcept {
109 size_t data_index = 0;
110 for (
size_t dimension{0}; dimension < Dimensions; ++dimension) {
111 data_index += strides_xy_.at(dimension) * index.at(dimension);
116 constexpr size_t check_range(
const index_type& index)
const {
117 using internal::array_as_string;
119 throw std::out_of_range(
120 std::string(
"Out of bounds lookup ") + array_as_string(index) +
" on matrix of shape " +
121 array_as_string(shape_xy_) +
".");
123 return get_offset(index);
125 shape_type shape_xy_;
126 stride_type strides_xy_;
138template <
typename T,
size_t Dimensions,
typename Container = std::vector<T>>
141 using size_type = int;
142 using shape_type = std::array<size_type, Dimensions>;
143 using index_type = std::array<size_type, Dimensions>;
144 using reference =
typename Container::reference;
145 using const_reference =
typename Container::const_reference;
150 constexpr explicit Matrix(
const shape_type& shape) : shape_{shape}, data_(get_size_from_shape(shape)) {}
153 constexpr Matrix(
const shape_type& shape,
const T& fill_value)
154 : shape_{shape}, data_(get_size_from_shape(shape), fill_value) {}
157 [[nodiscard]]
constexpr auto begin() noexcept {
return data_.begin(); }
159 [[nodiscard]]
constexpr auto begin() const noexcept {
return data_.cbegin(); }
162 [[nodiscard]]
constexpr auto end() noexcept {
return data_.end(); }
164 [[nodiscard]]
constexpr auto end() const noexcept {
return data_.cend(); }
167 [[nodiscard]]
constexpr reference
operator[](
const index_type& index)
noexcept {
return data_[get_index(index)]; }
170 [[nodiscard]]
constexpr const_reference
operator[](
const index_type& index)
const noexcept {
171 return data_[get_index(index)];
174 [[nodiscard]]
constexpr reference
at(
const index_type& index) {
return data_.at(check_range(index)); }
177 [[nodiscard]]
constexpr const_reference
at(
const index_type& index)
const {
return data_.at(check_range(index)); }
180 [[nodiscard]]
constexpr const shape_type&
get_shape() const noexcept {
return shape_; }
183 [[nodiscard]]
constexpr bool in_bounds(
const index_type& index)
const noexcept {
184 for (
size_t dimension = 0; dimension < Dimensions; ++dimension) {
185 if (!(0 <= index.at(dimension) && index.at(dimension) < shape_.at(dimension)))
return false;
192 return {
get_shape(), get_strides(), data_.data()};
196 return {
get_shape(), get_strides(), data_.data()};
200 [[nodiscard]]
constexpr Container&
get_container() noexcept {
return data_; }
203 [[nodiscard]]
constexpr const Container&
get_container() const noexcept {
return data_; }
205 template <
class Archive>
206 void serialize(Archive& archive) {
207 archive(shape_, data_);
212 [[nodiscard]]
static constexpr size_t get_size_from_shape(
const shape_type& shape)
noexcept {
214 for (
auto& it : shape) size *= it;
218 [[nodiscard]]
constexpr size_t get_index(
const index_type& index)
const noexcept {
220 size_t data_index = 0;
221 for (
size_t dimension = 0; dimension < Dimensions; ++dimension) {
222 data_index += stride * index.at(dimension);
223 stride *= shape_.at(dimension);
228 constexpr size_t check_range(
const index_type& index)
const {
229 using internal::array_as_string;
231 throw std::out_of_range(
232 std::string(
"Out of bounds lookup ") + array_as_string(index) +
" on matrix of shape " +
233 array_as_string(shape_) +
".");
235 return get_index(index);
238 [[nodiscard]]
constexpr index_type get_strides() const noexcept {
239 index_type strides{};
240 int stride =
static_cast<int>(
sizeof(T));
241 for (
size_t dimension = 0; dimension < Dimensions; ++dimension) {
242 strides.at(dimension) = stride;
243 stride *= shape_.at(dimension);
constexpr Matrix(const shape_type &shape)
Create a matrix of the given shape.
Definition matrix.hpp:150
constexpr reference at(const index_type &index)
Get the item at index, checking bounds.
Definition matrix.hpp:174
constexpr bool in_bounds(const index_type &index) const noexcept
Return true if index is within the bounds of this matrix.
Definition matrix.hpp:183
constexpr const_reference at(const index_type &index) const
Get the const item at index, checking bounds.
Definition matrix.hpp:177
constexpr const Container & get_container() const noexcept
Get the const flat container for this matrix.
Definition matrix.hpp:203
constexpr auto end() const noexcept
Return the iterator end.
Definition matrix.hpp:164
constexpr Container & get_container() noexcept
Get the flat container for this matrix.
Definition matrix.hpp:200
constexpr Matrix()=default
Default constructor.
constexpr reference operator[](const index_type &index) noexcept
Get the item at index.
Definition matrix.hpp:167
constexpr Matrix(const shape_type &shape, const T &fill_value)
Create a matrix of the given shape filled with a default value.
Definition matrix.hpp:153
constexpr const shape_type & get_shape() const noexcept
Return the shape of this matrix.
Definition matrix.hpp:180
constexpr auto begin() const noexcept
Return the iterator beginning.
Definition matrix.hpp:159
constexpr auto begin() noexcept
Return the iterator beginning.
Definition matrix.hpp:157
constexpr const_reference operator[](const index_type &index) const noexcept
Get the const item at index.
Definition matrix.hpp:170
constexpr auto end() noexcept
Return the iterator end.
Definition matrix.hpp:162
A view into a strided multi-dimensional array.
Definition matrix.hpp:65
constexpr reference at(const index_type &index)
Get the item at index, checking bounds.
Definition matrix.hpp:88
constexpr MatrixView(const shape_type &shape_xy, const stride_type &strides_xy, T *data) noexcept
Create a new multi-dimensional view.
Definition matrix.hpp:76
constexpr reference operator[](const index_type &index) noexcept
Get the item at index.
Definition matrix.hpp:80
constexpr const_reference at(const index_type &index) const
Get the const item at index, checking bounds.
Definition matrix.hpp:92
constexpr MatrixView()=default
Default constructor.
constexpr const_reference operator[](const index_type &index) const noexcept
Get the const item at index.
Definition matrix.hpp:84
constexpr bool in_bounds(const index_type &index) const noexcept
Return true if index is within the bounds of this matrix.
Definition matrix.hpp:97
The libtcod namespace.
Definition bresenham.hpp:157