Ver código fonte

Add narray_view class, similar to std::span for n-dimensional arrays.

pull/1/head
Sam Hocevar 4 anos atrás
pai
commit
cffee479d3
1 arquivos alterados com 106 adições e 53 exclusões
  1. +106
    -53
      include/lol/private/base/narray.h

+ 106
- 53
include/lol/private/base/narray.h Ver arquivo

@@ -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/vector> // lol::vec_t
#include <vector> // std::vector
#include <utility> // std::index_sequence

namespace lol
{

template<typename T, size_t N>
class [[nodiscard]] narray
template<typename T, size_t N, typename container_type>
class [[nodiscard]] narray_base
{
public:
typedef T value_type;

inline narray() = default;
inline ~narray() = default;

// Construct array with args: size1, size2, ..., sizen
template<typename... I> 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<int, N> const &sizes)
// Return sizes of each dimension
inline vec_t<int, N> sizes() const
{
resize(sizes);
return vec_t<int, N>(m_sizes);
}

// Empty array
inline void clear() { resize(vec_t<size_t, N>(0)); }
// Size in number of elements and in bytes
inline size_t size() const { return size_helper(std::make_index_sequence<N>{}); }
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<typename... I>
inline value_type &operator()(I... indices)
{
static_assert(N == sizeof...(I));
return m_data[offset(indices...)];
return data()[offset(indices...)];
}

template<typename... I>
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<int, N> const &indices)
{
return m_data[offset_helper(indices, std::make_index_sequence<N>{})];
return data()[offset_helper(indices, std::make_index_sequence<N>{})];
}

inline value_type const &operator()(vec_t<int, N> const &indices) const
{
return m_data[offset_helper(indices, std::make_index_sequence<N>{})];
return data()[offset_helper(indices, std::make_index_sequence<N>{})];
}

// Resize array with a list of sizes (size1, size2, ..., sizen)
template<typename... I>
inline void resize(I... sizes)
protected:
template <size_t... I>
inline size_t size_helper(std::index_sequence<I...>) 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<int, N> const &sizes)
template<typename... I>
inline size_t offset(size_t i, I... indices) const
{
resize_helper(sizes, std::make_index_sequence<N>{});
if constexpr(sizeof...(I) > 0)
i += m_sizes[N - sizeof...(I) - 1] * offset(indices...);
return i;
}

// Return sizes of each dimension
inline vec_t<int, N> sizes() const
template <size_t... I>
inline size_t offset_helper(vec_t<int, N> const &sizes, std::index_sequence<I...>) const
{
return vec_t<int, N>(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<size_t, N> m_sizes { 0 };

private:
template<typename... I> 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<container_type *>(this)->data();
}

template <std::size_t... I>
size_t offset_helper(vec_t<int, N> const &sizes, std::index_sequence<I...>) const
inline value_type const *data() const
{
return offset(size_t(sizes[I])...);
return static_cast<container_type const *>(this)->data();
}
};


template<typename T, size_t N>
class [[nodiscard]] narray : public narray_base<T, N, narray<T, N>>
{
public:
using value_type = T;

template <std::size_t... I>
void resize_helper(vec_t<int, N> const &sizes, std::index_sequence<I...>)
inline narray() = default;
inline ~narray() = default;

// Construct array with args: size1, size2, ..., sizen
template<typename... I> inline narray(I... sizes)
{
resize(sizes[I]...);
static_assert(N == sizeof...(I));
resize(sizes...);
}

vec_t<size_t, N> m_sizes { 0 };
// Construct array with integer vec_t arg:
inline narray(vec_t<int, N> const &sizes)
{
resize(sizes);
}

// Empty array
inline void clear() { resize(vec_t<size_t, N>(0)); }

// Resize array with a list of sizes (size1, size2, ..., sizen)
template<typename... I>
inline void resize(I... sizes)
{
static_assert(N == sizeof...(I));
this->m_sizes = { size_t(sizes)... };
m_data.resize(this->size());
}

template<typename U>
inline void resize(vec_t<U, N> const &sizes)
{
this->m_sizes = vec_t<size_t, N>(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<T> m_data;
};

template<typename T> using array2d = narray<T, 2>;
template<typename T> using array3d = narray<T, 3>;

template<typename T, size_t N>
class [[nodiscard]] narray_view : public narray_base<T, N, narray_view<T, N>>
{
public:
using value_type = T;

template<typename U>
inline narray_view(narray_base<T, N, U> &other)
: m_data(&other[0])
{
this->m_sizes = vec_t<size_t, N>(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<typename T> using array2d_view = narray_view<T, 2>;
template<typename T> using array3d_view = narray_view<T, 3>;

} // namespace lol


Carregando…
Cancelar
Salvar