#ifndef CPP_UTILITIES_MULTI_ARRAY_H #define CPP_UTILITIES_MULTI_ARRAY_H #include #include #include namespace CppUtilities { /// \cond namespace Detail { template struct DimensionsHelper { static std::size_t requiredSize(const Tuple &dimensionSizes) { return DimensionsHelper::requiredSize(dimensionSizes) * static_cast(std::get(dimensionSizes)); } static std::size_t offset(const Tuple &dimensions, const Tuple &indices, std::size_t factor) { return DimensionsHelper::offset(dimensions, indices, factor * static_cast(std::get(dimensions))) + (factor * static_cast(std::get(indices))); } }; template struct DimensionsHelper { static std::size_t requiredSize(const Tuple &dimensionSizes) { return static_cast(std::get<0>(dimensionSizes)); } static std::size_t offset(const Tuple &, const Tuple &indices, std::size_t factor) { return factor * static_cast(std::get<0>(indices)); } }; } // namespace Detail /// \endcond /// \brief The VectorBasedMultiArray struct allows using an std::vector with custom allocator as underlying container for the MultiArray class. template struct VectorBasedMultiArray { template using Type = std::vector; template static constexpr Type init(std::size_t requiredSize) { return Type(requiredSize); } }; /// \brief The VectorBasedMultiArray struct allows using an std::vector as underlying container for the MultiArray class. template <> struct VectorBasedMultiArray { template using Type = std::vector>; template static constexpr Type init(std::size_t requiredSize) { return Type(requiredSize); } }; /// \brief The ArrayBasedMultiArray struct allows using a fixed size array as underlying container for the MultiArray class. template struct ArrayBasedMultiArray { template using Type = std::array; template static constexpr Type init(std::size_t) { return Type(); } }; /// \brief The NoneOwningMultiArray struct allows using a caller-managed buffer array as underlying container for the MultiArray class. struct NoneOwningMultiArray { template using Type = T *; template static constexpr Type init(std::size_t) { return nullptr; } }; /// \brief The MultiArray class provides an *N*-dimensional array. /// \tparam T Specifies the type of the data the MultiArray is supposed to contain. /// \tparam UnderlyingContainer Specifies the type of the underlying container to use. /// \tparam Dimentions Specifies the types used to store the limit/size of the dimentions. Must be safely castable to std::size_t. template class MultiArray { public: MultiArray(Dimensions... dimensionSizes); std::size_t totalSize() const; static constexpr std::size_t dimensionCount(); template std::size_t dimensionSize() const; T &at(Dimensions... indices); const T &at(Dimensions... indices) const; T *data(); const T *data() const; typename UnderlyingContainer::template Type &buffer(); private: using HelperType = Detail::DimensionsHelper, dimensionCount()>; const std::tuple m_dims; const std::size_t m_size; typename UnderlyingContainer::template Type m_buff; }; /// \brief Constructs a new *N*-dimensional array. The sizes for the dimensions are passed as arguments and must be greather than zero. /// \remarks The number of dimensions *N* is deduced from the number of \a dimensionSizes. /// \sa makeMultiArray(), makeFixedSizeMultiArray() and makeNoneOwningMultiArray() for more convenient construction template MultiArray::MultiArray(Dimensions... dimensionSizes) : m_dims(std::make_tuple(dimensionSizes...)) , m_size(HelperType::requiredSize(m_dims)) , m_buff(UnderlyingContainer::template init(m_size)) { } /// \brief Returns the total number of elements. template std::size_t MultiArray::totalSize() const { return m_size; } /// \brief Returns the number of dimensions for that type of array. template constexpr std::size_t MultiArray::dimensionCount() { return std::tuple_size>::value; } /// \brief Returns the number of elements in the specified dimension. template template std::size_t MultiArray::dimensionSize() const { return static_cast(std::get(m_dims)); } /// \brief Returns the element at the position specified via \a indices. /// \remarks The number of \a indices must equal dimensionCount(). template T &MultiArray::at(Dimensions... indices) { return m_buff[HelperType::offset(m_dims, std::make_tuple(indices...), 1)]; } /// \brief Returns the element at the position specified via \a indices. /// \remarks The number of \a indices must equal dimensionCount(). template const T &MultiArray::at(Dimensions... indices) const { return m_buff[HelperType::offset(m_dims, std::make_tuple(indices...), 1)]; } /// \brief Returns a pointer to the raw data. /// \remarks Intended for debugging purposes only. The underlying data structure might change in future versions. template T *MultiArray::data() { return m_buff.data(); } /// \brief Returns a pointer to the raw data. /// \remarks Intended for debugging purposes only. The underlying data structure might change in future versions. template const T *MultiArray::data() const { return m_buff.data(); } /// \brief Allows accessing the underlying buffer directly. /// \remarks Assign the custom buffer using this method when using NoneOwningMultiArray as UnderlyingContainer. template typename UnderlyingContainer::template Type &MultiArray::buffer() { return m_buff; } /// \brief Constructs a new *N*-dimensional array using an std::vector with std::allocator as underlying container. /// The sizes for the dimensions are passed as arguments. /// \remarks The number of dimensions *N* is deduced from the number of \a dimensionSizes. template inline auto makeMultiArray(DimensionSizes... dimensionSizes) { return MultiArray, DimensionSizes...>(dimensionSizes...); } /// \brief Constructs a new *N*-dimensional array using a fixed size array as underlying container. /// The sizes for the dimensions are passed as arguments. /// \remarks The number of dimensions *N* is deduced from the number of \a dimensionSizes. template inline auto makeFixedSizeMultiArray(DimensionSizes... dimensionSizes) { return MultiArray, DimensionSizes...>(dimensionSizes...); } /// \brief Constructs a new *N*-dimensional array using a caller-managed buffer as underlying container. /// The sizes for the dimensions are passed as arguments. /// \remarks The number of dimensions *N* is deduced from the number of \a dimensionSizes. template inline auto makeNoneOwningMultiArray(DimensionSizes... dimensionSizes) { return MultiArray(dimensionSizes...); } } // namespace CppUtilities #endif // CPP_UTILITIES_MULTI_ARRAY_H