Add auto-expanding in all directions util::spatial_array
This commit is contained in:
parent
dc1b86fa75
commit
649c051b61
1 changed files with 174 additions and 0 deletions
174
libs/util/include/psemek/util/spatial_array.hpp
Normal file
174
libs/util/include/psemek/util/spatial_array.hpp
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/util/array.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace psemek::util
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T, std::size_t N, typename Index = std::int32_t>
|
||||||
|
struct spatial_array
|
||||||
|
{
|
||||||
|
spatial_array();
|
||||||
|
|
||||||
|
using index_type = Index;
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
T & get(Ix ... index);
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
T * get_if(Ix ... index);
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
T const * get_if(Ix ... index) const;
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
T const & at(Ix ... index) const;
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
bool contains(Ix ... index) const;
|
||||||
|
|
||||||
|
template <typename ... Ix>
|
||||||
|
void expand(Ix ... index);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Index origin_[N];
|
||||||
|
array<T, N> array_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N, typename Index>
|
||||||
|
spatial_array<T, N, Index>::spatial_array()
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
|
origin_[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
T & spatial_array<T, N, Index>::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 <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
T * spatial_array<T, N, Index>::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 <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
T const * spatial_array<T, N, Index>::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 <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
T const & spatial_array<T, N, Index>::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<Index>(size[i]))
|
||||||
|
throw std::runtime_error("element out of range");
|
||||||
|
ix[i] -= origin_[i];
|
||||||
|
}
|
||||||
|
return array_(ix);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
bool spatial_array<T, N, Index>::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<Index>(size[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N, typename Index>
|
||||||
|
template <typename ... Ix>
|
||||||
|
void spatial_array<T, N, Index>::expand(Ix ... index)
|
||||||
|
{
|
||||||
|
Index ix[N] {index...};
|
||||||
|
|
||||||
|
if (array_.empty())
|
||||||
|
{
|
||||||
|
std::array<std::size_t, N> 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<std::size_t, N> 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<Index>(new_size[i]))
|
||||||
|
new_size[i] += new_size[i];
|
||||||
|
|
||||||
|
while (ix[i] < new_origin[i])
|
||||||
|
{
|
||||||
|
new_origin[i] -= static_cast<Index>(new_size[i]);
|
||||||
|
new_size[i] += new_size[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array<T, N> new_array(new_size);
|
||||||
|
for (auto idx : array_.indices())
|
||||||
|
{
|
||||||
|
std::array<std::size_t, N> new_idx;
|
||||||
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
|
new_idx[i] = static_cast<Index>(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 <typename T, std::size_t N, typename Index>
|
||||||
|
void spatial_array<T, N, Index>::clear()
|
||||||
|
{
|
||||||
|
array_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue