/*+ ARES/HADES/BORG Package -- ./libLSS/tools/nary_arrays.hpp Copyright (C) 2014-2020 Guilhem Lavaux Copyright (C) 2009-2020 Jens Jasche Additional contributions from: Guilhem Lavaux (2023) +*/ #ifndef __LIBLSS_NARY_ARRAYS_HPP #define __LIBLSS_NARY_ARRAYS_HPP #include #include #include "libLSS/tools/array_concepts.hpp" namespace LibLSS { struct ArrayTuple_base { typedef boost::multi_array_types::size_type size_type; typedef boost::multi_array_types::index index; }; template struct ArrayTuple; template struct ArrayTuple: ArrayTuple_base { enum { NumDims = Ndims }; enum { arity = std::tuple_size::value }; static constexpr bool Shaped = false; typedef boost::array subindex; typedef boost::array subshape; typedef TupleT Tuple; typedef ReturnElement element; const Tuple tuple; inline ArrayTuple(Tuple const & t) : tuple(t) {} inline bool vectorizable() const { return false; } }; template struct ArrayTuple: ArrayTuple_base { enum { NumDims = Ndims }; enum { arity = std::tuple_size::value }; static constexpr bool Shaped = true; typedef TupleT Tuple; typedef ReturnElement element; const Tuple tuple; inline ArrayTuple(Tuple const & t) : tuple(t) {} inline const size_type *shape() const { return std::get<0>(tuple).shape(); } inline const index *index_bases() const { return std::get<0>(tuple).index_bases(); } inline size_type num_elements() const { return std::get<0>(tuple).num_elements(); } inline bool vectorizable() const { return false; } }; template struct ArrayNullTuple: ArrayTuple_base { enum { NumDims = Ndims }; enum { arity = arity_par }; typedef ReturnElement element; static constexpr bool Shaped = false; // Special no-op tuple struct Tuple { // Type to access i-th position of the given index. template struct TupleElement { template inline auto operator()(const Index& j) const-> decltype(j[i]) { return j[i]; } }; }; // Implicit accessor const Tuple tuple; inline ArrayNullTuple() : tuple() {} }; template struct ArrayNullTupleExtent: ArrayTuple_base { enum { NumDims = Ndims }; enum { arity = arity_par }; typedef ReturnElement element; static constexpr bool Shaped = true; typedef boost::array subindex; typedef boost::array subshape; // Special no-op tuple struct Tuple { // Type to access i-th position of the given index. template struct TupleElement { template auto operator()(const Index& j) const -> decltype(j[i]) { return j[i]; } }; }; // Implicit accessor const Tuple tuple; subindex indexes; subshape shapes; typedef boost::multi_array_types::extent_range extent_range; size_t total_elts; // ExtentGen is a boost::extents like type template ArrayNullTupleExtent(const ExtentType& f_extents) : tuple() { using std::transform; transform(f_extents.ranges_.begin(), f_extents.ranges_.end(), indexes.begin(), boost::mem_fun_ref(&extent_range::start)); transform(f_extents.ranges_.begin(), f_extents.ranges_.end(), shapes.begin(), boost::mem_fun_ref(&extent_range::size)); size_t _total = 1; std::for_each(shapes.begin(), shapes.end(), [&_total](size_type s) { _total *= s; }); total_elts = _total; } template ArrayNullTupleExtent(const ShapeList& _shapes, const IndexList& _indexbase) : tuple() { using std::transform; std::copy(_indexbase.begin(), _indexbase.end(), indexes.begin()); std::copy(_shapes.begin(), _shapes.end(), shapes.begin()); size_t _total = 1; std::for_each(shapes.begin(), shapes.end(), [&_total](size_type s) { _total *= s; }); total_elts = _total; } const size_type *shape() const { return &shapes[0];} const index *index_bases() const { return &indexes[0]; } size_type num_elements() const { return 0; } }; // Special cases for which the tuple of array is degenerate to the empty set.\ // The arraytuple is always not shaped then. template struct ArrayTuple,Shaped>: ArrayTuple_base, ArrayNullTuple { }; template struct ArrayTuple const,Shaped>: ArrayTuple_base, ArrayNullTuple { }; // Detect whether a type support shapes or not // By default no. template struct DetectShaped { static constexpr bool Shaped = false; }; template struct DetectShaped>::type> { static constexpr bool Shaped = T::Shaped; }; template struct DetectShaped>::type> { static constexpr bool Shaped = true; }; template struct DetectShaped::value && !array_concepts::is_array_view::value && !array_concepts::is_array_storage::value>::type> { static constexpr bool Shaped = true; }; template struct DetectShaped>::type> { static constexpr bool Shaped = true; }; } // Populate std with some additional getters to support NullTuples namespace std { template inline typename NullTuple::template TupleElement get(NullTuple const& t) throw() { return typename NullTuple::template TupleElement(); } } // Terminate the definition of a lazy/virtual array evaluation namespace LibLSS { namespace details { template struct array_apply_tuple { template static inline typename ArrayTuple::element apply(Operation&& op, ArrayTuple& at, Index i, Args&&... args) { return array_apply_tuple::apply(op, at, i, std::get(at.tuple)(i), args...); } }; template<> struct array_apply_tuple<0> { template static inline typename ArrayTuple::element apply(Operation&& op, ArrayTuple& at, Index i, Args&&... args) { return op(args...); } }; template inline typename ArrayTuple::element apply_op(Operation&& op, ArrayTuple& t, Index i ) { return array_apply_tuple::apply(op, t, i); }; }; } #endif