span.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_DETAIL_SPAN_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_SPAN_HPP
  8. #if __cpp_constexpr >= 201603 && __cpp_deduction_guides >= 201703 && \
  9. __cpp_lib_nonmember_container_access >= 201411 && __has_include(<span>)
  10. #include <span>
  11. namespace boost {
  12. namespace histogram {
  13. namespace detail {
  14. using std::span;
  15. } // namespace detail
  16. } // namespace histogram
  17. } // namespace boost
  18. #else // C++17 span not available, so we use our implementation
  19. // to be replaced by boost::span
  20. #include <array>
  21. #include <boost/assert.hpp>
  22. #include <boost/histogram/detail/non_member_container_access.hpp>
  23. #include <initializer_list>
  24. #include <iterator>
  25. #include <type_traits>
  26. namespace boost {
  27. namespace histogram {
  28. namespace detail {
  29. namespace dtl = ::boost::histogram::detail;
  30. static constexpr std::size_t dynamic_extent = ~static_cast<std::size_t>(0);
  31. template <class T, std::size_t N>
  32. class span_base {
  33. public:
  34. constexpr T* data() noexcept { return begin_; }
  35. constexpr const T* data() const noexcept { return begin_; }
  36. constexpr std::size_t size() const noexcept { return N; }
  37. protected:
  38. constexpr span_base(T* b, std::size_t s) noexcept : begin_(b) { BOOST_ASSERT(N == s); }
  39. constexpr void set(T* b, std::size_t s) noexcept {
  40. begin_ = b;
  41. BOOST_ASSERT(N == s);
  42. }
  43. private:
  44. T* begin_;
  45. };
  46. template <class T>
  47. class span_base<T, dynamic_extent> {
  48. public:
  49. constexpr T* data() noexcept { return begin_; }
  50. constexpr const T* data() const noexcept { return begin_; }
  51. constexpr std::size_t size() const noexcept { return size_; }
  52. protected:
  53. constexpr span_base(T* b, std::size_t s) noexcept : begin_(b), size_(s) {}
  54. constexpr void set(T* b, std::size_t s) noexcept {
  55. begin_ = b;
  56. size_ = s;
  57. }
  58. private:
  59. T* begin_;
  60. std::size_t size_;
  61. };
  62. template <class T, std::size_t Extent = dynamic_extent>
  63. class span : public span_base<T, Extent> {
  64. using base = span_base<T, Extent>;
  65. public:
  66. using element_type = T;
  67. using value_type = std::remove_cv_t<T>;
  68. using index_type = std::size_t;
  69. using difference_type = std::ptrdiff_t;
  70. using pointer = T*;
  71. using const_pointer = const T*;
  72. using reference = T&;
  73. using const_reference = const T&;
  74. using iterator = pointer;
  75. using const_iterator = const_pointer;
  76. using reverse_iterator = std::reverse_iterator<iterator>;
  77. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  78. static constexpr std::size_t extent = Extent;
  79. template <std::size_t _ = extent,
  80. class = std::enable_if_t<(_ == 0 || _ == dynamic_extent)> >
  81. constexpr span() noexcept : base(nullptr, 0) {}
  82. constexpr span(pointer first, pointer last)
  83. : span(first, static_cast<std::size_t>(last - first)) {
  84. BOOST_ASSERT(extent == dynamic_extent ||
  85. static_cast<difference_type>(extent) == (last - first));
  86. }
  87. constexpr span(pointer ptr, index_type count) : base(ptr, count) {}
  88. template <std::size_t N>
  89. constexpr span(element_type (&arr)[N]) noexcept : span(dtl::data(arr), N) {
  90. static_assert(extent == dynamic_extent || extent == N, "static sizes do not match");
  91. }
  92. template <std::size_t N,
  93. class = std::enable_if_t<(extent == dynamic_extent || extent == N)> >
  94. constexpr span(std::array<value_type, N>& arr) noexcept : span(dtl::data(arr), N) {}
  95. template <std::size_t N,
  96. class = std::enable_if_t<(extent == dynamic_extent || extent == N)> >
  97. constexpr span(const std::array<value_type, N>& arr) noexcept
  98. : span(dtl::data(arr), N) {}
  99. template <class Container, class = std::enable_if_t<std::is_convertible<
  100. decltype(dtl::size(std::declval<Container>()),
  101. dtl::data(std::declval<Container>())),
  102. pointer>::value> >
  103. constexpr span(const Container& cont) : span(dtl::data(cont), dtl::size(cont)) {}
  104. template <class Container, class = std::enable_if_t<std::is_convertible<
  105. decltype(dtl::size(std::declval<Container>()),
  106. dtl::data(std::declval<Container>())),
  107. pointer>::value> >
  108. constexpr span(Container& cont) : span(dtl::data(cont), dtl::size(cont)) {}
  109. template <class U, std::size_t N,
  110. class = std::enable_if_t<((extent == dynamic_extent || extent == N) &&
  111. std::is_convertible<U, element_type>::value)> >
  112. constexpr span(const span<U, N>& s) noexcept : span(s.data(), s.size()) {}
  113. template <class U, std::size_t N,
  114. class = std::enable_if_t<((extent == dynamic_extent || extent == N) &&
  115. std::is_convertible<U, element_type>::value)> >
  116. constexpr span(span<U, N>& s) noexcept : span(s.data(), s.size()) {}
  117. constexpr span(const span& other) noexcept = default;
  118. constexpr iterator begin() { return base::data(); }
  119. constexpr const_iterator begin() const { return base::data(); }
  120. constexpr const_iterator cbegin() const { return base::data(); }
  121. constexpr iterator end() { return base::data() + base::size(); }
  122. constexpr const_iterator end() const { return base::data() + base::size(); }
  123. constexpr const_iterator cend() const { return base::data() + base::size(); }
  124. reverse_iterator rbegin() { return reverse_iterator(end()); }
  125. const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
  126. const_reverse_iterator crbegin() { return reverse_iterator(end()); }
  127. reverse_iterator rend() { return reverse_iterator(begin()); }
  128. const_reverse_iterator rend() const { return reverse_iterator(begin()); }
  129. const_reverse_iterator crend() { return reverse_iterator(begin()); }
  130. constexpr reference front() { *base::data(); }
  131. constexpr reference back() { *(base::data() + base::size() - 1); }
  132. constexpr reference operator[](index_type idx) const { return base::data()[idx]; }
  133. constexpr std::size_t size_bytes() const noexcept {
  134. return base::size() * sizeof(element_type);
  135. }
  136. constexpr bool empty() const noexcept { return base::size() == 0; }
  137. template <std::size_t Count>
  138. constexpr span<element_type, Count> first() const {
  139. BOOST_ASSERT(Count <= base::size());
  140. return span<element_type, Count>(base::data(), Count);
  141. }
  142. constexpr span<element_type, dynamic_extent> first(std::size_t count) const {
  143. BOOST_ASSERT(count <= base::size());
  144. return span<element_type, dynamic_extent>(base::data(), count);
  145. }
  146. template <std::size_t Count>
  147. constexpr span<element_type, Count> last() const {
  148. BOOST_ASSERT(Count <= base::size());
  149. return span<element_type, Count>(base::data() + base::size() - Count, Count);
  150. }
  151. constexpr span<element_type, dynamic_extent> last(std::size_t count) const {
  152. BOOST_ASSERT(count <= base::size());
  153. return span<element_type, dynamic_extent>(base::data() + base::size() - count, count);
  154. }
  155. template <std::size_t Offset, std::size_t Count = dynamic_extent>
  156. constexpr span<element_type,
  157. (Count != dynamic_extent
  158. ? Count
  159. : (extent != dynamic_extent ? extent - Offset : dynamic_extent))>
  160. subspan() const {
  161. BOOST_ASSERT(Offset <= base::size());
  162. constexpr std::size_t E =
  163. (Count != dynamic_extent
  164. ? Count
  165. : (extent != dynamic_extent ? extent - Offset : dynamic_extent));
  166. BOOST_ASSERT(E == dynamic_extent || E <= base::size());
  167. return span<element_type, E>(base::data() + Offset,
  168. Count == dynamic_extent ? base::size() - Offset : Count);
  169. }
  170. constexpr span<element_type, dynamic_extent> subspan(
  171. std::size_t offset, std::size_t count = dynamic_extent) const {
  172. BOOST_ASSERT(offset <= base::size());
  173. const std::size_t s = count == dynamic_extent ? base::size() - offset : count;
  174. BOOST_ASSERT(s <= base::size());
  175. return span<element_type, dynamic_extent>(base::data() + offset, s);
  176. }
  177. };
  178. } // namespace detail
  179. } // namespace histogram
  180. } // namespace boost
  181. #endif
  182. #include <boost/histogram/detail/non_member_container_access.hpp>
  183. #include <utility>
  184. namespace boost {
  185. namespace histogram {
  186. namespace detail {
  187. namespace dtl = ::boost::histogram::detail;
  188. template <class T>
  189. auto make_span(T* begin, T* end) {
  190. return dtl::span<T>{begin, end};
  191. }
  192. template <class T>
  193. auto make_span(T* begin, std::size_t size) {
  194. return dtl::span<T>{begin, size};
  195. }
  196. template <class Container, class = decltype(dtl::size(std::declval<Container>()),
  197. dtl::data(std::declval<Container>()))>
  198. auto make_span(const Container& cont) {
  199. return make_span(dtl::data(cont), dtl::size(cont));
  200. }
  201. template <class T, std::size_t N>
  202. auto make_span(T (&arr)[N]) {
  203. return dtl::span<T, N>(arr, N);
  204. }
  205. } // namespace detail
  206. } // namespace histogram
  207. } // namespace boost
  208. #endif