From cffee479d3e09c5507db24f1467beb858f08f1dc Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 25 Jun 2020 13:01:37 +0200 Subject: [PATCH] Add narray_view class, similar to std::span for n-dimensional arrays. --- include/lol/private/base/narray.h | 159 ++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 53 deletions(-) diff --git a/include/lol/private/base/narray.h b/include/lol/private/base/narray.h index 7f45b923..eebe06d6 100644 --- a/include/lol/private/base/narray.h +++ b/include/lol/private/base/narray.h @@ -15,127 +15,180 @@ // // The narray class // ———————————————— -// An N-dimensional row-major array template class +// An n-dimensional row-major array template class // #include // lol::vec_t #include // std::vector +#include // std::index_sequence namespace lol { -template -class [[nodiscard]] narray +template +class [[nodiscard]] narray_base { public: - typedef T value_type; - - inline narray() = default; - inline ~narray() = default; - - // Construct array with args: size1, size2, ..., sizen - template inline narray(I... sizes) - { - static_assert(N == sizeof...(I)); - resize(sizes...); - } + using value_type = T; - // Construct array with integer vec_t arg: - inline narray(vec_t const &sizes) + // Return sizes of each dimension + inline vec_t sizes() const { - resize(sizes); + return vec_t(m_sizes); } - // Empty array - inline void clear() { resize(vec_t(0)); } + // Size in number of elements and in bytes + inline size_t size() const { return size_helper(std::make_index_sequence{}); } + inline size_t bytes() const { return size() * sizeof(value_type); } - // Access element i + // Access element i in row-major fashion inline value_type &operator[](size_t i) { - return m_data[i]; + return data()[i]; } inline value_type const &operator[](size_t i) const { - return m_data[i]; + return data()[i]; } - // Access element (i, j, .., z) in row-major fashion + // Access element (i, j, .., z) template inline value_type &operator()(I... indices) { static_assert(N == sizeof...(I)); - return m_data[offset(indices...)]; + return data()[offset(indices...)]; } template inline value_type const &operator()(I... indices) const { static_assert(N == sizeof...(I)); - return m_data[offset(indices...)]; + return data()[offset(indices...)]; } inline value_type &operator()(vec_t const &indices) { - return m_data[offset_helper(indices, std::make_index_sequence{})]; + return data()[offset_helper(indices, std::make_index_sequence{})]; } inline value_type const &operator()(vec_t const &indices) const { - return m_data[offset_helper(indices, std::make_index_sequence{})]; + return data()[offset_helper(indices, std::make_index_sequence{})]; } - // Resize array with a list of sizes (size1, size2, ..., sizen) - template - inline void resize(I... sizes) +protected: + template + inline size_t size_helper(std::index_sequence) const { - static_assert(N == sizeof...(I)); - m_data.resize((size_t(sizes) * ... * 1)); - m_sizes = { size_t(sizes)... }; + return (size_t(m_sizes[I]) * ... * 1); } - inline void resize(vec_t const &sizes) + template + inline size_t offset(size_t i, I... indices) const { - resize_helper(sizes, std::make_index_sequence{}); + if constexpr(sizeof...(I) > 0) + i += m_sizes[N - sizeof...(I) - 1] * offset(indices...); + return i; } - // Return sizes of each dimension - inline vec_t sizes() const + template + inline size_t offset_helper(vec_t const &sizes, std::index_sequence) const { - return vec_t(this->m_sizes); + return offset(size_t(sizes[I])...); } - inline value_type *data() { return m_data.data(); } - inline value_type const *data() const { return m_data.data(); } - inline size_t size() const { return m_data.size(); } - inline size_t bytes() const { return size() * sizeof(value_type); } + vec_t m_sizes { 0 }; private: - template size_t offset(size_t i, I... indices) const + // Use CRTP to access data() from the child class + inline value_type *data() { - if constexpr(sizeof...(I) > 0) - i += m_sizes[N - sizeof...(I) - 1] * offset(indices...); - return i; + return static_cast(this)->data(); } - template - size_t offset_helper(vec_t const &sizes, std::index_sequence) const + inline value_type const *data() const { - return offset(size_t(sizes[I])...); + return static_cast(this)->data(); } +}; + + +template +class [[nodiscard]] narray : public narray_base> +{ +public: + using value_type = T; - template - void resize_helper(vec_t const &sizes, std::index_sequence) + inline narray() = default; + inline ~narray() = default; + + // Construct array with args: size1, size2, ..., sizen + template inline narray(I... sizes) { - resize(sizes[I]...); + static_assert(N == sizeof...(I)); + resize(sizes...); } - vec_t m_sizes { 0 }; + // Construct array with integer vec_t arg: + inline narray(vec_t const &sizes) + { + resize(sizes); + } + + // Empty array + inline void clear() { resize(vec_t(0)); } + + // Resize array with a list of sizes (size1, size2, ..., sizen) + template + inline void resize(I... sizes) + { + static_assert(N == sizeof...(I)); + this->m_sizes = { size_t(sizes)... }; + m_data.resize(this->size()); + } + + template + inline void resize(vec_t const &sizes) + { + this->m_sizes = vec_t(sizes); + m_data.resize(this->size()); + } + + // Access data directly + inline value_type *data() { return m_data.data(); } + inline value_type const *data() const { return m_data.data(); } + +private: std::vector m_data; }; template using array2d = narray; template using array3d = narray; +template +class [[nodiscard]] narray_view : public narray_base> +{ +public: + using value_type = T; + + template + inline narray_view(narray_base &other) + : m_data(&other[0]) + { + this->m_sizes = vec_t(other.sizes()); + } + + // Access data directly + inline value_type *data() { return m_data; } + inline value_type const *data() const { return m_data; } + +private: + T *m_data; +}; + +template using array2d_view = narray_view; +template using array3d_view = narray_view; + } // namespace lol