span.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. Copyright 2019-2023 Glen Joseph Fernandes
  3. (glenjofe@gmail.com)
  4. Distributed under the Boost Software License, Version 1.0.
  5. (http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #ifndef BOOST_CORE_SPAN_HPP
  8. #define BOOST_CORE_SPAN_HPP
  9. #include <boost/core/detail/assert.hpp>
  10. #include <boost/core/data.hpp>
  11. #include <array>
  12. #include <iterator>
  13. #include <type_traits>
  14. namespace boost {
  15. constexpr std::size_t dynamic_extent = static_cast<std::size_t>(-1);
  16. template<class T, std::size_t E = dynamic_extent>
  17. class span;
  18. namespace detail {
  19. template<class U, class T, class = void>
  20. struct span_convertible {
  21. static constexpr bool value = false;
  22. };
  23. template<class U, class T>
  24. struct span_convertible<U, T, typename
  25. std::enable_if<std::is_convertible<U(*)[], T(*)[]>::value>::type> {
  26. static constexpr bool value = true;
  27. };
  28. template<std::size_t E, std::size_t N>
  29. struct span_capacity {
  30. static constexpr bool value = E == boost::dynamic_extent || E == N;
  31. };
  32. template<class T, std::size_t E, class U, std::size_t N>
  33. struct span_compatible {
  34. static constexpr bool value = span_capacity<E, N>::value &&
  35. span_convertible<U, T>::value;
  36. };
  37. template<class T>
  38. using span_uncvref = typename std::remove_cv<typename
  39. std::remove_reference<T>::type>::type;
  40. template<class>
  41. struct span_is_span {
  42. static constexpr bool value = false;
  43. };
  44. template<class T, std::size_t E>
  45. struct span_is_span<boost::span<T, E> > {
  46. static constexpr bool value = true;
  47. };
  48. template<class T>
  49. struct span_is_array {
  50. static constexpr bool value = false;
  51. };
  52. template<class T, std::size_t N>
  53. struct span_is_array<std::array<T, N> > {
  54. static constexpr bool value = true;
  55. };
  56. template<class T>
  57. using span_ptr = decltype(boost::data(std::declval<T&>()));
  58. template<class, class = void>
  59. struct span_data { };
  60. template<class T>
  61. struct span_data<T,
  62. typename std::enable_if<std::is_pointer<span_ptr<T> >::value>::type> {
  63. typedef typename std::remove_pointer<span_ptr<T> >::type type;
  64. };
  65. template<class, class, class = void>
  66. struct span_has_data {
  67. static constexpr bool value = false;
  68. };
  69. template<class R, class T>
  70. struct span_has_data<R, T, typename std::enable_if<span_convertible<typename
  71. span_data<R>::type, T>::value>::type> {
  72. static constexpr bool value = true;
  73. };
  74. template<class, class = void>
  75. struct span_has_size {
  76. static constexpr bool value = false;
  77. };
  78. template<class R>
  79. struct span_has_size<R, typename
  80. std::enable_if<std::is_convertible<decltype(std::declval<R&>().size()),
  81. std::size_t>::value>::type> {
  82. static constexpr bool value = true;
  83. };
  84. template<class R, class T>
  85. struct span_is_range {
  86. static constexpr bool value = (std::is_const<T>::value ||
  87. std::is_lvalue_reference<R>::value) &&
  88. !span_is_span<span_uncvref<R> >::value &&
  89. !span_is_array<span_uncvref<R> >::value &&
  90. !std::is_array<span_uncvref<R> >::value &&
  91. span_has_data<R, T>::value &&
  92. span_has_size<R>::value;
  93. };
  94. template<std::size_t E, std::size_t N>
  95. struct span_implicit {
  96. static constexpr bool value = E == boost::dynamic_extent ||
  97. N != boost::dynamic_extent;
  98. };
  99. template<class T, std::size_t E, class U, std::size_t N>
  100. struct span_copyable {
  101. static constexpr bool value = (N == boost::dynamic_extent ||
  102. span_capacity<E, N>::value) && span_convertible<U, T>::value;
  103. };
  104. template<std::size_t E, std::size_t O>
  105. struct span_sub {
  106. static constexpr std::size_t value = E == boost::dynamic_extent ?
  107. boost::dynamic_extent : E - O;
  108. };
  109. template<class T, std::size_t E>
  110. struct span_store {
  111. constexpr span_store(T* p_, std::size_t) noexcept
  112. : p(p_) { }
  113. static constexpr std::size_t n = E;
  114. T* p;
  115. };
  116. template<class T>
  117. struct span_store<T, boost::dynamic_extent> {
  118. constexpr span_store(T* p_, std::size_t n_) noexcept
  119. : p(p_)
  120. , n(n_) { }
  121. T* p;
  122. std::size_t n;
  123. };
  124. template<class T, std::size_t E>
  125. struct span_bytes {
  126. static constexpr std::size_t value = sizeof(T) * E;
  127. };
  128. template<class T>
  129. struct span_bytes<T, boost::dynamic_extent> {
  130. static constexpr std::size_t value = boost::dynamic_extent;
  131. };
  132. } /* detail */
  133. template<class T, std::size_t E>
  134. class span {
  135. public:
  136. typedef T element_type;
  137. typedef typename std::remove_cv<T>::type value_type;
  138. typedef std::size_t size_type;
  139. typedef std::ptrdiff_t difference_type;
  140. typedef T* pointer;
  141. typedef const T* const_pointer;
  142. typedef T& reference;
  143. typedef const T& const_reference;
  144. typedef T* iterator;
  145. typedef const T* const_iterator;
  146. typedef std::reverse_iterator<T*> reverse_iterator;
  147. typedef std::reverse_iterator<const T*> const_reverse_iterator;
  148. static constexpr std::size_t extent = E;
  149. template<std::size_t N = E,
  150. typename std::enable_if<N == dynamic_extent || N == 0, int>::type = 0>
  151. constexpr span() noexcept
  152. : s_(0, 0) { }
  153. template<class I,
  154. typename std::enable_if<E == dynamic_extent &&
  155. detail::span_convertible<I, T>::value, int>::type = 0>
  156. constexpr span(I* f, size_type c)
  157. : s_(f, c) { }
  158. template<class I,
  159. typename std::enable_if<E != dynamic_extent &&
  160. detail::span_convertible<I, T>::value, int>::type = 0>
  161. explicit constexpr span(I* f, size_type c)
  162. : s_(f, c) { }
  163. template<class I, class L,
  164. typename std::enable_if<E == dynamic_extent &&
  165. detail::span_convertible<I, T>::value, int>::type = 0>
  166. constexpr span(I* f, L* l)
  167. : s_(f, l - f) { }
  168. template<class I, class L,
  169. typename std::enable_if<E != dynamic_extent &&
  170. detail::span_convertible<I, T>::value, int>::type = 0>
  171. explicit constexpr span(I* f, L* l)
  172. : s_(f, l - f) { }
  173. template<std::size_t N,
  174. typename std::enable_if<detail::span_capacity<E, N>::value,
  175. int>::type = 0>
  176. constexpr span(typename std::enable_if<true, T>::type (&a)[N]) noexcept
  177. : s_(a, N) { }
  178. template<class U, std::size_t N,
  179. typename std::enable_if<detail::span_compatible<T, E, U, N>::value,
  180. int>::type = 0>
  181. constexpr span(std::array<U, N>& a) noexcept
  182. : s_(a.data(), N) { }
  183. template<class U, std::size_t N,
  184. typename std::enable_if<detail::span_compatible<T, E, const U,
  185. N>::value, int>::type = 0>
  186. constexpr span(const std::array<U, N>& a) noexcept
  187. : s_(a.data(), N) { }
  188. template<class R,
  189. typename std::enable_if<E == dynamic_extent &&
  190. detail::span_is_range<R, T>::value, int>::type = 0>
  191. constexpr span(R&& r) noexcept(noexcept(boost::data(r)) &&
  192. noexcept(r.size()))
  193. : s_(boost::data(r), r.size()) { }
  194. template<class R,
  195. typename std::enable_if<E != dynamic_extent &&
  196. detail::span_is_range<R, T>::value, int>::type = 0>
  197. explicit constexpr span(R&& r) noexcept(noexcept(boost::data(r)) &&
  198. noexcept(r.size()))
  199. : s_(boost::data(r), r.size()) { }
  200. template<class U, std::size_t N,
  201. typename std::enable_if<detail::span_implicit<E, N>::value &&
  202. detail::span_copyable<T, E, U, N>::value, int>::type = 0>
  203. constexpr span(const span<U, N>& s) noexcept
  204. : s_(s.data(), s.size()) { }
  205. template<class U, std::size_t N,
  206. typename std::enable_if<!detail::span_implicit<E, N>::value &&
  207. detail::span_copyable<T, E, U, N>::value, int>::type = 0>
  208. explicit constexpr span(const span<U, N>& s) noexcept
  209. : s_(s.data(), s.size()) { }
  210. template<std::size_t C>
  211. constexpr span<T, C> first() const {
  212. static_assert(C <= E, "Count <= Extent");
  213. return span<T, C>(s_.p, C);
  214. }
  215. template<std::size_t C>
  216. constexpr span<T, C> last() const {
  217. static_assert(C <= E, "Count <= Extent");
  218. return span<T, C>(s_.p + (s_.n - C), C);
  219. }
  220. template<std::size_t O, std::size_t C = dynamic_extent>
  221. constexpr typename std::enable_if<C == dynamic_extent,
  222. span<T, detail::span_sub<E, O>::value> >::type subspan() const {
  223. static_assert(O <= E, "Offset <= Extent");
  224. return span<T, detail::span_sub<E, O>::value>(s_.p + O, s_.n - O);
  225. }
  226. template<std::size_t O, std::size_t C = dynamic_extent>
  227. constexpr typename std::enable_if<C != dynamic_extent,
  228. span<T, C> >::type subspan() const {
  229. static_assert(O <= E && C <= E - O,
  230. "Offset <= Extent && Count <= Extent - Offset");
  231. return span<T, C>(s_.p + O, C);
  232. }
  233. constexpr span<T, dynamic_extent> first(size_type c) const {
  234. return BOOST_CORE_DETAIL_ASSERT(c <= size()),
  235. span<T, dynamic_extent>(s_.p, c);
  236. }
  237. constexpr span<T, dynamic_extent> last(size_type c) const {
  238. return BOOST_CORE_DETAIL_ASSERT(c <= size()),
  239. span<T, dynamic_extent>(s_.p + (s_.n - c), c);
  240. }
  241. constexpr span<T, dynamic_extent> subspan(size_type o,
  242. size_type c = dynamic_extent) const {
  243. return BOOST_CORE_DETAIL_ASSERT(o <= size() &&
  244. (c == dynamic_extent || c + o <= size())),
  245. span<T, dynamic_extent>(s_.p + o,
  246. c == dynamic_extent ? s_.n - o : c);
  247. }
  248. constexpr size_type size() const noexcept {
  249. return s_.n;
  250. }
  251. constexpr size_type size_bytes() const noexcept {
  252. return s_.n * sizeof(T);
  253. }
  254. constexpr bool empty() const noexcept {
  255. return s_.n == 0;
  256. }
  257. constexpr reference operator[](size_type i) const {
  258. return BOOST_CORE_DETAIL_ASSERT(i < size()), s_.p[i];
  259. }
  260. constexpr reference front() const {
  261. return BOOST_CORE_DETAIL_ASSERT(!empty()), *s_.p;
  262. }
  263. constexpr reference back() const {
  264. return BOOST_CORE_DETAIL_ASSERT(!empty()), s_.p[s_.n - 1];
  265. }
  266. constexpr pointer data() const noexcept {
  267. return s_.p;
  268. }
  269. constexpr iterator begin() const noexcept {
  270. return s_.p;
  271. }
  272. constexpr iterator end() const noexcept {
  273. return s_.p + s_.n;
  274. }
  275. constexpr reverse_iterator rbegin() const noexcept {
  276. return reverse_iterator(s_.p + s_.n);
  277. }
  278. constexpr reverse_iterator rend() const noexcept {
  279. return reverse_iterator(s_.p);
  280. }
  281. constexpr const_iterator cbegin() const noexcept {
  282. return s_.p;
  283. }
  284. constexpr const_iterator cend() const noexcept {
  285. return s_.p + s_.n;
  286. }
  287. constexpr const_reverse_iterator crbegin() const noexcept {
  288. return const_reverse_iterator(s_.p + s_.n);
  289. }
  290. constexpr const_reverse_iterator crend() const noexcept {
  291. return const_reverse_iterator(s_.p);
  292. }
  293. private:
  294. detail::span_store<T, E> s_;
  295. };
  296. #if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
  297. template<class T, std::size_t E>
  298. constexpr std::size_t span<T, E>::extent;
  299. #endif
  300. #ifdef __cpp_deduction_guides
  301. template<class I, class L>
  302. span(I*, L) -> span<I>;
  303. template<class T, std::size_t N>
  304. span(T(&)[N]) -> span<T, N>;
  305. template<class T, std::size_t N>
  306. span(std::array<T, N>&) -> span<T, N>;
  307. template<class T, std::size_t N>
  308. span(const std::array<T, N>&) -> span<const T, N>;
  309. template<class R>
  310. span(R&&) -> span<typename detail::span_data<R>::type>;
  311. template<class T, std::size_t E>
  312. span(span<T, E>) -> span<T, E>;
  313. #endif
  314. #ifdef __cpp_lib_byte
  315. template<class T, std::size_t E>
  316. inline span<const std::byte, detail::span_bytes<T, E>::value>
  317. as_bytes(span<T, E> s) noexcept
  318. {
  319. return span<const std::byte, detail::span_bytes<T,
  320. E>::value>(reinterpret_cast<const std::byte*>(s.data()),
  321. s.size_bytes());
  322. }
  323. template<class T, std::size_t E>
  324. inline typename std::enable_if<!std::is_const<T>::value,
  325. span<std::byte, detail::span_bytes<T, E>::value> >::type
  326. as_writable_bytes(span<T, E> s) noexcept
  327. {
  328. return span<std::byte, detail::span_bytes<T,
  329. E>::value>(reinterpret_cast<std::byte*>(s.data()), s.size_bytes());
  330. }
  331. #endif
  332. } /* boost */
  333. #endif