// Copyright 2019 Hans Dembinski // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_HISTOGRAM_DETAIL_SPAN_HPP #define BOOST_HISTOGRAM_DETAIL_SPAN_HPP #ifdef __has_include #if __has_include() #include #ifdef __cpp_lib_span #if __cpp_lib_span >= 201902 #define BOOST_HISTOGRAM_DETAIL_HAS_STD_SPAN #endif #endif #endif #endif #ifdef BOOST_HISTOGRAM_DETAIL_HAS_STD_SPAN #include namespace boost { namespace histogram { namespace detail { using std::span; } // namespace detail } // namespace histogram } // namespace boost #else // C++17 span not available, so we use our implementation // to be replaced by boost::span #include #include #include #include #include #include namespace boost { namespace histogram { namespace detail { namespace dtl = ::boost::histogram::detail; static constexpr std::size_t dynamic_extent = ~static_cast(0); template class span_base { public: constexpr T* data() noexcept { return begin_; } constexpr const T* data() const noexcept { return begin_; } constexpr std::size_t size() const noexcept { return N; } protected: constexpr span_base(T* b, std::size_t s) noexcept : begin_(b) { (void)s; assert(N == s); } constexpr void set(T* b, std::size_t s) noexcept { (void)s; begin_ = b; assert(N == s); } private: T* begin_; }; template class span_base { public: constexpr span_base() noexcept : begin_(nullptr), size_(0) {} constexpr T* data() noexcept { return begin_; } constexpr const T* data() const noexcept { return begin_; } constexpr std::size_t size() const noexcept { return size_; } protected: constexpr span_base(T* b, std::size_t s) noexcept : begin_(b), size_(s) {} constexpr void set(T* b, std::size_t s) noexcept { begin_ = b; size_ = s; } private: T* begin_; std::size_t size_; }; template class span : public span_base { using base = span_base; public: using element_type = T; using value_type = std::remove_cv_t; using index_type = std::size_t; using difference_type = std::ptrdiff_t; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; static constexpr std::size_t extent = Extent; using base::base; constexpr span(pointer first, pointer last) : span(first, static_cast(last - first)) { assert(extent == dynamic_extent || static_cast(extent) == (last - first)); } constexpr span(pointer ptr, index_type count) : base(ptr, count) {} template constexpr span(element_type (&arr)[N]) noexcept : span(dtl::data(arr), N) { static_assert(extent == dynamic_extent || extent == N, "static sizes do not match"); } template > constexpr span(std::array& arr) noexcept : span(dtl::data(arr), N) {} template > constexpr span(const std::array& arr) noexcept : span(dtl::data(arr), N) {} template ()), dtl::data(std::declval())), pointer>::value> > constexpr span(const Container& cont) : span(dtl::data(cont), dtl::size(cont)) {} template ()), dtl::data(std::declval())), pointer>::value> > constexpr span(Container& cont) : span(dtl::data(cont), dtl::size(cont)) {} template ::value)> > constexpr span(const span& s) noexcept : span(s.data(), s.size()) {} template ::value)> > constexpr span(span& s) noexcept : span(s.data(), s.size()) {} constexpr span(const span& other) noexcept = default; constexpr iterator begin() { return base::data(); } constexpr const_iterator begin() const { return base::data(); } constexpr const_iterator cbegin() const { return base::data(); } constexpr iterator end() { return base::data() + base::size(); } constexpr const_iterator end() const { return base::data() + base::size(); } constexpr const_iterator cend() const { return base::data() + base::size(); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return reverse_iterator(end()); } const_reverse_iterator crbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return reverse_iterator(begin()); } const_reverse_iterator crend() { return reverse_iterator(begin()); } constexpr reference front() { return *base::data(); } constexpr reference back() { return *(base::data() + base::size() - 1); } constexpr reference operator[](index_type idx) const { return base::data()[idx]; } constexpr std::size_t size_bytes() const noexcept { return base::size() * sizeof(element_type); } constexpr bool empty() const noexcept { return base::size() == 0; } template constexpr span first() const { assert(Count <= base::size()); return span(base::data(), Count); } constexpr span first(std::size_t count) const { assert(count <= base::size()); return span(base::data(), count); } template constexpr span last() const { assert(Count <= base::size()); return span(base::data() + base::size() - Count, Count); } constexpr span last(std::size_t count) const { assert(count <= base::size()); return span(base::data() + base::size() - count, count); } template constexpr span subspan() const { assert(Offset <= base::size()); constexpr std::size_t E = (Count != dynamic_extent ? Count : (extent != dynamic_extent ? extent - Offset : dynamic_extent)); assert(E == dynamic_extent || E <= base::size()); return span(base::data() + Offset, Count == dynamic_extent ? base::size() - Offset : Count); } constexpr span subspan( std::size_t offset, std::size_t count = dynamic_extent) const { assert(offset <= base::size()); const std::size_t s = count == dynamic_extent ? base::size() - offset : count; assert(s <= base::size()); return span(base::data() + offset, s); } }; } // namespace detail } // namespace histogram } // namespace boost #endif #include #include namespace boost { namespace histogram { namespace detail { namespace dtl = ::boost::histogram::detail; template auto make_span(T* begin, T* end) { return dtl::span{begin, end}; } template auto make_span(T* begin, std::size_t size) { return dtl::span{begin, size}; } template ()), dtl::data(std::declval()))> auto make_span(const Container& cont) { return make_span(dtl::data(cont), dtl::size(cont)); } template auto make_span(T (&arr)[N]) { return dtl::span(arr, N); } } // namespace detail } // namespace histogram } // namespace boost #endif