/// \file ROOT/rhysd_span.h /// \ingroup Base StdExt /// \author Axel Naumann /// \date 2015-09-06 /************************************************************************* * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #ifndef ROOT_RHYSD_SPAN_H #define ROOT_RHYSD_SPAN_H // Necessary to compile in c++11 mode #if __cplusplus >= 201402L #define R__CONSTEXPR_IF_CXX14 constexpr #else #define R__CONSTEXPR_IF_CXX14 #endif // From https://github.com/rhysd/array_view/blob/master/include/array_view.hpp #include #include #include #include #include #include #include #include namespace ROOT { namespace Detail { using std::size_t; // detail meta functions {{{ template struct is_array_class { static bool const value = false; }; template struct is_array_class> { static bool const value = true; }; template struct is_array_class> { static bool const value = true; }; template struct is_array_class> { static bool const value = true; }; // }}} // index sequences {{{ template< size_t... Indices > struct indices{ static constexpr size_t value[sizeof...(Indices)] = {Indices...}; }; template struct make_indices_next; template struct make_indices_next, Next> { typedef indices type; }; template struct make_indices_next2; template struct make_indices_next2, Next, Tail> { typedef indices type; }; template struct make_indices_impl; template struct make_indices_impl< First, Step, N, typename std::enable_if<(N == 0)>::type > { typedef indices<> type; }; template struct make_indices_impl< First, Step, N, typename std::enable_if<(N == 1)>::type > { typedef indices type; }; template struct make_indices_impl< First, Step, N, typename std::enable_if<(N > 1 && N % 2 == 0)>::type > : ROOT::Detail::make_indices_next< typename ROOT::Detail::make_indices_impl::type, First + N / 2 * Step > {}; template struct make_indices_impl< First, Step, N, typename std::enable_if<(N > 1 && N % 2 == 1)>::type > : ROOT::Detail::make_indices_next2< typename ROOT::Detail::make_indices_impl::type, First + N / 2 * Step, First + (N - 1) * Step > {}; template struct make_indices_ : ROOT::Detail::make_indices_impl< First, Step, ((Last - First) + (Step - 1)) / Step > {}; template < size_t Start, size_t Last, size_t Step = 1 > using make_indices = typename make_indices_< Start, Last, Step >::type; // }}} } // namespace Detail } namespace std { inline namespace __ROOT { // span {{{ struct check_bound_t {}; static constexpr check_bound_t check_bound{}; template class span { public: /* * types */ typedef T element_type; typedef std::remove_cv value_type; typedef element_type * pointer; typedef element_type const* const_pointer; typedef element_type & reference; typedef element_type const& const_reference; typedef element_type * iterator; typedef element_type const* const_iterator; typedef ptrdiff_t difference_type; typedef std::size_t index_type; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; /* * ctors and assign operators */ constexpr span() noexcept : length_(0), data_(nullptr) {} constexpr span(span const&) noexcept = default; constexpr span(span &&) noexcept = default; // Note: // This constructor can't be constexpr because & operator can't be constexpr. template /*implicit*/ span(std::array & a) noexcept : length_(N), data_(N > 0 ? a.data() : nullptr) {} // Note: // This constructor can't be constexpr because & operator can't be constexpr. template /*implicit*/ span(T(& a)[N]) noexcept : length_(N), data_(N > 0 ? std::addressof(a[0]) : nullptr) { static_assert(N > 0, "Zero-length array is not permitted in ISO C++."); } /*implicit*/ span(std::vector::type> const& v) noexcept : length_(v.size()), data_(v.empty() ? nullptr : v.data()) {} /*implicit*/ span(std::vector::type> & v) noexcept : length_(v.size()), data_(v.empty() ? nullptr : v.data()) {} /*implicit*/ constexpr span(pointer a, index_type const n) noexcept : length_(n), data_(a) {} template< class InputIterator, class = typename std::enable_if< std::is_same< typename std::remove_cv::type, typename std::iterator_traits::value_type >::value >::type > span(InputIterator start, InputIterator last) : length_(std::distance(start, last)), data_(&*start) {} span(std::initializer_list const& l) : length_(l.size()), data_(std::begin(l)) {} span& operator=(span const&) noexcept = default; span& operator=(span &&) noexcept = delete; /* * iterator interfaces */ constexpr iterator begin() const noexcept { return data_; } constexpr iterator end() const noexcept { return data_ + length_; } constexpr const_iterator cbegin() const noexcept { return begin(); } constexpr const_iterator cend() const noexcept { return end(); } reverse_iterator rbegin() const { return {end()}; } reverse_iterator rend() const { return {begin()}; } const_reverse_iterator crbegin() const { return rbegin(); } const_reverse_iterator crend() const { return rend(); } /* * access */ constexpr index_type size() const noexcept { return length_; } constexpr index_type length() const noexcept { return size(); } constexpr index_type max_size() const noexcept { return size(); } constexpr bool empty() const noexcept { return length_ == 0; } constexpr reference operator[](index_type const n) const noexcept { return *(data_ + n); } constexpr reference at(index_type const n) const { //Works only in C++14 //if (n >= length_) throw std::out_of_range("span::at()"); //return *(data_ + n); return n >= length_ ? throw std::out_of_range("span::at()") : *(data_ + n); } constexpr pointer data() const noexcept { return data_; } constexpr const_reference front() const noexcept { return *data_; } constexpr const_reference back() const noexcept { return *(data_ + length_ - 1); } /* * slices */ // slice with indices {{{ // check bound {{{ constexpr span slice(check_bound_t, index_type const pos, index_type const slicelen) const { //Works only in C++14 //if (pos >= length_ || pos + slicelen >= length_) { // throw std::out_of_range("span::slice()"); //} //return span{begin() + pos, begin() + pos + slicelen}; return pos >= length_ || pos + slicelen >= length_ ? throw std::out_of_range("span::slice()") : span{begin() + pos, begin() + pos + slicelen}; } constexpr span slice_before(check_bound_t, index_type const pos) const { //Works only in C++14 //if (pos >= length_) { // throw std::out_of_range("span::slice()"); //} //return span{begin(), begin() + pos}; return pos >= length_ ? std::out_of_range("span::slice()") : span{begin(), begin() + pos}; } constexpr span slice_after(check_bound_t, index_type const pos) const { //Works only in C++14 //if (pos >= length_) { // throw std::out_of_range("span::slice()"); //} //return span{begin() + pos, end()}; return pos >= length_ ? std::out_of_range("span::slice()") : span{begin() + pos, end()}; } // }}} // not check bound {{{ constexpr span slice(index_type const pos, index_type const slicelen) const { return span{begin() + pos, begin() + pos + slicelen}; } constexpr span slice_before(index_type const pos) const { return span{begin(), begin() + pos}; } constexpr span slice_after(index_type const pos) const { return span{begin() + pos, end()}; } // }}} // }}} // slice with iterators {{{ // check bound {{{ constexpr span slice(check_bound_t, iterator start, iterator last) const { //Works only in C++14 //if ( start >= end() || // last > end() || // start > last || // static_cast(std::distance(start, last > end() ? end() : last)) > length_ - std::distance(begin(), start) ) { // throw std::out_of_range("span::slice()"); //} //return span{start, last > end() ? end() : last}; return ( start >= end() || last > end() || start > last || static_cast(std::distance(start, last > end() ? end() : last)) > length_ - std::distance(begin(), start) ) ? throw std::out_of_range("span::slice()") : span{start, last > end() ? end() : last}; } constexpr span slice_before(check_bound_t, iterator const pos) const { //Works only in C++14 //if (pos < begin() || pos > end()) { // throw std::out_of_range("span::slice()"); //} //return span{begin(), pos > end() ? end() : pos}; return pos < begin() || pos > end() ? throw std::out_of_range("span::slice()") : span{begin(), pos > end() ? end() : pos}; } constexpr span slice_after(check_bound_t, iterator const pos) const { //Works only in C++14 // if (pos < begin() || pos > end()) { // throw std::out_of_range("span::slice()"); //} //return span{pos < begin() ? begin() : pos, end()}; return pos < begin() || pos > end() ? throw std::out_of_range("span::slice()") : span{pos < begin() ? begin() : pos, end()}; } // }}} // not check bound {{{ constexpr span slice(iterator start, iterator last) const { return span{start, last}; } constexpr span slice_before(iterator const pos) const { return span{begin(), pos}; } constexpr span slice_after(iterator const pos) const { return span{pos, end()}; } // }}} // }}} /* * others */ template::type>> auto to_vector(Allocator const& alloc = Allocator{}) const -> std::vector::type, Allocator> { return {begin(), end(), alloc}; } template auto to_array() const -> std::array { return to_array_impl(ROOT::Detail::make_indices<0, N>{}); } private: template auto to_array_impl(ROOT::Detail::indices) const -> std::array { return {{(I < length_ ? *(data_ + I) : T{} )...}}; } private: index_type length_; pointer data_; }; // }}} } // inline namespace __ROOT } // namespace std namespace ROOT { // compare operators {{{ namespace Detail { template< class ArrayL, class ArrayR > inline R__CONSTEXPR_IF_CXX14 bool operator_equal_impl(ArrayL const& lhs, size_t const lhs_size, ArrayR const& rhs, size_t const rhs_size) { if (lhs_size != rhs_size) { return false; } auto litr = std::begin(lhs); auto ritr = std::begin(rhs); for (; litr != std::end(lhs); ++litr, ++ritr) { if (!(*litr == *ritr)) { return false; } } return true; } } // namespace Detail } // namespace ROOT namespace std { inline namespace __ROOT { template inline constexpr bool operator==(span const& lhs, span const& rhs) { return ROOT::Detail::operator_equal_impl(lhs, lhs.length(), rhs, rhs.length()); } template< class T, class Array, class = typename std::enable_if< ROOT::Detail::is_array_class::value >::type > inline constexpr bool operator==(span const& lhs, Array const& rhs) { return ROOT::Detail::operator_equal_impl(lhs, lhs.length(), rhs, rhs.size()); } template inline constexpr bool operator==(span const& lhs, T2 const (& rhs)[N]) { return ROOT::Detail::operator_equal_impl(lhs, lhs.length(), rhs, N); } template< class T, class Array, class = typename std::enable_if< is_array::value >::type > inline constexpr bool operator!=(span const& lhs, Array const& rhs) { return !(lhs == rhs); } template< class Array, class T, class = typename std::enable_if< is_array::value >::type > inline constexpr bool operator==(Array const& lhs, span const& rhs) { return rhs == lhs; } template< class Array, class T, class = typename std::enable_if< is_array::value, Array >::type > inline constexpr bool operator!=(Array const& lhs, span const& rhs) { return !(rhs == lhs); } // }}} // helpers to construct view {{{ template< class Array, class = typename std::enable_if< ROOT::Detail::is_array_class::value >::type > inline constexpr auto make_view(Array const& a) -> span { return {a}; } template< class T, size_t N> inline constexpr span make_view(T const (&a)[N]) { return {a}; } template inline constexpr span make_view(T const* p, typename span::index_type const n) { return span{p, n}; } template::value_type>> inline constexpr Result make_view(InputIterator begin, InputIterator end) { return Result{begin, end}; } template inline constexpr span make_view(std::initializer_list const& l) { return {l}; } // }}} } // inline namespace __ROOT } // namespace std #if 0 // This stuff is too complex for our simple use case! #include #include #include // See N3851 namespace std { template class index; template class bounds { public: static constexpr int rank = Rank; using reference = ptrdiff_t &; using const_reference = const ptrdiff_t &; using size_type = size_t; using value_type = ptrdiff_t; private: std::array m_B; public: constexpr bounds() noexcept; constexpr bounds(value_type b) noexcept: m_B{{b}} { }; //constexpr bounds(const initializer_list&) noexcept; //constexpr bounds(const bounds&) noexcept; //bounds& operator=(const bounds&) noexcept; reference operator[](size_type i) noexcept { return m_B[i]; } constexpr const_reference operator[]( size_type i) const noexcept { return m_B[i]; }; bool operator==(const bounds &rhs) const noexcept; bool operator!=(const bounds &rhs) const noexcept; bounds operator+(const index &rhs) const noexcept; bounds operator-(const index &rhs) const noexcept; bounds &operator+=(const index &rhs) noexcept; bounds &operator-=(const index &rhs) noexcept; constexpr size_type size() const noexcept; bool contains(const index &idx) const noexcept; //bounds_iterator begin() const noexcept; //bounds_iterator end() const noexcept; }; //bounds operator+(const index& lhs, const bounds& rhs) noexcept; template class index { public: static constexpr int rank = Rank; using reference = ptrdiff_t &; using const_reference = const ptrdiff_t &; using size_type = size_t; using value_type = ptrdiff_t; // For index: constexpr index() noexcept; constexpr index(value_type) noexcept; constexpr index(const initializer_list &) noexcept; constexpr index(const index &) noexcept; index &operator=(const index &) noexcept; reference operator[](size_type component_idx) noexcept; constexpr const_reference operator[](size_type component_idx) const noexcept; bool operator==(const index &rhs) const noexcept; bool operator!=(const index &rhs) const noexcept; index operator+(const index &rhs) const noexcept; index operator-(const index &rhs) const noexcept; index &operator+=(const index &rhs) noexcept; index &operator-=(const index &rhs) noexcept; index &operator++() noexcept; index operator++(int) noexcept; index &operator--() noexcept; index operator--(int) noexcept; index operator+() const noexcept; index operator-() const noexcept; }; /// Mock-up of future atd::(experimental::)span. /// Supports only what we need for THist, e.g. Rank := 1. template class span { public: static constexpr int rank = Rank; using index_type = index; using bounds_type = bounds; using size_type = typename bounds_type::size_type; using value_type = ValueType; using pointer = typename std::add_pointer_t; using reference = typename std::add_lvalue_reference_t; constexpr span() noexcept; constexpr explicit span(std::vector &cont) noexcept; template constexpr explicit span(ArrayType &data) noexcept; template constexpr span(const span &rhs) noexcept; template constexpr span(bounds_type bounds, Container &cont) noexcept; constexpr span(bounds_type bounds, pointer data) noexcept; template span &operator=(const span &rhs) noexcept; constexpr bounds_type bounds() const noexcept; constexpr size_type size() const noexcept; constexpr index_type stride() const noexcept; constexpr pointer data() const noexcept; constexpr reference operator[](const index_type& idx) const noexcept; }; } #endif // too complex! #endif