Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

562 lines
18KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  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_IOTA_HPP
  14. #define RANGES_V3_VIEW_IOTA_HPP
  15. #include <climits>
  16. #include <cstdint>
  17. #include <limits>
  18. #include <type_traits>
  19. #include <meta/meta.hpp>
  20. #include <concepts/concepts.hpp>
  21. #include <range/v3/range_fwd.hpp>
  22. #include <range/v3/iterator/default_sentinel.hpp>
  23. #include <range/v3/iterator/diffmax_t.hpp>
  24. #include <range/v3/utility/static_const.hpp>
  25. #include <range/v3/view/delimit.hpp>
  26. #include <range/v3/view/facade.hpp>
  27. #include <range/v3/view/take_exactly.hpp>
  28. RANGES_DIAGNOSTIC_PUSH
  29. RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
  30. RANGES_DIAGNOSTIC_IGNORE_TRUNCATION
  31. namespace ranges
  32. {
  33. /// \cond
  34. namespace detail
  35. {
  36. template<std::size_t N, typename = void>
  37. struct promote_as_signed_
  38. {
  39. // This shouldn't cause us to LOSE precision, but maybe it doesn't
  40. // net us any either.
  41. static_assert(sizeof(std::intmax_t) * CHAR_BIT >= N,
  42. "Possible extended integral type?");
  43. using difference_type = diffmax_t;
  44. };
  45. template<std::size_t N>
  46. struct promote_as_signed_<N, enable_if_t<(N < 16)>>
  47. {
  48. using difference_type = std::int_fast16_t;
  49. };
  50. template<std::size_t N>
  51. struct promote_as_signed_<N, enable_if_t<(N >= 16 && N < 32)>>
  52. {
  53. using difference_type = std::int_fast32_t;
  54. };
  55. template<std::size_t N>
  56. struct promote_as_signed_<N, enable_if_t<(N >= 32 && N < 64)>>
  57. {
  58. using difference_type = std::int_fast64_t;
  59. };
  60. template<typename I>
  61. using iota_difference_t = typename if_then_t<
  62. std::is_integral<I>::value && sizeof(I) == sizeof(iter_difference_t<I>),
  63. promote_as_signed_<sizeof(iter_difference_t<I>) * CHAR_BIT>,
  64. with_difference_type_<iter_difference_t<I>>>::difference_type;
  65. // clang-format off
  66. CPP_def
  67. (
  68. template(typename I)
  69. concept decrementable_,
  70. requires (I i)
  71. (
  72. --i,
  73. i--,
  74. concepts::requires_<same_as<I&, decltype(--i)>>,
  75. concepts::requires_<same_as<I, decltype(i--)>>
  76. ) &&
  77. incrementable<I>
  78. );
  79. CPP_def
  80. (
  81. template(typename I)
  82. concept advanceable_,
  83. requires (I i, I const j, iota_difference_t<I> const n)
  84. (
  85. j - j,
  86. i += n,
  87. i -= n,
  88. static_cast<I>(j - n),
  89. static_cast<I>(j + n),
  90. static_cast<I>(n + j),
  91. // NOT TO SPEC:
  92. // Unsigned integers are advanceable, but subtracting them results in
  93. // an unsigned integral, which is not the same as the difference type,
  94. // which is signed.
  95. concepts::requires_<convertible_to<decltype(j - j), iota_difference_t<I>>>,
  96. concepts::requires_<same_as<I&, decltype(i += n)>>,
  97. concepts::requires_<same_as<I&, decltype(i -= n)>> //,
  98. // concepts::requires_<convertible_to<decltype(i - n), I>>,
  99. // concepts::requires_<convertible_to<decltype(i + n), I>>,
  100. // concepts::requires_<convertible_to<decltype(n + i), I>>
  101. ) &&
  102. decrementable_<I> && totally_ordered<I>
  103. );
  104. // clang-format on
  105. template<typename I>
  106. auto iota_advance_(I & i, iota_difference_t<I> n) -> CPP_ret(void)( //
  107. requires(!unsigned_integral<I>))
  108. {
  109. // TODO: bounds-check this
  110. i += n;
  111. }
  112. template<typename Int>
  113. auto iota_advance_(Int & i, iota_difference_t<Int> n) -> CPP_ret(void)( //
  114. requires unsigned_integral<Int>)
  115. {
  116. // TODO: bounds-check this
  117. if(n >= 0)
  118. i += static_cast<Int>(n);
  119. else
  120. i -= static_cast<Int>(-n);
  121. }
  122. template<typename I>
  123. auto iota_distance_(I const & i, I const & s) -> CPP_ret(iota_difference_t<I>)( //
  124. requires advanceable_<I> && (!integral<I>))
  125. {
  126. return static_cast<iota_difference_t<I>>(s - i);
  127. }
  128. template<typename Int>
  129. auto iota_distance_(Int i0, Int i1) -> CPP_ret(iota_difference_t<Int>)( //
  130. requires signed_integral<Int>)
  131. {
  132. // TODO: bounds-check this
  133. return static_cast<iota_difference_t<Int>>(
  134. static_cast<iota_difference_t<Int>>(i1) -
  135. static_cast<iota_difference_t<Int>>(i0));
  136. }
  137. template<typename Int>
  138. auto iota_distance_(Int i0, Int i1) -> CPP_ret(iota_difference_t<Int>)( //
  139. requires unsigned_integral<Int>)
  140. {
  141. // TODO: bounds-check this
  142. return (i0 > i1) ? static_cast<iota_difference_t<Int>>(
  143. -static_cast<iota_difference_t<Int>>(i0 - i1))
  144. : static_cast<iota_difference_t<Int>>(i1 - i0);
  145. }
  146. } // namespace detail
  147. /// \endcond
  148. /// \cond
  149. namespace iota_view_detail
  150. {
  151. struct adl_hook
  152. {};
  153. // Extension: iota_view models forwarding-range, as suggested by
  154. // https://github.com/ericniebler/stl2/issues/575
  155. template<class From, class To>
  156. constexpr auto begin(iota_view<From, To> r)
  157. {
  158. return r.begin();
  159. }
  160. template<class From, class To>
  161. constexpr auto end(iota_view<From, To> r)
  162. {
  163. return r.end();
  164. }
  165. template<class From, class To>
  166. constexpr auto begin(closed_iota_view<From, To> r)
  167. {
  168. return r.begin();
  169. }
  170. template<class From, class To>
  171. constexpr auto end(closed_iota_view<From, To> r)
  172. {
  173. return r.end();
  174. }
  175. } // namespace iota_view_detail
  176. /// \endcond
  177. /// \addtogroup group-views
  178. /// @{
  179. /// An iota view in a closed range
  180. template<typename From, typename To /* = From */>
  181. struct RANGES_EMPTY_BASES closed_iota_view
  182. : view_facade<closed_iota_view<From, To>, finite>
  183. , private iota_view_detail::adl_hook
  184. {
  185. private:
  186. friend range_access;
  187. From from_ = From();
  188. RANGES_NO_UNIQUE_ADDRESS To to_ = To();
  189. struct cursor
  190. {
  191. using difference_type = detail::iota_difference_t<From>;
  192. private:
  193. friend range_access;
  194. From from_ = From();
  195. RANGES_NO_UNIQUE_ADDRESS To to_ = To();
  196. bool done_ = false;
  197. From read() const
  198. {
  199. RANGES_EXPECT(!done_);
  200. return from_;
  201. }
  202. void next()
  203. {
  204. RANGES_EXPECT(!done_);
  205. if(from_ == to_)
  206. done_ = true;
  207. else
  208. ++from_;
  209. }
  210. bool equal(default_sentinel_t) const
  211. {
  212. return done_;
  213. }
  214. CPP_member
  215. auto equal(cursor const & that) const -> CPP_ret(bool)( //
  216. requires equality_comparable<From>)
  217. {
  218. return that.from_ == from_ && that.done_ == done_;
  219. }
  220. CPP_member
  221. auto prev() -> CPP_ret(void)( //
  222. requires detail::decrementable_<From>)
  223. {
  224. if(done_)
  225. done_ = false;
  226. else
  227. --from_;
  228. }
  229. CPP_member
  230. auto advance(difference_type n) -> CPP_ret(void)( //
  231. requires detail::advanceable_<From>)
  232. {
  233. if(n > 0)
  234. {
  235. RANGES_ENSURE(detail::iota_distance_(from_, to_) >= n - !done_);
  236. detail::iota_advance_(
  237. from_,
  238. n - (done_ = (detail::iota_distance_(from_, to_) <= n - !done_)));
  239. }
  240. else if(n < 0)
  241. detail::iota_advance_(from_, n + std::exchange(done_, false));
  242. }
  243. CPP_member
  244. auto distance_to(cursor const & that) const -> CPP_ret(difference_type)( //
  245. requires detail::advanceable_<From>)
  246. {
  247. using D = difference_type;
  248. return static_cast<D>(detail::iota_distance_(from_, that.from_)) +
  249. ((D)that.done_ - (D)done_);
  250. }
  251. CPP_member
  252. auto distance_to(default_sentinel_t) const -> CPP_ret(difference_type)( //
  253. requires sized_sentinel_for<To, From>)
  254. {
  255. return difference_type(to_ - from_) + !done_;
  256. }
  257. public:
  258. cursor() = default;
  259. constexpr cursor(From from, To to, bool done = false)
  260. : from_(std::move(from))
  261. , to_(std::move(to))
  262. , done_(done)
  263. {}
  264. };
  265. cursor begin_cursor() const
  266. {
  267. return {from_, to_};
  268. }
  269. CPP_member
  270. auto end_cursor() const -> CPP_ret(cursor)( //
  271. requires same_as<From, To>)
  272. {
  273. return {to_, to_, true};
  274. }
  275. CPP_member
  276. auto end_cursor() const -> CPP_ret(default_sentinel_t)( //
  277. requires(!same_as<From, To>))
  278. {
  279. return {};
  280. }
  281. constexpr void check_bounds_(std::true_type)
  282. {
  283. RANGES_EXPECT(from_ <= to_);
  284. }
  285. constexpr void check_bounds_(std::false_type)
  286. {}
  287. public:
  288. closed_iota_view() = default;
  289. constexpr closed_iota_view(meta::id_t<From> from, meta::id_t<To> to)
  290. : from_(std::move(from))
  291. , to_(std::move(to))
  292. {
  293. check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
  294. }
  295. };
  296. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  297. CPP_template(typename From, typename To)( //
  298. requires weakly_incrementable<From> && semiregular<To> &&
  299. (!integral<From> || !integral<To> ||
  300. std::is_signed<From>::value == std::is_signed<To>::value)) //
  301. closed_iota_view(From, To)
  302. ->closed_iota_view<From, To>;
  303. #endif
  304. template<typename From, typename To /* = unreachable_sentinel_t*/>
  305. struct RANGES_EMPTY_BASES iota_view
  306. : view_facade<iota_view<From, To>,
  307. same_as<To, unreachable_sentinel_t>
  308. ? infinite
  309. : std::is_integral<From>::value && std::is_integral<To>::value
  310. ? finite
  311. : unknown>
  312. , private iota_view_detail::adl_hook
  313. {
  314. private:
  315. friend range_access;
  316. From from_ = From();
  317. RANGES_NO_UNIQUE_ADDRESS To to_ = To();
  318. struct cursor;
  319. struct sentinel
  320. {
  321. private:
  322. friend struct cursor;
  323. RANGES_NO_UNIQUE_ADDRESS To to_;
  324. public:
  325. sentinel() = default;
  326. constexpr explicit sentinel(To to)
  327. : to_(std::move(to))
  328. {}
  329. };
  330. struct cursor
  331. {
  332. using difference_type = detail::iota_difference_t<From>;
  333. private:
  334. friend range_access;
  335. From from_;
  336. From read() const
  337. {
  338. return from_;
  339. }
  340. void next()
  341. {
  342. ++from_;
  343. }
  344. bool equal(sentinel const & that) const
  345. {
  346. return from_ == that.to_;
  347. }
  348. CPP_member
  349. auto equal(cursor const & that) const -> CPP_ret(bool)( //
  350. requires equality_comparable<From>)
  351. {
  352. return that.from_ == from_;
  353. }
  354. CPP_member
  355. auto prev() -> CPP_ret(void)( //
  356. requires detail::decrementable_<From>)
  357. {
  358. --from_;
  359. }
  360. CPP_member
  361. auto advance(difference_type n) -> CPP_ret(void)( //
  362. requires detail::advanceable_<From>)
  363. {
  364. detail::iota_advance_(from_, n);
  365. }
  366. // Not to spec: TODO the relational operators will effectively be constrained
  367. // with Advanceable, but they should be constrained with totally_ordered.
  368. // Reimplement iota_view without view_facade or basic_iterator.
  369. CPP_member
  370. auto distance_to(cursor const & that) const -> CPP_ret(difference_type)( //
  371. requires detail::advanceable_<From>)
  372. {
  373. return detail::iota_distance_(from_, that.from_);
  374. }
  375. // Extension: see https://github.com/ericniebler/stl2/issues/613
  376. CPP_member
  377. auto distance_to(sentinel const & that) const -> CPP_ret(difference_type)( //
  378. requires sized_sentinel_for<To, From>)
  379. {
  380. return that.to_ - from_;
  381. }
  382. public:
  383. cursor() = default;
  384. constexpr explicit cursor(From from)
  385. : from_(std::move(from))
  386. {}
  387. };
  388. cursor begin_cursor() const
  389. {
  390. return cursor{from_};
  391. }
  392. CPP_member
  393. auto CPP_fun(end_cursor)()(const requires(same_as<To, unreachable_sentinel_t>))
  394. {
  395. return unreachable;
  396. }
  397. CPP_member
  398. auto CPP_fun(end_cursor)()(const requires(!same_as<To, unreachable_sentinel_t>))
  399. {
  400. return detail::if_then_t<same_as<From, To>, cursor, sentinel>{to_};
  401. }
  402. constexpr void check_bounds_(std::true_type)
  403. {
  404. RANGES_EXPECT(from_ <= to_);
  405. }
  406. constexpr void check_bounds_(std::false_type)
  407. {}
  408. public:
  409. #ifdef RANGES_WORKAROUND_MSVC_934264
  410. constexpr
  411. #endif // RANGES_WORKAROUND_MSVC_934264
  412. iota_view() = default;
  413. constexpr explicit iota_view(From from)
  414. : from_(std::move(from))
  415. {}
  416. constexpr iota_view(meta::id_t<From> from, meta::id_t<To> to)
  417. : from_(std::move(from))
  418. , to_(std::move(to))
  419. {
  420. check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
  421. }
  422. };
  423. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  424. CPP_template(typename From, typename To)( //
  425. requires weakly_incrementable<From> && semiregular<To> &&
  426. (!integral<From> || !integral<To> ||
  427. std::is_signed<From>::value == std::is_signed<To>::value)) //
  428. iota_view(From, To)
  429. ->iota_view<From, To>;
  430. #endif
  431. namespace views
  432. {
  433. struct iota_fn
  434. {
  435. template<typename From>
  436. auto operator()(From value) const -> CPP_ret(iota_view<From>)( //
  437. requires weakly_incrementable<From>)
  438. {
  439. return iota_view<From>{std::move(value)};
  440. }
  441. template<typename From, typename To>
  442. auto operator()(From from, To to) const -> CPP_ret(iota_view<From, To>)( //
  443. requires weakly_incrementable<From> && semiregular<To> &&
  444. detail::weakly_equality_comparable_with_<From, To> &&
  445. (!integral<From> || !integral<To> ||
  446. std::is_signed<From>::value == std::is_signed<To>::value))
  447. {
  448. return {std::move(from), std::move(to)};
  449. }
  450. };
  451. struct closed_iota_fn
  452. {
  453. template<typename From, typename To>
  454. auto operator()(From from, To to) const
  455. -> CPP_ret(closed_iota_view<From, To>)( //
  456. requires weakly_incrementable<From> && semiregular<To> &&
  457. detail::weakly_equality_comparable_with_<From, To> &&
  458. (!integral<From> || !integral<To> ||
  459. std::is_signed<From>::value == std::is_signed<To>::value))
  460. {
  461. return {std::move(from), std::move(to)};
  462. }
  463. };
  464. /// \relates iota_fn
  465. /// \ingroup group-views
  466. RANGES_INLINE_VARIABLE(iota_fn, iota)
  467. /// \relates closed_iota_fn
  468. /// \ingroup group-views
  469. RANGES_INLINE_VARIABLE(closed_iota_fn, closed_iota)
  470. struct ints_fn : iota_view<int>
  471. {
  472. ints_fn() = default;
  473. template<typename Val>
  474. RANGES_DEPRECATED(
  475. "This potentially confusing API is deprecated. Prefer to "
  476. "explicitly specify the upper bound as with ranges::unreachable, as in "
  477. "views::ints( n, unreachable )")
  478. constexpr auto
  479. operator()(Val value) const -> CPP_ret(iota_view<Val>)( //
  480. requires integral<Val>)
  481. {
  482. return iota_view<Val>{value};
  483. }
  484. template<typename Val>
  485. constexpr auto operator()(Val value, unreachable_sentinel_t) const
  486. -> CPP_ret(iota_view<Val>)( //
  487. requires integral<Val>)
  488. {
  489. return iota_view<Val>{value};
  490. }
  491. template<typename Val>
  492. constexpr auto operator()(Val from, Val to) const
  493. -> CPP_ret(iota_view<Val, Val>)( //
  494. requires integral<Val>)
  495. {
  496. return {from, to};
  497. }
  498. };
  499. /// \relates ints_fn
  500. /// \ingroup group-views
  501. RANGES_INLINE_VARIABLE(ints_fn, ints)
  502. } // namespace views
  503. /// @}
  504. } // namespace ranges
  505. #include <range/v3/detail/satisfy_boost_range.hpp>
  506. RANGES_SATISFY_BOOST_RANGE(::ranges::closed_iota_view)
  507. RANGES_SATISFY_BOOST_RANGE(::ranges::iota_view)
  508. RANGES_DIAGNOSTIC_POP
  509. #endif