zip_with.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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_ZIP_WITH_HPP
  14. #define RANGES_V3_VIEW_ZIP_WITH_HPP
  15. #include <limits>
  16. #include <tuple>
  17. #include <type_traits>
  18. #include <utility>
  19. #include <meta/meta.hpp>
  20. #include <range/v3/range_fwd.hpp>
  21. #include <range/v3/functional/bind_back.hpp>
  22. #include <range/v3/functional/indirect.hpp>
  23. #include <range/v3/functional/invoke.hpp>
  24. #include <range/v3/iterator/operations.hpp>
  25. #include <range/v3/range/access.hpp>
  26. #include <range/v3/range/concepts.hpp>
  27. #include <range/v3/range/traits.hpp>
  28. #include <range/v3/utility/common_type.hpp>
  29. #include <range/v3/utility/semiregular_box.hpp>
  30. #include <range/v3/utility/static_const.hpp>
  31. #include <range/v3/utility/tuple_algorithm.hpp>
  32. #include <range/v3/view/all.hpp>
  33. #include <range/v3/view/empty.hpp>
  34. #include <range/v3/view/facade.hpp>
  35. #include <range/v3/detail/prologue.hpp>
  36. namespace ranges
  37. {
  38. /// \cond
  39. namespace detail
  40. {
  41. struct equal_to_
  42. {
  43. template<typename T, typename U>
  44. bool operator()(T const & t, U const & u) const
  45. {
  46. return static_cast<bool>(t == u);
  47. }
  48. };
  49. RANGES_INLINE_VARIABLE(equal_to_, equal_to)
  50. struct dec_
  51. {
  52. template<typename T>
  53. void operator()(T & t) const
  54. {
  55. --t;
  56. }
  57. };
  58. RANGES_INLINE_VARIABLE(dec_, dec)
  59. struct inc_
  60. {
  61. template<typename T>
  62. void operator()(T & t) const
  63. {
  64. ++t;
  65. }
  66. };
  67. RANGES_INLINE_VARIABLE(inc_, inc)
  68. struct _advance_
  69. {
  70. template(typename I, typename Diff)(
  71. requires input_or_output_iterator<I> AND integer_like_<Diff>)
  72. void operator()(I & i, Diff n) const
  73. {
  74. advance(i, static_cast<iter_difference_t<I>>(n));
  75. }
  76. };
  77. RANGES_INLINE_VARIABLE(_advance_, advance_)
  78. struct distance_to_
  79. {
  80. template<typename T>
  81. constexpr auto operator()(T const & t, T const & u) const -> decltype(u - t)
  82. {
  83. return u - t;
  84. }
  85. };
  86. RANGES_INLINE_VARIABLE(distance_to_, distance_to)
  87. struct _min_
  88. {
  89. template<typename T, typename U>
  90. constexpr auto operator()(T const & t, U const & u) const
  91. -> decltype(true ? t : u)
  92. {
  93. return u < t ? u : t;
  94. }
  95. };
  96. RANGES_INLINE_VARIABLE(_min_, min_)
  97. struct _max_
  98. {
  99. template<typename T, typename U>
  100. constexpr auto operator()(T const & t, U const & u) const
  101. -> decltype(true ? u : t)
  102. {
  103. return u < t ? t : u;
  104. }
  105. };
  106. RANGES_INLINE_VARIABLE(_max_, max_)
  107. template<typename State, typename Value>
  108. using zip_cardinality = std::integral_constant<
  109. cardinality,
  110. State::value >= 0 && Value::value >= 0
  111. ? min_(State::value, Value::value)
  112. : State::value >=0 && Value::value == infinite
  113. ? State::value
  114. : State::value == infinite && Value::value >= 0
  115. ? Value::value
  116. : State::value == finite || Value::value == finite
  117. ? finite
  118. : State::value == unknown || Value::value == unknown
  119. ? unknown
  120. : infinite>;
  121. } // namespace detail
  122. /// \endcond
  123. namespace views
  124. {
  125. // clang-format off
  126. /// \concept zippable_with_
  127. /// \brief The \c zippable_with_ concept
  128. template(typename Fun, typename... Rngs)(
  129. concept (zippable_with_)(Fun, Rngs...),
  130. invocable<Fun&, iterator_t<Rngs>...> AND
  131. invocable<Fun&, copy_tag, iterator_t<Rngs>...> AND
  132. invocable<Fun&, move_tag, iterator_t<Rngs>...>
  133. );
  134. /// \concept zippable_with
  135. /// \brief The \c zippable_with concept
  136. template<typename Fun, typename ...Rngs>
  137. CPP_concept zippable_with =
  138. and_v<input_range<Rngs>...> &&
  139. copy_constructible<Fun> &&
  140. CPP_concept_ref(views::zippable_with_, Fun, Rngs...);
  141. // clang-format on
  142. } // namespace views
  143. /// \addtogroup group-views
  144. /// @{
  145. template<typename Fun, typename... Rngs>
  146. struct iter_zip_with_view
  147. : view_facade<iter_zip_with_view<Fun, Rngs...>,
  148. meta::fold<meta::list<range_cardinality<Rngs>...>,
  149. std::integral_constant<cardinality, cardinality::infinite>,
  150. meta::quote<detail::zip_cardinality>>::value>
  151. {
  152. private:
  153. CPP_assert(sizeof...(Rngs) != 0);
  154. friend range_access;
  155. semiregular_box_t<Fun> fun_;
  156. std::tuple<Rngs...> rngs_;
  157. using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
  158. template<bool Const>
  159. struct cursor;
  160. template<bool Const>
  161. struct sentinel
  162. {
  163. private:
  164. friend struct cursor<Const>;
  165. friend struct sentinel<!Const>;
  166. std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends_;
  167. public:
  168. sentinel() = default;
  169. sentinel(detail::ignore_t,
  170. std::tuple<sentinel_t<meta::const_if_c<Const, Rngs>>...> ends)
  171. : ends_(std::move(ends))
  172. {}
  173. template(bool Other)(
  174. requires Const AND CPP_NOT(Other)) //
  175. sentinel(sentinel<Other> that)
  176. : ends_(std::move(that.ends_))
  177. {}
  178. };
  179. template<bool Const>
  180. struct cursor
  181. {
  182. private:
  183. friend struct cursor<!Const>;
  184. using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
  185. fun_ref_ fun_;
  186. std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its_;
  187. public:
  188. using difference_type =
  189. common_type_t<range_difference_t<meta::const_if_c<Const, Rngs>>...>;
  190. using single_pass = meta::or_c<(
  191. bool)single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rngs>>>...>;
  192. using value_type = detail::decay_t<invoke_result_t<
  193. fun_ref_ &, copy_tag, iterator_t<meta::const_if_c<Const, Rngs>>...>>;
  194. cursor() = default;
  195. cursor(fun_ref_ fun,
  196. std::tuple<iterator_t<meta::const_if_c<Const, Rngs>>...> its)
  197. : fun_(std::move(fun))
  198. , its_(std::move(its))
  199. {}
  200. template(bool Other)(
  201. requires Const AND CPP_NOT(Other)) //
  202. cursor(cursor<Other> that)
  203. : fun_(std::move(that.fun_))
  204. , its_(std::move(that.its_))
  205. {}
  206. // clang-format off
  207. auto CPP_auto_fun(read)()(const)
  208. (
  209. return tuple_apply(fun_, its_)
  210. )
  211. // clang-format on
  212. void next()
  213. {
  214. tuple_for_each(its_, detail::inc);
  215. }
  216. CPP_member
  217. auto equal(cursor const & that) const //
  218. -> CPP_ret(bool)(
  219. requires and_v<
  220. sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
  221. iterator_t<meta::const_if_c<Const, Rngs>>>...>)
  222. {
  223. // By returning true if *any* of the iterators are equal, we allow
  224. // zipped ranges to be of different lengths, stopping when the first
  225. // one reaches the last.
  226. return tuple_foldl(tuple_transform(its_, that.its_, detail::equal_to),
  227. false,
  228. [](bool a, bool b) { return a || b; });
  229. }
  230. bool equal(sentinel<Const> const & s) const
  231. {
  232. // By returning true if *any* of the iterators are equal, we allow
  233. // zipped ranges to be of different lengths, stopping when the first
  234. // one reaches the last.
  235. return tuple_foldl(tuple_transform(its_, s.ends_, detail::equal_to),
  236. false,
  237. [](bool a, bool b) { return a || b; });
  238. }
  239. CPP_member
  240. auto prev() //
  241. -> CPP_ret(void)(
  242. requires and_v<bidirectional_range<meta::const_if_c<Const, Rngs>>...>)
  243. {
  244. tuple_for_each(its_, detail::dec);
  245. }
  246. CPP_member
  247. auto advance(difference_type n) //
  248. -> CPP_ret(void)(
  249. requires and_v<random_access_range<meta::const_if_c<Const, Rngs>>...>)
  250. {
  251. tuple_for_each(its_, bind_back(detail::advance_, n));
  252. }
  253. CPP_member
  254. auto distance_to(cursor const & that) const //
  255. -> CPP_ret(difference_type)(
  256. requires and_v<
  257. sized_sentinel_for<iterator_t<meta::const_if_c<Const, Rngs>>,
  258. iterator_t<meta::const_if_c<Const, Rngs>>>...>)
  259. {
  260. // Return the smallest distance (in magnitude) of any of the iterator
  261. // pairs. This is to accommodate zippers of sequences of different length.
  262. if(0 < std::get<0>(that.its_) - std::get<0>(its_))
  263. return tuple_foldl(
  264. tuple_transform(its_, that.its_, detail::distance_to),
  265. (std::numeric_limits<difference_type>::max)(),
  266. detail::min_);
  267. else
  268. return tuple_foldl(
  269. tuple_transform(its_, that.its_, detail::distance_to),
  270. (std::numeric_limits<difference_type>::min)(),
  271. detail::max_);
  272. }
  273. // clang-format off
  274. template<std::size_t... Is>
  275. auto CPP_auto_fun(move_)(meta::index_sequence<Is...>)(const)
  276. (
  277. return invoke(fun_, move_tag{}, std::get<Is>(its_)...)
  278. )
  279. // clang-format on
  280. auto move() const noexcept(noexcept(std::declval<cursor const &>().move_(
  281. meta::make_index_sequence<sizeof...(Rngs)>{})))
  282. -> decltype(std::declval<cursor const &>().move_(
  283. meta::make_index_sequence<sizeof...(Rngs)>{}))
  284. {
  285. return move_(meta::make_index_sequence<sizeof...(Rngs)>{});
  286. }
  287. };
  288. template<bool Const>
  289. using end_cursor_t =
  290. meta::if_c<concepts::and_v<(bool)common_range<Rngs>...,
  291. !(bool)single_pass_iterator_<iterator_t<Rngs>>...>,
  292. cursor<Const>, sentinel<Const>>;
  293. cursor<false> begin_cursor()
  294. {
  295. return {fun_, tuple_transform(rngs_, ranges::begin)};
  296. }
  297. end_cursor_t<false> end_cursor()
  298. {
  299. return {fun_, tuple_transform(rngs_, ranges::end)};
  300. }
  301. template(bool Const = true)(
  302. requires Const AND and_v<range<Rngs const>...> AND
  303. views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
  304. cursor<Const> begin_cursor() const
  305. {
  306. return {fun_, tuple_transform(rngs_, ranges::begin)};
  307. }
  308. template(bool Const = true)(
  309. requires Const AND and_v<range<Rngs const>...> AND
  310. views::zippable_with<Fun, meta::if_c<Const, Rngs const>...>)
  311. end_cursor_t<Const> end_cursor() const
  312. {
  313. return {fun_, tuple_transform(rngs_, ranges::end)};
  314. }
  315. public:
  316. iter_zip_with_view() = default;
  317. explicit iter_zip_with_view(Rngs... rngs)
  318. : fun_(Fun{})
  319. , rngs_{std::move(rngs)...}
  320. {}
  321. explicit iter_zip_with_view(Fun fun, Rngs... rngs)
  322. : fun_(std::move(fun))
  323. , rngs_{std::move(rngs)...}
  324. {}
  325. CPP_auto_member
  326. constexpr auto CPP_fun(size)()(const //
  327. requires and_v<sized_range<Rngs const>...>)
  328. {
  329. using size_type = common_type_t<range_size_t<Rngs const>...>;
  330. return range_cardinality<iter_zip_with_view>::value >= 0
  331. ? size_type{(
  332. std::size_t)range_cardinality<iter_zip_with_view>::value}
  333. : tuple_foldl(tuple_transform(rngs_,
  334. [](auto && r) -> size_type {
  335. return ranges::size(r);
  336. }),
  337. (std::numeric_limits<size_type>::max)(),
  338. detail::min_);
  339. }
  340. };
  341. template<typename Fun, typename... Rngs>
  342. struct zip_with_view : iter_zip_with_view<indirected<Fun>, Rngs...>
  343. {
  344. CPP_assert(sizeof...(Rngs) != 0);
  345. zip_with_view() = default;
  346. explicit zip_with_view(Rngs... rngs)
  347. : iter_zip_with_view<indirected<Fun>, Rngs...>{{Fun{}}, std::move(rngs)...}
  348. {}
  349. explicit zip_with_view(Fun fun, Rngs... rngs)
  350. : iter_zip_with_view<indirected<Fun>, Rngs...>{{std::move(fun)},
  351. std::move(rngs)...}
  352. {}
  353. };
  354. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  355. template(typename Fun, typename... Rng)(
  356. requires copy_constructible<Fun>)
  357. zip_with_view(Fun, Rng &&...)
  358. -> zip_with_view<Fun, views::all_t<Rng>...>;
  359. #endif
  360. namespace views
  361. {
  362. struct iter_zip_with_fn
  363. {
  364. template(typename... Rngs, typename Fun)(
  365. requires and_v<viewable_range<Rngs>...> AND
  366. zippable_with<Fun, Rngs...> AND (sizeof...(Rngs) != 0)) //
  367. iter_zip_with_view<Fun, all_t<Rngs>...> //
  368. operator()(Fun fun, Rngs &&... rngs) const
  369. {
  370. return iter_zip_with_view<Fun, all_t<Rngs>...>{
  371. std::move(fun), all(static_cast<Rngs &&>(rngs))...};
  372. }
  373. template(typename Fun)(
  374. requires zippable_with<Fun>) //
  375. constexpr empty_view<detail::decay_t<invoke_result_t<Fun &>>>
  376. operator()(Fun) const noexcept
  377. {
  378. return {};
  379. }
  380. };
  381. /// \relates iter_zip_with_fn
  382. /// \ingroup group-views
  383. RANGES_INLINE_VARIABLE(iter_zip_with_fn, iter_zip_with)
  384. struct zip_with_fn
  385. {
  386. template(typename... Rngs, typename Fun)(
  387. requires and_v<viewable_range<Rngs>...> AND
  388. and_v<input_range<Rngs>...> AND copy_constructible<Fun> AND
  389. invocable<Fun &, range_reference_t<Rngs>...> AND
  390. (sizeof...(Rngs) != 0)) //
  391. zip_with_view<Fun, all_t<Rngs>...> operator()(Fun fun, Rngs &&... rngs) const
  392. {
  393. return zip_with_view<Fun, all_t<Rngs>...>{
  394. std::move(fun), all(static_cast<Rngs &&>(rngs))...};
  395. }
  396. template(typename Fun)(
  397. requires copy_constructible<Fun> AND invocable<Fun &>) //
  398. constexpr empty_view<detail::decay_t<invoke_result_t<Fun &>>>
  399. operator()(Fun) const noexcept
  400. {
  401. return {};
  402. }
  403. };
  404. /// \relates zip_with_fn
  405. /// \ingroup group-views
  406. RANGES_INLINE_VARIABLE(zip_with_fn, zip_with)
  407. } // namespace views
  408. /// @}
  409. } // namespace ranges
  410. #include <range/v3/detail/epilogue.hpp>
  411. #include <range/v3/detail/satisfy_boost_range.hpp>
  412. RANGES_SATISFY_BOOST_RANGE(::ranges::iter_zip_with_view)
  413. RANGES_SATISFY_BOOST_RANGE(::ranges::zip_with_view)
  414. #endif