Support indexing util::array with arbitrary array-like types

This commit is contained in:
Nikita Lisitsa 2021-10-30 22:04:50 +03:00
parent 8571bc9c6d
commit 249ca33aab

View file

@ -9,6 +9,38 @@
namespace psemek::util
{
namespace detail
{
template <typename T, typename = void>
struct is_array : std::false_type {};
template <typename T>
struct is_array<T, std::void_t<decltype(std::declval<T&>()[0])>>
: std::true_type
{};
template <typename T>
constexpr bool is_array_v = is_array<T>::value;
template <typename ... Ts>
struct is_index;
template <>
struct is_index<>
: std::false_type
{};
template <typename T, typename ... Ts>
struct is_index<T, Ts...>
: std::bool_constant<!is_array_v<T>>
{};
template <typename ... Ts>
constexpr bool is_index_v = is_index<Ts...>::value;
}
template <typename T, std::size_t N>
struct array
{
@ -62,14 +94,27 @@ namespace psemek::util
return dims_[2];
}
T & operator()(dims_type const & index);
T const & operator()(dims_type const & index) const;
template <typename Index>
std::enable_if_t<detail::is_array_v<Index>, T &>
operator()(Index const & index);
template <typename Index>
std::enable_if_t<detail::is_array_v<Index>, T const &>
operator()(Index const & index) const;
template <typename ... Ixs>
T & operator()(Ixs ... ixs);
std::enable_if_t<detail::is_index_v<Ixs...>, T &>
operator()(Ixs ... ixs);
template <typename ... Ixs>
T const & operator()(Ixs ... ixs) const;
std::enable_if_t<detail::is_index_v<Ixs...>, T const &>
operator()(Ixs ... ixs) const;
template <typename I>
T & operator()(std::initializer_list<I> const & index);
template <typename I>
T const & operator()(std::initializer_list<I> const & index) const;
array copy() const;
@ -127,8 +172,8 @@ namespace psemek::util
return false;
}
template <std::size_t N>
std::size_t index(std::array<std::size_t, N> const & i, std::array<std::size_t, N> const & dims)
template <std::size_t N, typename Index>
std::size_t index(Index const & i, std::array<std::size_t, N> const & dims)
{
std::size_t r = 0;
for (std::size_t d = N; d --> 0;)
@ -278,20 +323,25 @@ namespace psemek::util
}
template <typename T, std::size_t N>
T & array<T, N>::operator()(dims_type const & index)
template <typename Index>
std::enable_if_t<detail::is_array_v<Index>, T &>
array<T, N>::operator()(Index const & index)
{
return data_[detail::index(index, dims_)];
}
template <typename T, std::size_t N>
T const & array<T, N>::operator()(dims_type const & index) const
template <typename Index>
std::enable_if_t<detail::is_array_v<Index>, T const &>
array<T, N>::operator()(Index const & index) const
{
return data_[detail::index(index, dims_)];
}
template <typename T, std::size_t N>
template <typename ... Ixs>
T & array<T, N>::operator()(Ixs ... ixs)
std::enable_if_t<detail::is_index_v<Ixs...>, T &>
array<T, N>::operator()(Ixs ... ixs)
{
dims_type dims{static_cast<std::size_t>(ixs)...};
return (*this)(dims);
@ -299,12 +349,27 @@ namespace psemek::util
template <typename T, std::size_t N>
template <typename ... Ixs>
T const & array<T, N>::operator()(Ixs ... ixs) const
std::enable_if_t<detail::is_index_v<Ixs...>, T const &>
array<T, N>::operator()(Ixs ... ixs) const
{
dims_type dims{static_cast<std::size_t>(ixs)...};
return (*this)(dims);
}
template <typename T, std::size_t N>
template <typename I>
T & array<T, N>::operator()(std::initializer_list<I> const & index)
{
return data_[detail::index(std::data(index), dims_)];
}
template <typename T, std::size_t N>
template <typename I>
T const & array<T, N>::operator()(std::initializer_list<I> const & index) const
{
return data_[detail::index(std::data(index), dims_)];
}
template <typename T, std::size_t N>
array<T, N> array<T, N>::copy() const
{