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.

237 lines
8.3KB

  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_INTERSPERSE_HPP
  14. #define RANGES_V3_VIEW_INTERSPERSE_HPP
  15. #include <type_traits>
  16. #include <utility>
  17. #include <meta/meta.hpp>
  18. #include <range/v3/range_fwd.hpp>
  19. #include <range/v3/functional/bind_back.hpp>
  20. #include <range/v3/iterator/operations.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/utility/static_const.hpp>
  26. #include <range/v3/view/adaptor.hpp>
  27. #include <range/v3/view/view.hpp>
  28. namespace ranges
  29. {
  30. /// \addtogroup group-views
  31. /// @{
  32. template<typename Rng>
  33. struct intersperse_view
  34. : view_adaptor<intersperse_view<Rng>, Rng,
  35. (range_cardinality<Rng>::value > 0)
  36. ? static_cast<cardinality>(range_cardinality<Rng>::value * 2 - 1)
  37. : range_cardinality<Rng>::value>
  38. {
  39. intersperse_view() = default;
  40. constexpr intersperse_view(Rng rng, range_value_t<Rng> val)
  41. : intersperse_view::view_adaptor{detail::move(rng)}
  42. , val_(detail::move(val))
  43. {}
  44. CPP_member
  45. constexpr auto CPP_fun(size)()(const requires sized_range<Rng const>)
  46. {
  47. auto const n = ranges::size(this->base());
  48. return n ? n * 2 - 1 : 0;
  49. }
  50. CPP_member
  51. constexpr auto CPP_fun(size)()(requires sized_range<Rng>)
  52. {
  53. auto const n = ranges::size(this->base());
  54. return n ? n * 2 - 1 : 0;
  55. }
  56. private:
  57. friend range_access;
  58. template<bool Const>
  59. struct cursor_adaptor : adaptor_base
  60. {
  61. private:
  62. friend struct cursor_adaptor<!Const>;
  63. using CRng = meta::const_if_c<Const, Rng>;
  64. bool toggle_ = false;
  65. range_value_t<Rng> val_;
  66. public:
  67. cursor_adaptor() = default;
  68. explicit constexpr cursor_adaptor(range_value_t<Rng> const & val)
  69. : val_{val}
  70. {}
  71. CPP_template(bool Other)( //
  72. requires Const && (!Other)) cursor_adaptor(cursor_adaptor<Other> that)
  73. : toggle_(that.toggle_)
  74. , val_(std::move(that.val_))
  75. {}
  76. template<typename View>
  77. constexpr iterator_t<CRng> begin(View & view)
  78. {
  79. auto first = ranges::begin(view.base());
  80. toggle_ = first != ranges::end(view.base());
  81. return first;
  82. }
  83. constexpr range_value_t<Rng> read(iterator_t<CRng> const & it) const
  84. {
  85. return toggle_ ? *it : val_;
  86. }
  87. CPP_member
  88. constexpr auto equal(iterator_t<CRng> const & it0,
  89. iterator_t<CRng> const & it1,
  90. cursor_adaptor const & other) const -> CPP_ret(bool)( //
  91. requires sentinel_for<iterator_t<CRng>, iterator_t<CRng>>)
  92. {
  93. return it0 == it1 && toggle_ == other.toggle_;
  94. }
  95. constexpr void next(iterator_t<CRng> & it)
  96. {
  97. if(toggle_)
  98. ++it;
  99. toggle_ = !toggle_;
  100. }
  101. CPP_member
  102. constexpr auto prev(iterator_t<CRng> & it) -> CPP_ret(void)( //
  103. requires bidirectional_range<CRng>)
  104. {
  105. toggle_ = !toggle_;
  106. if(toggle_)
  107. --it;
  108. }
  109. CPP_member
  110. constexpr auto distance_to(iterator_t<CRng> const & it,
  111. iterator_t<CRng> const & other_it,
  112. cursor_adaptor const & other) const
  113. -> CPP_ret(range_difference_t<Rng>)( //
  114. requires sized_sentinel_for<iterator_t<CRng>, iterator_t<CRng>>)
  115. {
  116. return (other_it - it) * 2 + (other.toggle_ - toggle_);
  117. }
  118. CPP_member
  119. constexpr auto advance(iterator_t<CRng> & it,
  120. range_difference_t<CRng> n) -> CPP_ret(void)( //
  121. requires random_access_range<CRng>)
  122. {
  123. ranges::advance(it, n >= 0 ? (n + toggle_) / 2 : (n - !toggle_) / 2);
  124. if(n % 2 != 0)
  125. toggle_ = !toggle_;
  126. }
  127. };
  128. template<bool Const>
  129. struct sentinel_adaptor : adaptor_base
  130. {
  131. private:
  132. using CRng = meta::const_if_c<Const, Rng>;
  133. public:
  134. sentinel_adaptor() = default;
  135. CPP_template(bool Other)( //
  136. requires Const && (!Other)) sentinel_adaptor(sentinel_adaptor<Other>)
  137. {}
  138. static constexpr bool empty(iterator_t<CRng> const & it,
  139. cursor_adaptor<Const> const &,
  140. sentinel_t<CRng> const & sent)
  141. {
  142. return it == sent;
  143. }
  144. };
  145. constexpr auto begin_adaptor() -> cursor_adaptor<false>
  146. {
  147. return cursor_adaptor<false>{val_};
  148. }
  149. CPP_member
  150. constexpr auto begin_adaptor() const -> CPP_ret(cursor_adaptor<true>)( //
  151. requires range<Rng const>)
  152. {
  153. return cursor_adaptor<true>{val_};
  154. }
  155. CPP_member
  156. constexpr auto end_adaptor() -> CPP_ret(cursor_adaptor<false>)( //
  157. requires common_range<Rng> && (!single_pass_iterator_<iterator_t<Rng>>))
  158. {
  159. return cursor_adaptor<false>{val_};
  160. }
  161. CPP_member
  162. constexpr auto end_adaptor() noexcept -> CPP_ret(sentinel_adaptor<false>)( //
  163. requires(!common_range<Rng>) || single_pass_iterator_<iterator_t<Rng>>)
  164. {
  165. return {};
  166. }
  167. template<bool Const = true>
  168. constexpr auto end_adaptor() const -> CPP_ret(cursor_adaptor<Const>)( //
  169. requires Const && range<meta::const_if_c<Const, Rng>> &&
  170. common_range<meta::const_if_c<Const, Rng>> &&
  171. (!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>))
  172. {
  173. return cursor_adaptor<true>{val_};
  174. }
  175. template<bool Const = true>
  176. constexpr auto end_adaptor() const noexcept
  177. -> CPP_ret(sentinel_adaptor<Const>)( //
  178. requires Const && range<meta::const_if_c<Const, Rng>> &&
  179. (!common_range<meta::const_if_c<Const, Rng>> ||
  180. single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>))
  181. {
  182. return {};
  183. }
  184. range_value_t<Rng> val_;
  185. };
  186. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  187. template<typename Rng>
  188. intersperse_view(Rng &&, range_value_t<Rng>)->intersperse_view<views::all_t<Rng>>;
  189. #endif
  190. namespace views
  191. {
  192. struct intersperse_fn
  193. {
  194. private:
  195. friend view_access;
  196. template<typename T>
  197. static constexpr auto CPP_fun(bind)(intersperse_fn intersperse, T t)( //
  198. requires copyable<T>)
  199. {
  200. return make_pipeable(bind_back(intersperse, std::move(t)));
  201. }
  202. public:
  203. template<typename Rng>
  204. constexpr auto operator()(Rng && rng, range_value_t<Rng> val) const
  205. -> CPP_ret(intersperse_view<all_t<Rng>>)( //
  206. requires viewable_range<Rng> && input_range<Rng> &&
  207. convertible_to<range_reference_t<Rng>, range_value_t<Rng>> &&
  208. semiregular<range_value_t<Rng>>)
  209. {
  210. return {all(static_cast<Rng &&>(rng)), std::move(val)};
  211. }
  212. };
  213. /// \relates intersperse_fn
  214. /// \ingroup group-views
  215. RANGES_INLINE_VARIABLE(view<intersperse_fn>, intersperse)
  216. } // namespace views
  217. } // namespace ranges
  218. #include <range/v3/detail/satisfy_boost_range.hpp>
  219. RANGES_SATISFY_BOOST_RANGE(::ranges::intersperse_view)
  220. #endif