You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

414 lines
15KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Casey Carter 2016-2017
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_VIEW_SPAN_HPP
  14. #define RANGES_V3_VIEW_SPAN_HPP
  15. #include <cstddef>
  16. #include <meta/meta.hpp>
  17. #include <range/v3/range_fwd.hpp>
  18. #include <range/v3/algorithm/equal.hpp>
  19. #include <range/v3/algorithm/lexicographical_compare.hpp>
  20. #include <range/v3/iterator/reverse_iterator.hpp>
  21. #include <range/v3/range/access.hpp>
  22. #include <range/v3/range/concepts.hpp>
  23. #include <range/v3/range/primitives.hpp>
  24. #include <range/v3/range/traits.hpp>
  25. #include <range/v3/view/interface.hpp>
  26. namespace ranges
  27. {
  28. /// \cond
  29. namespace detail
  30. {
  31. using span_index_t = std::ptrdiff_t;
  32. } // namespace detail
  33. /// \endcond
  34. constexpr detail::span_index_t dynamic_extent = -1;
  35. /// \cond
  36. namespace detail
  37. {
  38. template<typename To, typename From>
  39. constexpr auto narrow_cast(From from) noexcept -> CPP_ret(To)( //
  40. requires integral<To> && integral<From>)
  41. {
  42. using C = common_type_t<To, From>;
  43. return RANGES_EXPECT((from > 0) == (static_cast<To>(from) > 0)),
  44. RANGES_EXPECT(static_cast<C>(from) ==
  45. static_cast<C>(static_cast<To>(from))),
  46. static_cast<To>(from);
  47. }
  48. template<typename T>
  49. constexpr span_index_t byte_size(span_index_t n) noexcept
  50. {
  51. return n == dynamic_extent ? dynamic_extent
  52. : (RANGES_EXPECT(n >= 0),
  53. RANGES_EXPECT(narrow_cast<std::size_t>(n) <=
  54. PTRDIFF_MAX / sizeof(T)),
  55. n * narrow_cast<span_index_t>(sizeof(T)));
  56. }
  57. template<span_index_t N>
  58. struct span_extent
  59. {
  60. CPP_assert(N >= 0);
  61. constexpr span_extent() noexcept = default;
  62. constexpr span_extent(span_index_t size) noexcept
  63. // this constructor does nothing, the delegation exists only
  64. // to provide a place for the contract check expression.
  65. : span_extent{(RANGES_EXPECT(size == N), tag{})}
  66. {}
  67. constexpr span_index_t size() const noexcept
  68. {
  69. return N;
  70. }
  71. private:
  72. struct tag
  73. {};
  74. constexpr span_extent(tag) noexcept
  75. {}
  76. };
  77. template<>
  78. struct span_extent<dynamic_extent>
  79. {
  80. span_extent() = default;
  81. constexpr span_extent(span_index_t size) noexcept
  82. : size_{((void)RANGES_EXPECT(size >= 0), size)}
  83. {}
  84. constexpr span_index_t size() const noexcept
  85. {
  86. return size_;
  87. }
  88. private:
  89. span_index_t size_ = 0;
  90. };
  91. constexpr span_index_t subspan_extent(span_index_t Extent, span_index_t Offset,
  92. span_index_t Count) noexcept
  93. {
  94. return Count == dynamic_extent && Extent != dynamic_extent ? Extent - Offset
  95. : Count;
  96. }
  97. } // namespace detail
  98. // clang-format off
  99. CPP_def
  100. (
  101. template(typename Rng, typename T)
  102. concept span_compatible_range,
  103. sized_range<Rng> && contiguous_range<Rng> &&
  104. detail::is_convertible<
  105. detail::element_t<Rng>(*)[],
  106. T(*)[]>::value
  107. );
  108. CPP_def
  109. (
  110. template(typename Rng, detail::span_index_t N)
  111. (concept span_dynamic_conversion)(Rng, N),
  112. N == dynamic_extent ||
  113. range_cardinality<Rng>::value < cardinality()
  114. );
  115. CPP_def
  116. (
  117. template(typename Rng, detail::span_index_t N)
  118. (concept span_static_conversion)(Rng, N),
  119. N != dynamic_extent && range_cardinality<Rng>::value == N
  120. );
  121. // clang-format on
  122. /// \endcond
  123. template<typename T, detail::span_index_t N = dynamic_extent>
  124. struct RANGES_EMPTY_BASES span
  125. : public view_interface<
  126. span<T, N>, (N == dynamic_extent ? finite : static_cast<cardinality>(N))>
  127. , public detail::span_extent<N>
  128. {
  129. CPP_assert(std::is_object<T>::value);
  130. using element_type = T;
  131. using value_type = meta::_t<std::remove_cv<T>>;
  132. using index_type = detail::span_index_t;
  133. using difference_type = index_type;
  134. using pointer = T *;
  135. using reference = T &;
  136. using iterator = T *;
  137. using reverse_iterator = ranges::reverse_iterator<iterator>;
  138. static constexpr index_type extent = N;
  139. constexpr span() noexcept = default;
  140. constexpr span(pointer ptr, index_type cnt) noexcept
  141. : detail::span_extent<N>{(RANGES_EXPECT(cnt >= 0), cnt)}
  142. , data_{(RANGES_EXPECT(0 == cnt || ptr != nullptr), ptr)}
  143. {}
  144. template<typename = void> // Artificially templatize so that the other
  145. // constructor is preferred for {ptr, 0}
  146. constexpr span(pointer first, pointer last) noexcept
  147. : span{first, last - first}
  148. {}
  149. CPP_template(typename Rng)( //
  150. requires(!defer::same_as<span, uncvref_t<Rng>>) &&
  151. defer::span_compatible_range<Rng, T> &&
  152. defer::span_dynamic_conversion<Rng, N>) //
  153. constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng),
  154. ranges::size(rng)))
  155. : span{ranges::data(rng), detail::narrow_cast<index_type>(ranges::size(rng))}
  156. {}
  157. CPP_template(typename Rng)( //
  158. requires(!defer::same_as<span, uncvref_t<Rng>>) &&
  159. defer::span_compatible_range<Rng, T> &&
  160. defer::span_static_conversion<Rng, N>) //
  161. constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng)))
  162. : span{ranges::data(rng), N}
  163. {}
  164. template<index_type Count>
  165. constexpr span<T, Count> first() const noexcept
  166. {
  167. static_assert(Count >= 0, "Count of elements to extract cannot be negative.");
  168. static_assert(
  169. N == dynamic_extent || Count <= N,
  170. "Count of elements to extract must be less than the static span extent.");
  171. return RANGES_EXPECT(Count <= size()),
  172. RANGES_EXPECT(Count == 0 || data_ != nullptr),
  173. span<T, Count>{data_, Count};
  174. }
  175. constexpr span<T> first(index_type cnt) const noexcept
  176. {
  177. return RANGES_EXPECT(cnt >= 0 && cnt <= size()),
  178. RANGES_EXPECT(cnt == 0 || data_ != nullptr), span<T>{data_, cnt};
  179. }
  180. template<index_type Count>
  181. constexpr span<T, Count> last() const noexcept
  182. {
  183. static_assert(Count >= 0, "Count of elements to extract cannot be negative.");
  184. static_assert(
  185. N == dynamic_extent || Count <= N,
  186. "Count of elements to extract must be less than the static span extent.");
  187. return RANGES_EXPECT(Count <= size()),
  188. RANGES_EXPECT((Count == 0 && size() == 0) || data_ != nullptr),
  189. span<T, Count>{data_ + size() - Count, Count};
  190. }
  191. constexpr span<T> last(index_type cnt) const noexcept
  192. {
  193. return RANGES_EXPECT(cnt >= 0 && cnt <= size()),
  194. RANGES_EXPECT((cnt == 0 && size() == 0) || data_ != nullptr),
  195. span<T>{data_ + size() - cnt, cnt};
  196. }
  197. template<index_type Offset, index_type Count>
  198. constexpr span<T, detail::subspan_extent(N, Offset, Count)> subspan() const
  199. noexcept
  200. {
  201. static_assert(Offset >= 0,
  202. "Offset of first element to extract cannot be negative.");
  203. static_assert(Count >= dynamic_extent,
  204. "Count of elements to extract cannot be negative.");
  205. static_assert(
  206. N == dynamic_extent ||
  207. N >= Offset + (Count == dynamic_extent ? 0 : Count),
  208. "Sequence of elements to extract must be within the static span extent.");
  209. return RANGES_EXPECT(size() >=
  210. Offset + (Count == dynamic_extent ? 0 : Count)),
  211. RANGES_EXPECT((Offset == 0 && Count <= 0) || data_ != nullptr),
  212. span<T, detail::subspan_extent(N, Offset, Count)>{
  213. data_ + Offset, Count == dynamic_extent ? size() - Offset : Count};
  214. }
  215. template<index_type Offset>
  216. constexpr span<T, (N >= Offset ? N - Offset : dynamic_extent)> subspan() const
  217. noexcept
  218. {
  219. static_assert(Offset >= 0,
  220. "Offset of first element to extract cannot be negative.");
  221. static_assert(N == dynamic_extent || N >= Offset,
  222. "Offset of first element to extract must be within the static "
  223. "span extent.");
  224. return RANGES_EXPECT(size() >= Offset),
  225. RANGES_EXPECT((Offset == 0 && size() == 0) || data_ != nullptr),
  226. span < T,
  227. N >= Offset ? N - Offset
  228. : dynamic_extent > {data_ + Offset, size() - Offset};
  229. }
  230. constexpr span<T, dynamic_extent> subspan(index_type offset) const noexcept
  231. {
  232. return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(size() >= offset),
  233. RANGES_EXPECT((offset == 0 && size() == 0) || data_ != nullptr),
  234. span<T, dynamic_extent>{data_ + offset, size() - offset};
  235. }
  236. constexpr span<T, dynamic_extent> subspan(index_type offset,
  237. index_type cnt) const noexcept
  238. {
  239. return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(cnt >= 0),
  240. RANGES_EXPECT(size() >= offset + cnt),
  241. RANGES_EXPECT((offset == 0 && cnt == 0) || data_ != nullptr),
  242. span<T, dynamic_extent>{data_ + offset, cnt};
  243. }
  244. constexpr pointer data() const noexcept
  245. {
  246. return data_;
  247. }
  248. using detail::span_extent<N>::size;
  249. constexpr index_type size_bytes() const noexcept
  250. {
  251. return detail::byte_size<T>(size());
  252. }
  253. constexpr bool empty() const noexcept
  254. {
  255. return size() == 0;
  256. }
  257. constexpr reference operator[](index_type idx) const noexcept
  258. {
  259. return RANGES_EXPECT(idx >= 0), RANGES_EXPECT(idx < size()),
  260. RANGES_EXPECT(data_), data_[idx];
  261. }
  262. constexpr iterator begin() const noexcept
  263. {
  264. return RANGES_EXPECT(!size() || data_), data_;
  265. }
  266. constexpr iterator end() const noexcept
  267. {
  268. return RANGES_EXPECT(!size() || data_), data_ + size();
  269. }
  270. constexpr reverse_iterator rbegin() const noexcept
  271. {
  272. return reverse_iterator{end()};
  273. }
  274. constexpr reverse_iterator rend() const noexcept
  275. {
  276. return reverse_iterator{begin()};
  277. }
  278. template<typename U, index_type M>
  279. auto operator==(span<U, M> const & that) const -> CPP_ret(bool)( //
  280. requires equality_comparable_with<T, U>)
  281. {
  282. RANGES_EXPECT(!size() || data());
  283. RANGES_EXPECT(!that.size() || that.data());
  284. return ranges::equal(*this, that);
  285. }
  286. template<typename U, index_type M>
  287. auto operator!=(span<U, M> const & that) const -> CPP_ret(bool)( //
  288. requires equality_comparable_with<T, U>)
  289. {
  290. return !(*this == that);
  291. }
  292. template<typename U, index_type M>
  293. auto operator<(span<U, M> const & that) const -> CPP_ret(bool)( //
  294. requires totally_ordered_with<T, U>)
  295. {
  296. RANGES_EXPECT(!size() || data());
  297. RANGES_EXPECT(!that.size() || that.data());
  298. return ranges::lexicographical_compare(*this, that);
  299. }
  300. template<typename U, index_type M>
  301. auto operator>(span<U, M> const & that) const -> CPP_ret(bool)( //
  302. requires totally_ordered_with<T, U>)
  303. {
  304. return that < *this;
  305. }
  306. template<typename U, index_type M>
  307. auto operator<=(span<U, M> const & that) const -> CPP_ret(bool)( //
  308. requires totally_ordered_with<T, U>)
  309. {
  310. return !(that < *this);
  311. }
  312. template<typename U, index_type M>
  313. auto operator>=(span<U, M> const & that) const -> CPP_ret(bool)( //
  314. requires totally_ordered_with<T, U>)
  315. {
  316. return !(*this < that);
  317. }
  318. private:
  319. T * data_ = nullptr;
  320. };
  321. template<typename T, detail::span_index_t N>
  322. constexpr detail::span_index_t span<T, N>::extent;
  323. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  324. CPP_template(typename Rng)( //
  325. requires contiguous_range<Rng>) //
  326. span(Rng && rng)
  327. ->span<detail::element_t<Rng>, (range_cardinality<Rng>::value < cardinality()
  328. ? dynamic_extent
  329. : static_cast<detail::span_index_t>(
  330. range_cardinality<Rng>::value))>;
  331. #endif
  332. template<typename T, detail::span_index_t N>
  333. span<unsigned char const, detail::byte_size<T>(N)> as_bytes(span<T, N> s) noexcept
  334. {
  335. return {reinterpret_cast<unsigned char const *>(s.data()), s.size_bytes()};
  336. }
  337. template<typename T, detail::span_index_t N>
  338. span<unsigned char, detail::byte_size<T>(N)> as_writeable_bytes(span<T, N> s) noexcept
  339. {
  340. return {reinterpret_cast<unsigned char *>(s.data()), s.size_bytes()};
  341. }
  342. template<typename ElementType>
  343. constexpr span<ElementType> make_span(ElementType * ptr,
  344. detail::span_index_t cnt) noexcept
  345. {
  346. return span<ElementType>{ptr, cnt};
  347. }
  348. template<typename ElementType>
  349. constexpr span<ElementType> make_span(ElementType * first,
  350. ElementType * last) noexcept
  351. {
  352. return span<ElementType>{first, last};
  353. }
  354. CPP_template(typename Rng)( //
  355. requires contiguous_range<Rng> &&
  356. (range_cardinality<Rng>::value < cardinality())) //
  357. constexpr span<detail::element_t<Rng>> make_span(Rng && rng) noexcept(
  358. noexcept(ranges::data(rng), ranges::size(rng)))
  359. {
  360. return {ranges::data(rng),
  361. detail::narrow_cast<detail::span_index_t>(ranges::size(rng))};
  362. }
  363. CPP_template(typename Rng)( //
  364. requires contiguous_range<Rng> &&
  365. (range_cardinality<Rng>::value >= cardinality())) //
  366. constexpr span<
  367. detail::element_t<Rng>,
  368. static_cast<detail::span_index_t>(
  369. range_cardinality<Rng>::
  370. value)> make_span(Rng && rng) noexcept(noexcept(ranges::data(rng)))
  371. {
  372. return {ranges::data(rng), range_cardinality<Rng>::value};
  373. }
  374. } // namespace ranges
  375. #endif // RANGES_V3_VIEW_SPAN_HPP