// // rarray - Runtime arrays: template classes for pointer-based, // runtime, reference counted, multi-dimensional // arrays. Documentation in rarraydoc.pdf // // Copyright (c) 2013-2026 Ramses van Zon // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #ifndef RARRAY_H_ #define RARRAY_H_ #include #include #include #include #include #include #include #include #include #include #if __cplusplus >= 201103L #include #include #include #include #include #endif #if __cplusplus >= 202002L #if __has_include() #include #endif #endif #if __cplusplus >= 201103L #include #include #include #define RA_VERSION "v2.8.2" #define RA_VERSION_NUMBER 2008002 #ifdef RA_BOUNDSCHECK #define RA_CHECKORSAY(a, b) if (not(a)) throw std::out_of_range(std::string(b) + " in function " + std::string(__PRETTY_FUNCTION__) + " (rarray:" + std::to_string(__LINE__) + ")") #define RA_noboundscheck false #else #define RA_CHECKORSAY(a, b) #define RA_noboundscheck true #endif #if !defined(RA_FORCE_inline) # if defined(_MSC_VER) # if _MSC_VER >= 1900 # define RA_FORCE_inline [[msvc::forceinline]] inline # define RA_FORCE_static_inline [[msvc::forceinline]] static inline # else # define RA_FORCE_inline __forceinline inline # define RA_FORCE_static_inline __forceinline static inline # endif # elif defined(__INTEL_COMPILER) # define RA_FORCE_inline __forceinline inline # define RA_FORCE_static_inline __forceinline static inline # elif defined(__clang__) # if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) # define RA_FORCE_inline __attribute__((always_inline)) inline # define RA_FORCE_static_inline __attribute__((always_inline)) static inline # else # define RA_FORCE_inline [[gnu::always_inline]] inline # define RA_FORCE_static_inline [[gnu::always_inline]] static inline # endif # elif defined(__GNUC__) # if __GNUC__ < 4 || (GNU_C == 4 && __GNUC_MINOR < 8) # define RA_FORCE_inline __attribute__((always_inline)) inline # define RA_FORCE_static_inline __attribute__((always_inline)) static inline # else # define RA_FORCE_inline [[gnu::always_inline]] inline # define RA_FORCE_static_inline [[gnu::always_inline]] static inline # endif # else # define RA_FORCE_inline inline # define RA_FORCE_static_inline static inline # endif #endif namespace ra { using size_type = std::ptrdiff_t; using index_type = std::ptrdiff_t; using rank_type = int; } // namespace ra namespace ra { namespace detail { template class shared_buffer { public: using size_type = ::ra::size_type; RA_FORCE_inline shared_buffer() noexcept { uninit(); } RA_FORCE_inline explicit shared_buffer(size_type asize) : data_(nullptr), orig_(nullptr), size_(0), refs_(nullptr) { using Tnoconst = typename std::remove_const::type; auto to_be_data = std::unique_ptr(new Tnoconst[asize]); refs_ = new std::atomic(1); data_ = to_be_data.release(); orig_ = data_; size_ = asize; } RA_FORCE_inline shared_buffer(size_type asize, T* adata) noexcept(RA_noboundscheck) : data_(adata), orig_(nullptr), size_(asize), refs_(nullptr) { RA_CHECKORSAY(adata, "nullptr given as data"); } RA_FORCE_inline shared_buffer(const shared_buffer& other) noexcept : data_(other.data_), orig_(other.orig_), size_(other.size_), refs_(other.refs_) { incref(); } RA_FORCE_inline shared_buffer(shared_buffer&& from) noexcept : data_(from.data_), orig_(from.orig_), size_(from.size_), refs_(from.refs_) { from.uninit(); } RA_FORCE_inline auto operator=(const shared_buffer& other) noexcept -> shared_buffer& { if (this != &other) { decref(); data_ = other.data_; orig_ = other.orig_; size_ = other.size_; refs_ = other.refs_; incref(); } return *this; } RA_FORCE_inline auto operator=(shared_buffer&& from) noexcept -> shared_buffer& { decref(); data_ = from.data_; orig_ = from.orig_; size_ = from.size_; refs_ = from.refs_; from.uninit(); return *this; } RA_FORCE_inline ~shared_buffer() noexcept { decref(); } RA_FORCE_inline auto operator[](size_type index) const noexcept(RA_noboundscheck) -> const T& { RA_CHECKORSAY(index >= 0 && index < size(), "element not in buffer"); return data_[index]; } RA_FORCE_inline auto operator[](size_type index) noexcept(RA_noboundscheck) -> T& { RA_CHECKORSAY(index >= 0 && index < size(), "element not in buffer"); return data_[index]; } RA_FORCE_inline auto at(size_type index) const -> const T& { if (index < 0 || index >= size_) { throw std::out_of_range("shared_buffer::at"); } return data_[index]; } RA_FORCE_inline auto at(size_type index) -> T& { if (index < 0 || index >= size_) { throw std::out_of_range("shared_buffer::at"); } return data_[index]; } RA_FORCE_inline auto slice(size_type from, size_type to) -> shared_buffer { if (from < 0 || to < 0 || from > size_ || to > size_) { throw std::out_of_range("shared_buffer::slice"); } shared_buffer result(*this); result.data_ += from; result.size_ = 0; if (from <= to) { result.size_ = to - from; } return result; } RA_FORCE_inline auto slice(size_type from, size_type to) const -> const shared_buffer { if (from < 0 || to < 0 || from > size_ || to > size_) { throw std::out_of_range("shared_buffer::slice"); } shared_buffer result(*this); result.data_ += from; result.size_ = 0; if (from <= to) { result.size_ = to - from; } return result; } RA_FORCE_inline auto size() const noexcept -> size_type { return size_; } RA_FORCE_inline auto copy() const -> shared_buffer { return shared_buffer(size_, cbegin(), cend()); } using iterator = T*; using const_iterator = const T*; RA_FORCE_inline auto begin() noexcept -> iterator { return data_; } RA_FORCE_inline auto end() noexcept -> iterator { return data_+size_; } RA_FORCE_inline auto begin() const noexcept -> const_iterator { return data_; } RA_FORCE_inline auto end() const noexcept -> const_iterator { return data_+size_; } RA_FORCE_inline auto cbegin() const noexcept -> const_iterator { return data_; } RA_FORCE_inline auto cend() const noexcept -> const_iterator { return data_+size_; } using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; RA_FORCE_inline auto rbegin() -> reverse_iterator { return std::reverse_iterator(data_+size_); } RA_FORCE_inline auto rend() -> reverse_iterator { return std::reverse_iterator(data_); } RA_FORCE_inline auto rbegin() const -> const_reverse_iterator { return std::reverse_iterator(data_+size_); } RA_FORCE_inline auto rend() const -> const_reverse_iterator { return std::reverse_iterator(data_); } RA_FORCE_inline auto crbegin() const -> const_reverse_iterator { return std::reverse_iterator(data_+size_); } RA_FORCE_inline auto crend() const -> const_reverse_iterator { return std::reverse_iterator(data_); } RA_FORCE_inline void resize(size_type newsize, bool keep_content = false) { if ( newsize < size_ && refs_ != nullptr && (*refs_) == 1 ) { size_ = newsize; } else { auto newrefs = new std::atomic(1); T* newdata = nullptr; try { newdata = new T[newsize]; } catch (...) { delete newrefs; throw; } if (keep_content) { try { size_type minsize = ((size_ < newsize)?size_:newsize); for (size_type i = 0; i < minsize; i++) { newdata[i] = data_[i]; } } catch (...) { delete newrefs; delete[] newdata; throw; } } decref(); data_ = newdata; orig_ = newdata; size_ = newsize; refs_ = newrefs; } } RA_FORCE_inline void fill(const T& value) { for (size_type i = 0; i < size_; i++) { data_[i] = value; } } void assign(size_type count, const T& value) { resize(count); fill(value); } template::value>::type> RA_FORCE_inline void assign(InputIt first, InputIt last) { resize(last-first); T* data = data_; for (InputIt it = first; it != last; it++) { *(data++) = *it; } } RA_FORCE_inline void assign(std::initializer_list ilist) { assign(ilist.begin(), ilist.end()); } private: T* data_; T* orig_; size_type size_; std::atomic* refs_; RA_FORCE_inline void uninit() noexcept { data_ = nullptr; orig_ = nullptr; size_ = 0; refs_ = nullptr; } RA_FORCE_inline void incref() noexcept { if (refs_ != nullptr) { (*refs_)++; } } RA_FORCE_inline void decref() noexcept { if (refs_ != nullptr) { if (--(*refs_) == 0) { delete[] orig_; delete refs_; uninit(); } } } template RA_FORCE_inline shared_buffer(size_type asize, InputIt first, InputIt last) : data_(nullptr), orig_(nullptr), size_(0), refs_(nullptr) { using noconstT = typename std::remove_const::type; #ifndef __ibmxl__ auto to_be_data = std::unique_ptr(new T[asize]{*first}); #else auto to_be_data = std::unique_ptr(const_cast(new typename std::remove_const::type[asize])); #endif std::copy(first, last, const_cast(to_be_data.get())); refs_ = new std::atomic(1); data_ = to_be_data.release(); orig_ = data_; size_ = asize; } }; } // namespace detail } // namespace ra namespace ra { namespace detail { class Offsets { public: RA_FORCE_inline explicit Offsets(const std::vector& extent) : rank_(static_cast(extent.size())) { if (rank_ > 0) { size_type noffsets = 0; ndataoffsets_ = 1; for (rank_type dim = rank_ - 1; dim-- != 0; ) { noffsets = extent[dim]*(1 + noffsets); } for (rank_type dim = 0 ; dim < rank_-1; dim++) { ndataoffsets_ *= extent[dim]; } offsets_.reserve(noffsets); offsets_.resize(noffsets); if (noffsets > 1) { size_type offsetnum = 0; size_type extenttot = extent[0]; for (rank_type dim = 1; dim < rank_ - 1; dim++) { for (size_type j = 0; j < extenttot; j++) { offsets_[offsetnum+j] = offsetnum + extenttot + (j*extent[dim]); } offsetnum += extenttot; extenttot *= extent[dim]; } ndataoffsets_ = extenttot; for (index_type j = 0; j < ndataoffsets_; j++) { offsets_[offsetnum + j] = j*extent[rank_ - 1]; } } } } template RA_FORCE_inline auto apply_offsets(T* data) const -> void*** { static_assert(sizeof(T*) == sizeof(void*) && sizeof(T*) == sizeof(void**), "rarray's Offsets requires all pointers to have the same size"); auto noffsets = (size_type)offsets_.size(); void*** offsets = nullptr; if (ndataoffsets_ != 0 || noffsets != 0) { if (ndataoffsets_ == 1 && noffsets == 0) { offsets = reinterpret_cast(const_cast::type*>(data)); } else { offsets = new void**[noffsets]; size_type ioffset = 0; for (; ioffset < noffsets - ndataoffsets_; ioffset++) { offsets[ioffset] = reinterpret_cast(offsets) + offsets_[ioffset]; } for (; ioffset < noffsets; ioffset++) { offsets[ioffset] = reinterpret_cast( const_cast::type*>(data) + offsets_[ioffset]); } } } return offsets; } RA_FORCE_inline auto get_num_data_offsets() const noexcept -> size_type { return ndataoffsets_; } RA_FORCE_inline auto get_num_offsets() const noexcept -> size_type { return (size_type)offsets_.size(); } RA_FORCE_inline auto get_rank() const noexcept -> rank_type { return rank_; } private: rank_type rank_{}; std::vector offsets_; size_type ndataoffsets_{}; }; } // namespace detail } // namespace ra namespace ra { namespace detail { template struct PointerArray { using type = typename PointerArray::type const*; using noconst_type = typename PointerArray::noconst_type*; }; template struct PointerArray { using type = T*; using noconst_type = T*; }; template struct PointerArray { using type = T&; using noconst_type = T&; }; template struct DataFromPtrs; template struct DataArrayFromPtrs; template class shared_shape { public: using ptrs_type = typename PointerArray::type; using size_type = ::ra::size_type; RA_FORCE_inline shared_shape() noexcept { uninit(); } RA_FORCE_inline shared_shape(const std::array& anextent, T* adata) : extent_(anextent), ptrs_(nullptr), refs_(nullptr), orig_(nullptr) { ra::detail::Offsets offsets({extent_.begin(), extent_.end()}); auto to_be_orig = std::unique_ptr(offsets.apply_offsets(adata)); if (R > 1) { refs_ = new std::atomic(1); } orig_ = to_be_orig.release(); ptrs_ = reinterpret_cast(orig_); if (R == 1) { orig_ = nullptr; } ndataoffsets_ = offsets.get_num_data_offsets(); } RA_FORCE_inline shared_shape(const shared_shape& other) noexcept : extent_(other.extent_), ptrs_(other.ptrs_), refs_(other.refs_), orig_(other.orig_), ndataoffsets_(other.ndataoffsets_) { incref(); } RA_FORCE_inline shared_shape(shared_shape&& other) noexcept : extent_(other.extent_), ptrs_(other.ptrs_), refs_(other.refs_), orig_(other.orig_), ndataoffsets_(other.ndataoffsets_) { other.uninit(); } RA_FORCE_inline auto operator=(const shared_shape& other) noexcept -> shared_shape& { if (this != &other) { decref(); extent_ = other.extent_; ptrs_ = other.ptrs_; refs_ = other.refs_; orig_ = other.orig_; ndataoffsets_ = other.ndataoffsets_; incref(); } return *this; } RA_FORCE_inline auto operator=(shared_shape&& other) noexcept -> shared_shape& { decref(); extent_ = other.extent_; ptrs_ = other.ptrs_; refs_ = other.refs_; orig_ = other.orig_; ndataoffsets_ = other.ndataoffsets_; other.uninit(); return *this; } RA_FORCE_inline ~shared_shape() noexcept { decref(); } RA_FORCE_inline auto copy() const -> shared_shape { return shared_shape(extent_, data()); } RA_FORCE_inline void relocate(T* newdata) { if (R == 1) { ptrs_ = reinterpret_cast(newdata); } else if (R > 1) { std::ptrdiff_t shift = reinterpret_cast(newdata) - reinterpret_cast(data()); if (shift != 0) { if (refs_ != nullptr && *refs_ > 1) { *this = this->copy(); } char** data_array = DataArrayFromPtrs::call(ptrs_); for (size_type i = 0; i < ndataoffsets_; i++) { data_array[i] += shift; } } } } RA_FORCE_inline void reshape(const std::array& newextent) { if (newextent != extent_) { if (size() == std::accumulate(&newextent[0], &newextent[R], 1, std::multiplies())) { *this = shared_shape(newextent, data()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } } RA_FORCE_inline auto ptrs() const noexcept -> ptrs_type { return ptrs_; } RA_FORCE_inline auto data() const noexcept -> T* { return DataFromPtrs::call(ptrs_); } RA_FORCE_inline auto size() const noexcept -> size_type { return ndataoffsets_ * extent_[R-1]; } RA_FORCE_inline auto extent(rank_type dim) const -> size_type { if (dim < 0 || dim >= R) { throw std::out_of_range("shared_shape::extent(rank_type)"); } return extent_[dim]; } RA_FORCE_inline auto extent() const noexcept -> const std::array& { return extent_; } RA_FORCE_inline auto at(size_type index) const -> shared_shape { if (R < 1 || index < 0 || index >= extent_[0]) { throw std::out_of_range("shared_shape::at"); } shared_shape result; if (R > 1) { for (rank_type dim = 0; dim < R-1; ++dim) { result.extent_[dim] = extent_[dim + 1]; } result.ptrs_ = ptrs_[index]; result.refs_ = refs_; result.orig_ = orig_; result.ndataoffsets_ = ndataoffsets_/extent_[0]; incref(); } return result; } RA_FORCE_inline auto slice(size_type beginindex, size_type endindex) const -> shared_shape { if (R < 1 || beginindex < 0 || beginindex >= extent_[0] || endindex < 0 || endindex > extent_[0]) { throw std::out_of_range("shared_shape::slice"); } shared_shape result; if (R > 0 && beginindex < endindex) { result.extent_[0] = endindex - beginindex; for (rank_type dim = 1; dim < R; ++dim) { result.extent_[dim] = extent_[dim]; } result.ptrs_ = ptrs_ + beginindex; result.refs_ = refs_; result.orig_ = orig_; if (R > 1) { result.ndataoffsets_ = result.extent_[0]*(ndataoffsets_/extent_[0]); } else { result.ndataoffsets_ = 1; } incref(); } return result; } private: std::array extent_; ptrs_type ptrs_; std::atomic* refs_; void*** orig_; size_type ndataoffsets_; RA_FORCE_inline void uninit() noexcept { ptrs_ = nullptr; orig_ = nullptr; refs_ = nullptr; ndataoffsets_ = 0; extent_.fill(0); } RA_FORCE_inline void incref() const noexcept { if (refs_ != nullptr) { (*refs_)++; } } RA_FORCE_inline void decref() noexcept { if (refs_ != nullptr) { if (--(*refs_) == 0) { if (R > 1) { delete[] orig_; } delete refs_; uninit(); } } } template friend class shared_shape; }; template class shared_shape { public: using ptrs_type = T; using size_type = ra::size_type; private: std::array extent_; ptrs_type ptrs_; std::atomic* refs_; void*** orig_; size_type ndataoffsets_; RA_FORCE_inline void incref() const noexcept {} template friend class shared_shape; }; template struct DataFromPtrs { RA_FORCE_static_inline auto call(typename PointerArray::type ptrs) noexcept -> T* { return DataFromPtrs::call(*ptrs); } }; template struct DataFromPtrs { RA_FORCE_static_inline auto call(typename PointerArray::type ptrs) noexcept -> T* { return reinterpret_cast(ptrs); } }; template struct DataArrayFromPtrs { RA_FORCE_static_inline auto call(typename PointerArray::type ptrs) noexcept -> char** { return DataArrayFromPtrs::call(*ptrs); } }; template struct DataArrayFromPtrs { RA_FORCE_static_inline auto call(typename PointerArray::type ptrs) noexcept -> char** { return reinterpret_cast(const_cast::type, 2>::noconst_type>(ptrs)); } }; template struct DataArrayFromPtrs { RA_FORCE_static_inline auto call(typename PointerArray::type ptrs) noexcept -> char** { return nullptr; } }; } // namespace detail } // namespace ra namespace ra { enum class RESIZE : unsigned char { NO, ALLOWED }; enum class MISSING : unsigned char { SKIP, DEFAULT, REPEAT }; namespace detail { template class CommaOp; template class Bracket; template class ConstBracket; #define ExOp class template class Expr; template void init_shape_fill(unsigned rank, size_type* extents, const T& lst) {} template void init_shape_fill(unsigned rank, size_type* extents, const std::initializer_list& lst) { extents[0] = std::max(extents[0], static_cast(lst.size())); if (rank >= 2) { for (const auto& sublst : lst) { init_shape_fill(rank - 1, extents + 1, sublst); } } } template auto init_shape(const std::initializer_list& lst) -> std::array { std::array extents{0}; init_shape_fill(R, extents.data(), lst); return extents; } template struct init_list_prop { enum { rank = 0 }; using type = T; }; template struct init_list_prop> { enum { rank = init_list_prop::rank + 1 }; using type = typename init_list_prop::type; }; } // namespace detail template class rarray { public: using value_type = T; using difference_type = ::ra::size_type; using size_type = ::ra::size_type; using iterator = T*; using const_iterator = const T*; using parray_t = typename detail::PointerArray::type; using noconst_parray_t = typename detail::PointerArray::noconst_type; RA_FORCE_inline rarray() : buffer_(), shape_() {} template::type> RA_FORCE_inline explicit rarray(size_type n0) : buffer_(n0), shape_({n0}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1) : buffer_(n0*n1), shape_({n0, n1}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2) : buffer_(n0*n1*n2), shape_({n0, n1, n2}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3) : buffer_(n0*n1*n2*n3), shape_({n0, n1, n2, n3}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4) : buffer_(n0*n1*n2*n3*n4), shape_({n0, n1, n2, n3, n4}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5) : buffer_(n0*n1*n2*n3*n4*n5), shape_({n0, n1, n2, n3, n4, n5}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6) : buffer_(n0*n1*n2*n3*n4*n5*n6), shape_({n0, n1, n2, n3, n4, n5, n6}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7), shape_({n0, n1, n2, n3, n4, n5, n6, n7}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}, buffer_.begin()) {} template::type> RA_FORCE_inline rarray(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, size_type n10) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9*n10), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}, buffer_.begin()) {} RA_FORCE_inline explicit rarray(const size_type* anextent) : buffer_(std::accumulate(anextent, anextent+R, 1, std::multiplies())), shape_(reinterpret_cast&>(*anextent), buffer_.begin()) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0) : buffer_(n0, buffer), shape_({n0}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1) : buffer_(n0*n1, buffer), shape_({n0, n1}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2) : buffer_(n0*n1*n2, buffer), shape_({n0, n1, n2}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3) : buffer_(n0*n1*n2*n3, buffer), shape_({n0, n1, n2, n3}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4) : buffer_(n0*n1*n2*n3*n4, buffer), shape_({n0, n1, n2, n3, n4}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5) : buffer_(n0*n1*n2*n3*n4*n5, buffer), shape_({n0, n1, n2, n3, n4, n5}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6) : buffer_(n0*n1*n2*n3*n4*n5*n6, buffer), shape_({n0, n1, n2, n3, n4, n5, n6}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7, buffer), shape_({n0, n1, n2, n3, n4, n5, n6, n7}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8, buffer), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9, buffer), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}, buffer) {} template::type> RA_FORCE_inline rarray(T* buffer, size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, size_type n10) : buffer_(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9*n10, buffer), shape_({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}, buffer) {} RA_FORCE_inline rarray(T* buffer, const size_type* anextent) : buffer_(std::accumulate(anextent, anextent+R, 1, std::multiplies()), buffer), shape_(reinterpret_cast&>(*anextent), buffer) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[Z]) : buffer_(Z, arr), shape_({Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[Y][Z]) : buffer_(Y*Z, *arr), shape_({Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[X][Y][Z]) : buffer_(X*Y*Z, **arr), shape_({X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[W][X][Y][Z]) : buffer_(W*X*Y*Z, ***arr), shape_({W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[V][W][X][Y][Z]) : buffer_(V*W*X*Y*Z, ****arr), shape_({V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[U][V][W][X][Y][Z]) : buffer_(U*V*W*X*Y*Z, *****arr), shape_({U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[T_][U][V][W][X][Y][Z]) : buffer_(T_*U*V*W*X*Y*Z, ******arr), shape_({T_, U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[S][T_][U][V][W][X][Y][Z]) : buffer_(S*T_*U*V*W*X*Y*Z, *******arr), shape_({S, T_, U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[R_][S][T_][U][V][W][X][Y][Z]) : buffer_(R_*S*T_*U*V*W*X*Y*Z, ********arr), shape_({R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[Q][R_][S][T_][U][V][W][X][Y][Z]) : buffer_(Q*R_*S*T_*U*V*W*X*Y*Z, *********arr), shape_({Q, R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> RA_FORCE_inline explicit rarray(T (&arr)[P][Q][R_][S][T_][U][V][W][X][Y][Z]) : buffer_(P*Q*R_*S*T_*U*V*W*X*Y*Z, **********arr), shape_({P, Q, R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) {} template::type> inline explicit rarray(T (&&arr)[Z]) : buffer_(Z), shape_({Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[Y][Z]) : buffer_(Y*Z), shape_({Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[X][Y][Z]) : buffer_(X*Y*Z), shape_({X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[W][X][Y][Z]) : buffer_(W*X*Y*Z), shape_({W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[V][W][X][Y][Z]) : buffer_(V*W*X*Y*Z), shape_({V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[U][V][W][X][Y][Z]) : buffer_(U*V*W*X*Y*Z), shape_({U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[T_][U][V][W][X][Y][Z]) : buffer_(T_*U*V*W*X*Y*Z), shape_({T_, U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[S][T_][U][V][W][X][Y][Z]) : buffer_(S*T_*U*V*W*X*Y*Z), shape_({S, T_, U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[R_][S][T_][U][V][W][X][Y][Z]) : buffer_(R_*S*T_*U*V*W*X*Y*Z), shape_({R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[Q][R_][S][T_][U][V][W][X][Y][Z]) : buffer_(Q*R_*S*T_*U*V*W*X*Y*Z), shape_({Q, R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } template::type> RA_FORCE_inline explicit rarray(T (&&arr)[P][Q][R_][S][T_][U][V][W][X][Y][Z]) : buffer_(P*Q*R_*S*T_*U*V*W*X*Y*Z), shape_({P, Q, R_, S, T_, U, V, W, X, Y, Z}, buffer_.begin()) { using Tnoconst = typename std::remove_const::type; std::copy_n(reinterpret_cast(arr), buffer_.size(), const_cast(buffer_.begin())); } RA_FORCE_inline rarray(const rarray &rarr) noexcept : buffer_(rarr.buffer_), shape_(rarr.shape_) {} RA_FORCE_inline auto operator=(const rarray &rarr) noexcept -> rarray& = default; RA_FORCE_inline rarray(rarray&& rarr) noexcept : buffer_(std::move(rarr.buffer_)), shape_(std::move(rarr.shape_)) {} RA_FORCE_inline auto operator=(rarray&& rarr) noexcept -> rarray& { buffer_ = std::move(rarr.buffer_); shape_ = std::move(rarr.shape_); return *this; } RA_FORCE_inline auto operator=(const T& value) noexcept(RA_noboundscheck && std::is_nothrow_copy_constructible()) -> detail::CommaOp { RA_CHECKORSAY(!empty(), "assignment to unsized array"); RA_CHECKORSAY(size() > 0, "assignment with more elements than in array"); T* first = &(buffer_[0]); if (size() > 0) { *first = value; detail::CommaOp co(first+1, first+size()-1); return co; } return detail::CommaOp(nullptr, nullptr); } RA_FORCE_inline ~rarray() = default; template RA_FORCE_inline void fill(const detail::Expr& e); template RA_FORCE_inline void form(const detail::Expr& e); template RA_FORCE_inline auto operator=(const detail::Expr& e) -> rarray&; template RA_FORCE_inline auto operator+=(const detail::Expr& e) -> rarray&; template RA_FORCE_inline auto operator-=(const detail::Expr& e) -> rarray&; template RA_FORCE_inline auto operator*=(const detail::Expr& e) -> rarray&; template RA_FORCE_inline auto operator/=(const detail::Expr& e) -> rarray&; template RA_FORCE_inline auto operator%=(const detail::Expr& e) -> rarray&; template::type> RA_FORCE_inline void reshape(size_type n0, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0; if (size() == newsize) { shape_ = detail::shared_shape({n0}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= n0) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4*n5; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4*n5*n6; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, RESIZE resize_policy = RESIZE::NO) { const size_type newsize=n0*n1*n2*n3*n4*n5*n6*n7; if (size() == n0*n1*n2*n3*n4*n5*n6*n7) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4*n5*n6*n7*n8; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4*n5*n6*n7*n8*n9; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } template::type> RA_FORCE_inline void reshape(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, size_type n10, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = n0*n1*n2*n3*n4*n5*n6*n7*n8*n9*n10; if (size() == newsize) { shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}, buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}, buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } RA_FORCE_inline void reshape(const size_type* newshape, RESIZE resize_policy = RESIZE::NO) { const size_type newsize = std::accumulate(newshape, newshape+R, 1, std::multiplies()); if (size() == newsize) { shape_ = detail::shared_shape((const std::array&)(*newshape), buffer_.begin()); } else if (resize_policy == RESIZE::ALLOWED && size() >= newsize) { buffer_ = buffer_.slice(0, newsize); shape_ = detail::shared_shape((const std::array&)(*newshape), buffer_.begin()); } else { throw std::out_of_range(std::string("Incompatible dimensions in function ") + std::string(__PRETTY_FUNCTION__)); } } RA_FORCE_inline auto copy() const -> rarray { rarray clone; clone.buffer_ = buffer_.copy(); clone.shape_ = shape_.copy(); clone.shape_.relocate(clone.buffer_.begin()); return clone; } template::value>::type> RA_FORCE_inline operator const rarray&() const noexcept { return const_ref(); } constexpr static auto rank() noexcept -> int { return R; } RA_FORCE_inline auto empty() const noexcept -> bool { return buffer_.cbegin() == nullptr; } RA_FORCE_inline auto extent(rank_type dim) const -> size_type { return shape_.extent(dim); } RA_FORCE_inline auto shape() const noexcept -> const size_type* { return &(shape_.extent()[0]); } RA_FORCE_inline auto size() const noexcept -> size_type { return shape_.size(); } RA_FORCE_inline auto data() noexcept -> T* { return buffer_.begin(); } RA_FORCE_inline auto data() const noexcept -> const T* { return buffer_.begin(); } RA_FORCE_inline auto ptr_array() const noexcept -> parray_t { return shape_.ptrs(); } RA_FORCE_inline auto noconst_ptr_array() const noexcept -> noconst_parray_t { return const_cast(shape_.ptrs()); } RA_FORCE_inline auto const_ref() const noexcept -> const rarray& { return reinterpret_cast&>(*this); } RA_FORCE_inline void clear() noexcept { shape_ = detail::shared_shape(); buffer_ = detail::shared_buffer(); } RA_FORCE_inline void fill(const T& value) { buffer_.fill(value); } private: template::type> RA_FORCE_inline void fill_g(std::initializer_list list, MISSING missing_policy) { auto filler = list.begin(); for (size_type i = 0; i < extent(0); i++) { if (filler != list.end()) { buffer_[i] = *filler++; if (filler == list.end()) { if (missing_policy == MISSING::REPEAT) filler = list.begin(); else if (missing_policy == MISSING::SKIP) break; } } else { buffer_[i] = T{}; } } } template::type> RA_FORCE_inline void fill_g(std::initializer_list list, MISSING missing_policy) { auto filler = list.begin(); for (size_type i = 0; i < extent(0); i++) { if (filler != list.end()) { at(i).fill_g(*filler++, missing_policy); if (filler == list.end()) { if (missing_policy == MISSING::REPEAT) filler = list.begin(); else if (missing_policy == MISSING::SKIP) break; } } else { at(i).fill(T{}); } } } template RA_FORCE_inline void form_g(std::initializer_list list, MISSING missing_policy) { std::array newshape = detail::init_shape(list); size_type newsize = std::accumulate(newshape.begin(), newshape.end(), 1, std::multiplies()); buffer_ = detail::shared_buffer(newsize); shape_ = detail::shared_shape(newshape, buffer_.begin()); fill_g(list, missing_policy); } public: template::type> RA_FORCE_inline void fill(std::initializer_list list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void fill(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { fill_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>>> list, MISSING missing_policy = MISSING::DEFAULT) { form_g(list, missing_policy); } template::type> RA_FORCE_inline void form(size_type n0, const T& value) { buffer_ = detail::shared_buffer(n0); shape_ = detail::shared_shape({n0}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, const T& value) { buffer_ = detail::shared_buffer(n0*n1); shape_ = detail::shared_shape({n0, n1}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2); shape_ = detail::shared_shape({n0, n1, n2}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3); shape_ = detail::shared_shape({n0, n1, n2, n3}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4); shape_ = detail::shared_shape({n0, n1, n2, n3, n4}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5*n6); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5*n6*n7); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5*n6*n7*n8); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}, buffer_.begin()); buffer_.fill(value); } template::type> RA_FORCE_inline void form(size_type n0, size_type n1, size_type n2, size_type n3, size_type n4, size_type n5, size_type n6, size_type n7, size_type n8, size_type n9, size_type n10, const T& value) { buffer_ = detail::shared_buffer(n0*n1*n2*n3*n4*n5*n6*n7*n8*n9*n10); shape_ = detail::shared_shape({n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}, buffer_.begin()); buffer_.fill(value); } RA_FORCE_inline auto begin() noexcept -> iterator { return buffer_.begin(); } RA_FORCE_inline auto begin() const noexcept -> const_iterator { return buffer_.begin(); } RA_FORCE_inline auto cbegin() const noexcept -> const_iterator { return buffer_.cbegin(); } RA_FORCE_inline auto end() noexcept -> iterator { return buffer_.end(); } RA_FORCE_inline auto end() const noexcept -> const_iterator { return buffer_.end(); } RA_FORCE_inline auto cend() const noexcept -> const_iterator { return buffer_.cend(); } RA_FORCE_inline auto index(const T& a, int i) const -> size_type { std::ptrdiff_t linearindex = &a - &(buffer_[0]); if (linearindex < 0 || linearindex >= size()) throw "element not in array"; const size_type* extent_ = shape(); for (int j = R-1; j > i; j--) linearindex /= extent_[j]; return linearindex % extent_[i]; } RA_FORCE_inline auto index(const iterator& iter, int i) const -> size_type { return index(*iter, i); } RA_FORCE_inline auto index(const T& a) const -> std::array { std::array ind; std::ptrdiff_t linearindex = &a - &(buffer_[0]); RA_CHECKORSAY(linearindex >= 0 && linearindex < size(), "element not in array"); int j = R; const size_type* extent_ = shape(); while (j-->0) { ind[j] = linearindex % extent_[j]; linearindex /= extent_[j]; } return ind; } RA_FORCE_inline auto index(const iterator& i) const -> std::array { return index(*i); } template> RA_FORCE_inline auto at(size_type i) -> typename std::enable_if::type { if (i < 0 || i >= extent(0)) throw std::out_of_range("rarray::at"); size_type stride = size()/extent(0); return ra::rarray(buffer_.slice(i*stride, (i+1)*stride), shape_.at(i)); } template RA_FORCE_inline auto at(size_type i) -> typename std::enable_if::type { if (i < 0 || i >= extent(0)) throw std::out_of_range("rarray::at"); return shape_.ptrs()[i]; } template> RA_FORCE_inline auto at(size_type i) const -> typename std::enable_if::type { if (i < 0 || i >= extent(0)) throw std::out_of_range("rarray::at"); size_type stride = size()/extent(0); return ra::rarray(buffer_.slice(i*stride, (i+1)*stride), shape_.at(i)); } template RA_FORCE_inline auto at(size_type i) const -> typename std::enable_if::type { if (i < 0 || i >= extent(0)) throw std::out_of_range("rarray::at"); return shape_.ptrs()[i]; } RA_FORCE_inline auto slice(size_type beginindex, size_type endindex) -> rarray { if (beginindex < 0 || beginindex >= shape_.extent(0) || endindex < 0 || endindex > shape_.extent(0)) throw std::out_of_range("rarray::slice"); size_type stride = size()/extent(0); return {buffer_.slice(beginindex*stride, endindex*stride), shape_.slice(beginindex, endindex)}; } template RA_FORCE_inline auto operator[](size_type i) -> typename std::enable_if::type { RA_CHECKORSAY(i >= 0 && i < extent(0), "index out of range of array"); return buffer_.begin()[i]; } template RA_FORCE_inline auto operator[](size_type i) -> typename std::enable_if >::type { return { *this, i, this->shape() }; } template RA_FORCE_inline auto operator[](size_type i) const -> typename std::enable_if::type { RA_CHECKORSAY(i >= 0 && i < extent(0), "index out of range of array"); return buffer_.cbegin()[i]; } template RA_FORCE_inline auto operator[](size_type i) const -> typename std::enable_if>::type { return { *this, i, this->shape() }; } #if __cpp_multidimensional_subscript >= 202110L template RA_FORCE_inline auto operator[](size_type i, Ts... args) -> typename std::enable_if::type { return operator[](i)[args...]; } template RA_FORCE_inline auto operator[](size_type i, Ts... args) const -> typename std::enable_if::type { return operator[](i)[args...]; } #endif RA_FORCE_inline auto leval(size_type i) const -> const T&; private: friend class detail::Bracket>; friend class detail::ConstBracket>; RA_FORCE_inline auto private_at(size_type i) -> typename detail::PointerArray::type { return shape_.ptrs()[i]; } RA_FORCE_inline auto private_at(size_type i) const -> typename detail::PointerArray::type { return shape_.ptrs()[i]; } friend class rarray; RA_FORCE_inline rarray(detail::shared_buffer&& abuffer, detail::shared_shape&& ashape) : buffer_(std::forward>(abuffer)), shape_(std::forward>(ashape)) {} RA_FORCE_inline rarray(const detail::shared_buffer&& abuffer, detail::shared_shape&& ashape) : buffer_(std::forward>(const_cast&& >(abuffer))), shape_(std::forward>(ashape)) {} detail::shared_buffer buffer_; detail::shared_shape shape_; }; namespace detail { template class CommaOp { public: RA_FORCE_inline auto operator,(const T& e) -> CommaOp& { RA_CHECKORSAY(ptr_ != nullptr && last_ != nullptr, "invalid comma operator"); RA_CHECKORSAY(ptr_ <= last_, "assignment with more elements than in array"); if (ptr_ && ptr_ <= last_) *ptr_++ = e; return *this; } private: RA_FORCE_inline CommaOp(T* ptr, T* last) noexcept(RA_noboundscheck) : ptr_(ptr), last_(last) { RA_CHECKORSAY(ptr_ != nullptr && last_ != nullptr, "invalid comma operator"); } T *ptr_; T * const last_; template friend class ra::rarray; }; template class Bracket { private: P& parent_; ///< what array/array expression is being accessed size_type index_; const size_type* shape_; public: RA_FORCE_inline auto operator[](size_type nextindex) noexcept(RA_noboundscheck) -> Bracket { return { *this, nextindex, shape_ + 1 }; } RA_FORCE_inline operator decltype(parent_.at(index_)) () { return parent_.at(index_); } Bracket(const Bracket&) = delete; Bracket(const Bracket&&) = delete; auto operator=(const Bracket&) -> Bracket& = delete; auto operator=(const Bracket&&) -> Bracket& = delete; ~Bracket() = default; private: RA_FORCE_inline Bracket(P& parent, size_type i, const size_type* shape) noexcept(RA_noboundscheck) : parent_(parent), index_(i), shape_(shape) { RA_CHECKORSAY(index_ >=0 && index_ < shape_[0], "index out of range of array"); } RA_FORCE_inline auto private_at(size_type nextindex) noexcept(RA_noboundscheck) -> decltype(parent_.private_at(index_)[nextindex]) { return parent_.private_at(index_)[nextindex]; } template friend class ra::rarray; template friend class detail::Bracket; public: RA_FORCE_inline auto at(size_type nextindex) -> decltype(parent_.at(index_).at(nextindex)) { return parent_.at(index_).at(nextindex); } #if __cpp_multidimensional_subscript >= 202110L template RA_FORCE_inline auto operator[](size_type nextindex, Ts... args) -> typename std::enable_if::type { return operator[](nextindex)[args...]; } #endif }; template class Bracket { private: P& parent_; ///< what array/array expression is being accessed size_type index_; const size_type* shape_; public: RA_FORCE_inline auto operator[](size_type nextindex) noexcept(RA_noboundscheck) -> T& { RA_CHECKORSAY(nextindex >= 0 && nextindex < shape_[1], "index out of range of array"); return parent_.private_at(index_)[nextindex]; } RA_FORCE_inline operator decltype(parent_.at(index_)) () { return parent_.at(index_); } Bracket(const Bracket&) = delete; Bracket(const Bracket&&) = delete; auto operator=(const Bracket&) -> Bracket& = delete; auto operator=(const Bracket&&) -> Bracket& = delete; ~Bracket() = default; private: RA_FORCE_inline Bracket(P& parent, size_type i, const size_type* shape) noexcept(RA_noboundscheck) : parent_(parent), index_(i), shape_(shape) { RA_CHECKORSAY(index_ >= 0 && index_ < shape_[0], "index out of range of array"); } template friend class ra::rarray; template friend class detail::Bracket; public: RA_FORCE_inline auto at(size_type nextindex) -> decltype(parent_.at(index_).at(nextindex)) { return parent_.at(index_).at(nextindex); } }; template class ConstBracket { private: const P& parent_; size_type index_; public: RA_FORCE_inline auto operator[](size_type nextindex) const noexcept(RA_noboundscheck) -> ConstBracket { return { *this, nextindex, shape_ + 1 }; } RA_FORCE_inline operator decltype(parent_.at(index_)) () { return parent_.at(index_); } ConstBracket(const ConstBracket&) = delete; ConstBracket(const ConstBracket&&) = delete; auto operator=(const ConstBracket&) -> ConstBracket& = delete; auto operator=(const ConstBracket&&) -> ConstBracket& = delete; ~ConstBracket() = default; private: const size_type* shape_; RA_FORCE_inline ConstBracket(const P& parent, size_type i, const size_type* shape) noexcept(RA_noboundscheck) : parent_(parent), index_(i), shape_(shape) { RA_CHECKORSAY(index_ >= 0 && index_ < shape_[0], "index out of range of array"); } RA_FORCE_inline auto private_at(size_type nextindex) const noexcept(RA_noboundscheck) -> decltype(parent_.private_at(index_)[nextindex]) { return parent_.private_at(index_)[nextindex]; } template friend class ra::rarray; template friend class detail::ConstBracket; public: RA_FORCE_inline auto at(size_type nextindex) const -> decltype(parent_.at(index_).at(nextindex)) { return parent_.at(index_).at(nextindex); } #if __cpp_multidimensional_subscript >= 202110L template RA_FORCE_inline auto operator[](size_type nextindex, Ts... args) -> typename std::enable_if::type { return operator[](nextindex)[args...]; } #endif }; template class ConstBracket { private: const P& parent_; size_type index_; public: RA_FORCE_inline auto operator[](size_type nextindex) const noexcept(RA_noboundscheck) -> const T& { RA_CHECKORSAY(nextindex >=0 && nextindex < shape_[1], "index out of range of array"); return parent_.private_at(index_)[nextindex]; } RA_FORCE_inline operator decltype(parent_.at(index_)) () { return parent_.at(index_); } ConstBracket(const ConstBracket&) = delete; ConstBracket(const ConstBracket&&) = delete; auto operator=(const ConstBracket&) -> ConstBracket& = delete; auto operator=(const ConstBracket&&) -> ConstBracket& = delete; ~ConstBracket() = default; private: const size_type* shape_; RA_FORCE_inline ConstBracket(const P& parent, size_type i, const size_type* shape) noexcept(RA_noboundscheck) : parent_(parent), index_(i), shape_(shape) { RA_CHECKORSAY(index_ >= 0 && index_ < shape_[0], "index out of range of array"); } template friend class ra::rarray; template friend class detail::ConstBracket; public: RA_FORCE_inline auto at(size_type nextindex) const -> decltype(parent_.at(index_).at(nextindex)) { return parent_.at(index_).at(nextindex); } }; template auto make_rarray_g(std::initializer_list list, ra::MISSING missing_policy) -> rarray::type,ra::detail::init_list_prop::rank> { rarray::type, ra::detail::init_list_prop::rank> a; a.form(list, missing_policy); return a; } } // namespace detail template inline auto linspace(S x1, S x2, size_type n = 0, bool end_incl = true) -> rarray { if (n == 0) { if (x2 > x1) n = static_cast(x2 - x1 + end_incl); else n = static_cast(x1 - x2 + end_incl); } rarray x(n); for (size_type i = 0; i < n; i++) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" x[i] = x1 + static_cast(((x2-x1)*i)/(n-end_incl)); #pragma GCC diagnostic pop if (end_incl) x[n-1] = x2; return x; } template class Xrange { struct const_iterator { using difference_type = std::ptrdiff_t; using value_type = T; using pointer = T*; using reference = T&; using iterator_category = std::input_iterator_tag; RA_FORCE_inline const_iterator(): i_(0), b_(0), d_(1) {} RA_FORCE_inline const_iterator(const Xrange& xr, T i): i_(i), b_(xr.b_), d_(xr.d_) {} RA_FORCE_inline auto operator!=(const const_iterator& other) const -> bool { return i_ != other.i_; } RA_FORCE_inline auto operator==(const const_iterator& other) const -> bool { return i_ == other.i_ && d_ == other.d_ && b_ == other.b_; } RA_FORCE_inline auto operator++() -> const_iterator& { i_ += d_; if (d_ > 0 && i_ >= b_) i_ = b_; if (d_ < 0 && i_ <= b_) i_ = b_; return *this; } RA_FORCE_inline auto operator++(int) -> const_iterator { const const_iterator temp = *this; this->operator++(); return temp; } RA_FORCE_inline auto operator*() const -> const T& { return i_; } RA_FORCE_inline auto operator+=(difference_type n) -> const_iterator& { i_ += (T)(n*d_); if (n*d_ > 0 && i_ >= b_) i_ = b_; if (n*d_ < 0 && i_ <= b_) i_ = b_; return *this; } RA_FORCE_inline auto operator-=(difference_type n) -> const_iterator& { i_ -= (T)(n*d_); if (-n*d_ > 0 && i_ >= b_) i_ = b_; if (-n*d_ < 0 && i_ <= b_) i_ = b_; return *this; } RA_FORCE_inline auto operator-(const const_iterator& other) const -> difference_type { return (i_ - other.i_)/d_; } RA_FORCE_inline auto operator--() -> const_iterator& { i_ -= d_; if (-d_ > 0 && i_ >= b_) i_ = b_; if (-d_ < 0 && i_ <= b_) i_ = b_; return *this; } RA_FORCE_inline auto operator--(int) -> const_iterator { const const_iterator temp = *this; this->operator--(); return temp; } RA_FORCE_inline auto operator+(difference_type n) const -> const_iterator { const_iterator result(*this); result += n; return result; } RA_FORCE_inline auto operator-(difference_type n) const -> const_iterator { const_iterator result(*this); result -= n; return result; } RA_FORCE_inline auto operator[](difference_type n) const -> const T { return i_ + n*d_; } friend auto operator+(difference_type n, const const_iterator& rhs) -> const_iterator { const_iterator result(rhs); result += n; return result; } RA_FORCE_inline auto operator<(const const_iterator& other) const -> bool { return i_ < other.i_; } RA_FORCE_inline auto operator<=(const const_iterator& other) const -> bool { return i_ <= other.i_; } RA_FORCE_inline auto operator>(const const_iterator& other) const -> bool { return i_ < other.i_; } RA_FORCE_inline auto operator>=(const const_iterator& other) const -> bool { return i_ <= other.i_; } T i_, b_, d_; }; T a_, b_, d_; static auto ceil(double x) -> T { return static_cast(static_cast(x) + static_cast(x != static_cast(static_cast(x)))); } public: RA_FORCE_inline Xrange(T a, T b, T d) : a_(a), b_(a + ceil(static_cast(b-a)/static_cast(d))*d), d_(d) {} RA_FORCE_inline auto begin() const -> const_iterator { return const_iterator(*this, a_); } RA_FORCE_inline auto end() const -> const_iterator { return const_iterator(*this, b_); } RA_FORCE_inline auto size() const -> size_t { return static_cast((b_-a_)/d_); } }; template inline auto xrange(T end) -> Xrange { return Xrange(static_cast(0), end, static_cast(1)); } template inline auto xrange(S begin, T end) -> Xrange { return Xrange(static_cast(begin), end, static_cast(1)); } template inline auto xrange(S begin, T end, U step) -> Xrange { return Xrange(static_cast(begin), end, static_cast(step)); } template inline auto extent(const A &a, int i) -> size_type { switch (i) { case 0: return std::extent(); case 1: return std::extent(); case 2: return std::extent(); case 3: return std::extent(); case 4: return std::extent(); case 5: return std::extent(); case 6: return std::extent(); case 7: return std::extent(); case 8: return std::extent(); case 9: return std::extent(); case 10: return std::extent(); default: throw std::out_of_range("ra::extent"); return 0; } } template inline auto extent(const rarray &a, int i) -> size_type { return a.extent(i); } template auto make_rarray(std::initializer_list list, MISSING missing_policy = MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list> list, MISSING missing_policy = MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list>>>>>>>>>> list, MISSING missing_policy=MISSING::DEFAULT) -> rarray { return detail::make_rarray_g(list, missing_policy); } template auto make_rarray(size_type n0, const T& fillvalue) -> rarray { rarray result(n0); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0, size_type n1, const T& fillvalue) -> rarray { rarray result(n0,n1); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,const T& fillvalue) -> rarray { rarray result(n0,n1,n2); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,size_type n6,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5,n6); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,size_type n6,size_type n7,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5,n6,n7); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,size_type n6,size_type n7,size_type n8,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5,n6,n7,n8); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,size_type n6,size_type n7,size_type n8,size_type n9,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9); result.fill(fillvalue); return result; } template auto make_rarray(size_type n0,size_type n1,size_type n2,size_type n3,size_type n4,size_type n5,size_type n6,size_type n7,size_type n8,size_type n9,size_type n10,const T& fillvalue) -> rarray { rarray result(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10); result.fill(fillvalue); return result; } } // namespace ra namespace std { template struct remove_all_extents> { using type = T; }; template struct rank> { static const size_t value = R; }; } // namespace std #ifndef RA_FORCE_static_inline #define RA_FORCE_static_inline static #endif namespace ra { namespace detail { template struct Deref { RA_FORCE_static_inline auto access(typename PointerArray::type ptrarr, const size_type* indices) -> T& { return Deref::access(ptrarr[indices[0]-1], indices+1); } }; template struct Deref { RA_FORCE_static_inline auto access(typename PointerArray::type ptrarr, const size_type* indices) -> T& { return ptrarr[indices[0]-1]; } }; template struct StringToValue { RA_FORCE_static_inline void get(const std::string& input, T& output) { std::stringstream str(input); str >> output; } }; template<> struct StringToValue { RA_FORCE_static_inline void get(const std::string& input, std::string& output) { output = input; } }; enum class token : unsigned char { BRACEOPEN, BRACECLOSE, COMMA, DATASTRING, END }; inline auto toch(const token& Token) -> char { switch (Token) { case token::BRACEOPEN: return '{'; case token::BRACECLOSE: return '}'; case token::COMMA: return ','; case token::DATASTRING: return '$'; case token::END: return '.'; default: return '\0'; } } template inline auto text_output(std::ostream &out, const rarray& rarr) -> std::ostream& { if (!rarr.empty()) { out << "{\n"; for (size_type i = 0; i < rarr.extent(0); i++) { if (i > 0) { out << ",\n"; } out << rarr.at(i); } out << "\n}"; } else { for (int i = 0; i < R; i++) { out << '{'; } for (int i = 0; i < R; i++) { out << '}'; } out << "\n"; } return out; } template inline auto text_output(std::ostream &out, const rarray& rarr) -> std::ostream& { if (!rarr.empty()) { out << '{'; for (size_type i = 0; i < rarr.extent(0); i++) { if (i > 0) { out << ','; } std::stringstream strstr; std::string result; const T& val = rarr.at(i); strstr << val; result = strstr.str(); if (result.find_first_of("{,}#") != std::string::npos && (result[0] != '(' || result[result.size()-1] != ')' || result.substr(1, result.size()-2).find_first_of(')') != std::string::npos) ) { out << '#' << result.size() << ':'; } out << result; } out << '}'; } else { out << "{}"; } return out; } RA_FORCE_static_inline auto get_but_eat_newline(std::istream& input) -> char { char ch1 = '\n'; while (ch1 == '\n' && !input.eof()) { input >> ch1; } return ch1; } RA_FORCE_static_inline auto get_but_eat_whitespace(std::istream & input) -> char { char ch1; input >> ch1; return ch1; } template inline auto parse_shape(std::istream & input) -> std::pair>, std::array> { std::pair>, std::array> wholeresult; auto init_file_ptr = input.tellg(); try { std::list>& result = wholeresult.first; size_type* shape = wholeresult.second.data(); std::array current_shape; for (rank_type dim = 0; dim < R; dim++) { current_shape[dim] = 1; shape[dim] = 0; if (get_but_eat_newline(input) != '{') { throw std::istream::failure("Format error"); } result.emplace_back(token::BRACEOPEN, ""); } int current_depth = R-1; while (current_depth >= 0) { if (current_depth == R-1) { char lastchar; std::string word; do { if (word.empty()) { lastchar = get_but_eat_newline(input); } else { input.get(lastchar); } if (lastchar != ',' && lastchar != '}') { word += lastchar; } if (word == "#") { word = ""; std::string skipstr; do { input.get(lastchar); skipstr += lastchar; } while (lastchar != ':'); int skip = atoi(skipstr.c_str()); for (int i = 0; i < skip; i++) { char nextchar; input.get(nextchar); word += nextchar; } } else if (word == "(") { const int safeguardcount = 1024*1024; int count = 0; while (lastchar != ')' && count < safeguardcount) { input.get(lastchar); word += lastchar; count++; } input.get(lastchar); } if (lastchar == ',') { result.emplace_back(token::DATASTRING, word); result.emplace_back(token::COMMA, ""); word = ""; current_shape[current_depth]++; } } while (lastchar != '}'); result.emplace_back(token::DATASTRING, word); result.emplace_back(token::BRACECLOSE, ""); if (shape != nullptr) { if (shape[current_depth] < current_shape[current_depth]) { shape[current_depth] = current_shape[current_depth]; } } current_depth--; } else { switch (get_but_eat_whitespace(input)) { case ',': result.emplace_back(token::COMMA, ""); current_shape[current_depth]++; break; case '{': result.emplace_back(token::BRACEOPEN, ""); current_depth++; current_shape[current_depth] = 1; break; case '}': result.emplace_back(token::BRACECLOSE, ""); if (shape != nullptr) { if (shape[current_depth] < current_shape[current_depth]) { shape[current_depth] = current_shape[current_depth]; } } current_depth--; break; default: throw std::istream::failure("Format error"); } } } result.emplace_back(token::END, ""); } catch (std::istream::failure& e) { input.seekg(init_file_ptr); input.setstate(std::ios::failbit); throw; } return wholeresult; } template inline void parse_strings(const std::pair>, std::array> & tokens, typename PointerArray::type ptrptr) { std::array index; int current_depth = -1; for (auto& tokenpair : tokens.first) { switch (tokenpair.first) { case token::BRACEOPEN: current_depth++; index[current_depth] = 1; break; case token::BRACECLOSE: current_depth--; break; case token::COMMA: index[current_depth]++; break; case token::DATASTRING: StringToValue::get(tokenpair.second, Deref::access(ptrptr, index.data())); break; case token::END: break; } if (tokenpair.first == token::END) { break; } } } } // namespace detail template inline auto operator<<(std::ostream &outstream, const rarray& rarr) -> std::ostream& { return detail::text_output(outstream, rarr); } template inline auto operator>>(std::istream &instream, rarray& rarr) -> std::istream& { auto parsed = detail::parse_shape(instream); size_type* parsed_extent = parsed.second.data(); if (std::accumulate(parsed_extent, parsed_extent+R, 1, std::multiplies()) <= rarr.size()) { rarr.reshape(parsed_extent, RESIZE::ALLOWED); } else { rarr = rarray(parsed_extent); } detail::parse_strings(parsed, rarr.ptr_array()); return instream; } } // namespace ra #if __cplusplus >= 202002L #if __has_include() namespace std { template struct formatter> : formatter { template auto format(const ra::rarray& r, CTX& ctx) const { stringstream s; s << r; return formatter::format(s.str(), ctx); } }; } #endif #endif #undef RA_CHECKORSAY #undef RA_FORCE_inline #undef RA_FORCE_static_inline #undef RA_noboundscheck #define EXTENT(A, I) ra::extent(A, I) #define RARRAY(A) rarray::type, std::rank::value>(A) #define INDEX(A, X, I) RARRAY(A).index(X, I) using ra::rarray; using ra::linspace; using ra::xrange; using ra::make_rarray; template using rvector = rarray; template using rmatrix = rarray; template using rtensor = rarray; #else #error "This file requires C++11 or newer support." #endif #endif