From 649c051b61e3e429fc6b0e4cabc0c393ce9fd861 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 5 Aug 2022 15:54:58 +0300 Subject: [PATCH] Add auto-expanding in all directions util::spatial_array --- .../include/psemek/util/spatial_array.hpp | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 libs/util/include/psemek/util/spatial_array.hpp diff --git a/libs/util/include/psemek/util/spatial_array.hpp b/libs/util/include/psemek/util/spatial_array.hpp new file mode 100644 index 00000000..c0b60c1a --- /dev/null +++ b/libs/util/include/psemek/util/spatial_array.hpp @@ -0,0 +1,174 @@ +#pragma once + +#include + +#include + +namespace psemek::util +{ + + template + struct spatial_array + { + spatial_array(); + + using index_type = Index; + + template + T & get(Ix ... index); + + template + T * get_if(Ix ... index); + + template + T const * get_if(Ix ... index) const; + + template + T const & at(Ix ... index) const; + + template + bool contains(Ix ... index) const; + + template + void expand(Ix ... index); + + void clear(); + + private: + Index origin_[N]; + array array_; + }; + + template + spatial_array::spatial_array() + { + for (std::size_t i = 0; i < N; ++i) + origin_[i] = 0; + } + + template + template + T & spatial_array::get(Ix ... index) + { + if (!contains(index...)) + expand(index...); + + Index ix[N] {index...}; + for (std::size_t i = 0; i < N; ++i) + ix[i] -= origin_[i]; + return array_(ix); + } + + template + template + T * spatial_array::get_if(Ix ... index) + { + if (!contains(index...)) + return nullptr; + + Index ix[N] {index...}; + for (std::size_t i = 0; i < N; ++i) + ix[i] -= origin_[i]; + return &array_(ix); + } + + template + template + T const * spatial_array::get_if(Ix ... index) const + { + if (!contains(index...)) + return nullptr; + + Index ix[N] {index...}; + for (std::size_t i = 0; i < N; ++i) + ix[i] -= origin_[i]; + return &array_(ix); + } + + template + template + T const & spatial_array::at(Ix ... index) const + { + auto const size = array_.dims(); + Index ix[N] {index...}; + for (std::size_t i = 0; i < N; ++i) + { + if (ix[i] < origin_[i] || ix[i] >= origin_[i] + static_cast(size[i])) + throw std::runtime_error("element out of range"); + ix[i] -= origin_[i]; + } + return array_(ix); + } + + template + template + bool spatial_array::contains(Ix ... index) const + { + auto const size = array_.dims(); + Index ix[N] {index...}; + for (std::size_t i = 0; i < N; ++i) + if (ix[i] < origin_[i] || ix[i] >= origin_[i] + static_cast(size[i])) + return false; + return true; + } + + template + template + void spatial_array::expand(Ix ... index) + { + Index ix[N] {index...}; + + if (array_.empty()) + { + std::array size; + + for (std::size_t i = 0; i < N; ++i) + { + origin_[i] = ix[i]; + size[i] = 1; + } + + array_.resize(size); + return; + } + + Index new_origin[N]; + std::array new_size = array_.dims(); + + for (std::size_t i = 0; i < N; ++i) + new_origin[i] = origin_[i]; + + for (std::size_t i = 0; i < N; ++i) + { + while (ix[i] >= new_origin[i] + static_cast(new_size[i])) + new_size[i] += new_size[i]; + + while (ix[i] < new_origin[i]) + { + new_origin[i] -= static_cast(new_size[i]); + new_size[i] += new_size[i]; + } + } + + array new_array(new_size); + for (auto idx : array_.indices()) + { + std::array new_idx; + for (std::size_t i = 0; i < N; ++i) + new_idx[i] = static_cast(idx[i]) + origin_[i] - new_origin[i]; + new_array(new_idx) = std::move(array_(idx)); + } + + array_ = std::move(new_array); + + for (std::size_t i = 0; i < N; ++i) + origin_[i] = new_origin[i]; + } + + template + void spatial_array::clear() + { + array_.clear(); + } + +}