.. _program_listing_file_libtcod_matrix.hpp: Program Listing for File matrix.hpp =================================== |exhale_lsh| :ref:`Return to documentation for file ` (``libtcod/matrix.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* BSD 3-Clause License * * Copyright © 2008-2026, Jice and the libtcod contributors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #pragma once #ifndef LIBTCOD_MATRIX_HPP_ #define LIBTCOD_MATRIX_HPP_ #include #include #include #include namespace tcod { namespace internal { template [[nodiscard]] static std::string array_as_string(const ArrayType& arr) { std::string result{"{"}; for (const auto& it : arr) { result += std::to_string(it); if (&it != &arr.back()) { result += ", "; } } result += "}"; return result; } } // namespace internal template class MatrixView { public: using size_type = int; // The int size of indexes. using shape_type = std::array; // The type used to store the matrixes shape. using stride_type = std::array; // The type used to store strides. using index_type = std::array; // The type used to index the container. using reference = T&; using const_reference = const T&; constexpr MatrixView() = default; constexpr MatrixView(const shape_type& shape_xy, const stride_type& strides_xy, T* data) noexcept : shape_xy_{shape_xy}, strides_xy_{strides_xy}, data_{reinterpret_cast(data)} {}; [[nodiscard]] constexpr reference operator[](const index_type& index) noexcept { return *reinterpret_cast(data_ + get_offset(index)); } [[nodiscard]] constexpr const_reference operator[](const index_type& index) const noexcept { return *reinterpret_cast(data_ + get_offset(index)); } [[nodiscard]] constexpr reference at(const index_type& index) { return *reinterpret_cast(data_ + check_range(index)); } [[nodiscard]] constexpr const_reference at(const index_type& index) const { return *reinterpret_cast(data_ + check_range(index)); } [[nodiscard]] constexpr bool in_bounds(const index_type& index) const noexcept { for (size_t dimension = 0; dimension < Dimensions; ++dimension) { if (!(0 <= index.at(dimension) && index.at(dimension) < shape_xy_.at(dimension))) return false; } return true; } private: // `unsigned char*` pointer which has the same const as `T`. using data_ptr = typename std::conditional::value, const unsigned char*, unsigned char*>::type; [[nodiscard]] constexpr size_t get_offset(const index_type& index) const noexcept { size_t data_index = 0; for (size_t dimension{0}; dimension < Dimensions; ++dimension) { data_index += strides_xy_.at(dimension) * index.at(dimension); } return data_index; } constexpr size_t check_range(const index_type& index) const { using internal::array_as_string; if (!in_bounds(index)) { throw std::out_of_range( std::string("Out of bounds lookup ") + array_as_string(index) + " on matrix of shape " + array_as_string(shape_xy_) + "."); } return get_offset(index); } shape_type shape_xy_; // The shape of this view. stride_type strides_xy_; // The strides of this view in bytes. data_ptr data_; // A pointer to the viewed memory. }; template > class Matrix { public: using size_type = int; // The int size of indexes. using shape_type = std::array; // The type used to measure the matrixes shape. using index_type = std::array; // The type used to index the container. using reference = typename Container::reference; using const_reference = typename Container::const_reference; constexpr Matrix() = default; constexpr explicit Matrix(const shape_type& shape) : shape_{shape}, data_(get_size_from_shape(shape)) {} constexpr Matrix(const shape_type& shape, const T& fill_value) : shape_{shape}, data_(get_size_from_shape(shape), fill_value) {} [[nodiscard]] constexpr auto begin() noexcept { return data_.begin(); } [[nodiscard]] constexpr auto begin() const noexcept { return data_.cbegin(); } [[nodiscard]] constexpr auto end() noexcept { return data_.end(); } [[nodiscard]] constexpr auto end() const noexcept { return data_.cend(); } [[nodiscard]] constexpr reference operator[](const index_type& index) noexcept { return data_[get_index(index)]; } [[nodiscard]] constexpr const_reference operator[](const index_type& index) const noexcept { return data_[get_index(index)]; } [[nodiscard]] constexpr reference at(const index_type& index) { return data_.at(check_range(index)); } [[nodiscard]] constexpr const_reference at(const index_type& index) const { return data_.at(check_range(index)); } [[nodiscard]] constexpr const shape_type& get_shape() const noexcept { return shape_; } [[nodiscard]] constexpr bool in_bounds(const index_type& index) const noexcept { for (size_t dimension = 0; dimension < Dimensions; ++dimension) { if (!(0 <= index.at(dimension) && index.at(dimension) < shape_.at(dimension))) return false; } return true; } [[nodiscard]] constexpr operator MatrixView() noexcept { return {get_shape(), get_strides(), data_.data()}; } [[nodiscard]] constexpr operator MatrixView() const noexcept { return {get_shape(), get_strides(), data_.data()}; } [[nodiscard]] constexpr Container& get_container() noexcept { return data_; } [[nodiscard]] constexpr const Container& get_container() const noexcept { return data_; } template void serialize(Archive& archive) { archive(shape_, data_); } private: [[nodiscard]] static constexpr size_t get_size_from_shape(const shape_type& shape) noexcept { size_t size = 1; for (auto& it : shape) size *= it; return size; } [[nodiscard]] constexpr size_t get_index(const index_type& index) const noexcept { size_t stride = 1; size_t data_index = 0; for (size_t dimension = 0; dimension < Dimensions; ++dimension) { data_index += stride * index.at(dimension); stride *= shape_.at(dimension); } return data_index; } constexpr size_t check_range(const index_type& index) const { using internal::array_as_string; if (!in_bounds(index)) { throw std::out_of_range( std::string("Out of bounds lookup ") + array_as_string(index) + " on matrix of shape " + array_as_string(shape_) + "."); } return get_index(index); } [[nodiscard]] constexpr index_type get_strides() const noexcept { index_type strides{}; int stride = static_cast(sizeof(T)); for (size_t dimension = 0; dimension < Dimensions; ++dimension) { strides.at(dimension) = stride; stride *= shape_.at(dimension); } return strides; } shape_type shape_; Container data_; }; } // namespace tcod #endif // LIBTCOD_MATRIX_HPP_