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.

793 lines
29KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Tomislav Ivek 2015-2016
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_VIEW_SET_ALGORITHM_HPP
  15. #define RANGES_V3_VIEW_SET_ALGORITHM_HPP
  16. #include <algorithm>
  17. #include <iterator>
  18. #include <type_traits>
  19. #include <utility>
  20. #include <meta/meta.hpp>
  21. #include <range/v3/range_fwd.hpp>
  22. #include <range/v3/functional/comparisons.hpp>
  23. #include <range/v3/functional/identity.hpp>
  24. #include <range/v3/functional/invoke.hpp>
  25. #include <range/v3/iterator/default_sentinel.hpp>
  26. #include <range/v3/range/access.hpp>
  27. #include <range/v3/range/primitives.hpp>
  28. #include <range/v3/range/traits.hpp>
  29. #include <range/v3/utility/move.hpp>
  30. #include <range/v3/utility/semiregular_box.hpp>
  31. #include <range/v3/utility/static_const.hpp>
  32. #include <range/v3/view/all.hpp>
  33. #include <range/v3/view/facade.hpp>
  34. #include <range/v3/view/view.hpp>
  35. namespace ranges
  36. {
  37. /// \cond
  38. namespace detail
  39. {
  40. template<typename Rng1, typename Rng2, typename C, typename P1, typename P2,
  41. template<bool, typename...> class Cursor, cardinality Cardinality>
  42. struct set_algorithm_view
  43. : view_facade<set_algorithm_view<Rng1, Rng2, C, P1, P2, Cursor, Cardinality>,
  44. Cardinality>
  45. {
  46. private:
  47. friend range_access;
  48. semiregular_box_t<C> pred_;
  49. semiregular_box_t<P1> proj1_;
  50. semiregular_box_t<P2> proj2_;
  51. Rng1 rng1_;
  52. Rng2 rng2_;
  53. template<bool IsConst>
  54. using cursor = Cursor<IsConst, Rng1, Rng2, C, P1, P2>;
  55. cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
  56. {
  57. return {pred_,
  58. proj1_,
  59. proj2_,
  60. ranges::begin(rng1_),
  61. ranges::end(rng1_),
  62. ranges::begin(rng2_),
  63. ranges::end(rng2_)};
  64. }
  65. CPP_member
  66. auto begin_cursor() const -> CPP_ret(cursor<true>)( //
  67. requires range<Rng1 const> && range<Rng2 const>)
  68. {
  69. return {pred_,
  70. proj1_,
  71. proj2_,
  72. ranges::begin(rng1_),
  73. ranges::end(rng1_),
  74. ranges::begin(rng2_),
  75. ranges::end(rng2_)};
  76. }
  77. public:
  78. set_algorithm_view() = default;
  79. set_algorithm_view(Rng1 rng1, Rng2 rng2, C pred, P1 proj1, P2 proj2)
  80. : pred_(std::move(pred))
  81. , proj1_(std::move(proj1))
  82. , proj2_(std::move(proj2))
  83. , rng1_(std::move(rng1))
  84. , rng2_(std::move(rng2))
  85. {}
  86. };
  87. template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
  88. typename P2>
  89. struct set_difference_cursor
  90. {
  91. private:
  92. friend struct set_difference_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
  93. using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
  94. using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
  95. using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
  96. pred_ref_ pred_;
  97. proj1_ref_ proj1_;
  98. proj2_ref_ proj2_;
  99. template<typename T>
  100. using constify_if = meta::const_if_c<IsConst, T>;
  101. using R1 = constify_if<Rng1>;
  102. using R2 = constify_if<Rng2>;
  103. iterator_t<R1> it1_;
  104. sentinel_t<R1> end1_;
  105. iterator_t<R2> it2_;
  106. sentinel_t<R2> end2_;
  107. void satisfy()
  108. {
  109. while(it1_ != end1_)
  110. {
  111. if(it2_ == end2_)
  112. return;
  113. if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
  114. return;
  115. if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
  116. ++it1_;
  117. ++it2_;
  118. }
  119. }
  120. public:
  121. using value_type = range_value_t<constify_if<Rng1>>;
  122. using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
  123. single_pass_iterator_<iterator_t<R2>>>;
  124. set_difference_cursor() = default;
  125. set_difference_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
  126. iterator_t<R1> it1, sentinel_t<R1> end1,
  127. iterator_t<R2> it2, sentinel_t<R2> end2)
  128. : pred_(std::move(pred))
  129. , proj1_(std::move(proj1))
  130. , proj2_(std::move(proj2))
  131. , it1_(std::move(it1))
  132. , end1_(std::move(end1))
  133. , it2_(std::move(it2))
  134. , end2_(std::move(end2))
  135. {
  136. satisfy();
  137. }
  138. CPP_template(bool Other)( //
  139. requires IsConst && (!Other)) //
  140. set_difference_cursor(
  141. set_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
  142. : pred_(std::move(that.pred_))
  143. , proj1_(std::move(that.proj1_))
  144. , proj2_(std::move(that.proj2_))
  145. , it1_(std::move(that.it1_))
  146. , end1_(std::move(that.end1_))
  147. , it2_(std::move(that.it2_))
  148. , end2_(std::move(that.end2_))
  149. {}
  150. // clang-format off
  151. auto CPP_auto_fun(read)()(const)
  152. (
  153. return *it1_
  154. )
  155. // clang-format on
  156. void next()
  157. {
  158. ++it1_;
  159. satisfy();
  160. }
  161. CPP_member
  162. auto equal(set_difference_cursor const & that) const -> CPP_ret(bool)( //
  163. requires forward_range<Rng1>)
  164. {
  165. // does not support comparing iterators from different ranges
  166. return it1_ == that.it1_;
  167. }
  168. bool equal(default_sentinel_t) const
  169. {
  170. return it1_ == end1_;
  171. }
  172. // clang-format off
  173. auto CPP_auto_fun(move)()(const)
  174. (
  175. return iter_move(it1_)
  176. )
  177. // clang-format on
  178. };
  179. constexpr cardinality set_difference_cardinality(cardinality c1, cardinality c2)
  180. {
  181. return (c1 == unknown)
  182. ? unknown
  183. : (c1 >= 0) || (c1 == finite) ? finite : // else, c1 == infinite
  184. (c2 >= 0) || (c2 == finite) ? infinite : unknown;
  185. }
  186. } // namespace detail
  187. /// \endcond
  188. template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
  189. using set_difference_view =
  190. detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_difference_cursor,
  191. detail::set_difference_cardinality(
  192. range_cardinality<Rng1>::value,
  193. range_cardinality<Rng2>::value)>;
  194. namespace views
  195. {
  196. struct set_difference_fn
  197. {
  198. public:
  199. template<typename Rng1, typename Rng2, typename C = less,
  200. typename P1 = identity, typename P2 = identity>
  201. auto operator()(Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{},
  202. P2 proj2 = P2{}) const
  203. -> CPP_ret(set_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>)( //
  204. requires viewable_range<Rng1> && input_range<Rng1> &&
  205. viewable_range<Rng2> && input_range<Rng2> &&
  206. indirect_relation<C, projected<iterator_t<Rng1>, P1>,
  207. projected<iterator_t<Rng2>, P2>>)
  208. {
  209. return {all(static_cast<Rng1 &&>(rng1)),
  210. all(static_cast<Rng2 &&>(rng2)),
  211. std::move(pred),
  212. std::move(proj1),
  213. std::move(proj2)};
  214. }
  215. };
  216. /// \relates set_difference_fn
  217. /// \ingroup group-views
  218. RANGES_INLINE_VARIABLE(view<set_difference_fn>, set_difference)
  219. } // namespace views
  220. /// @}
  221. /// \cond
  222. namespace detail
  223. {
  224. template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
  225. typename P2>
  226. struct set_intersection_cursor
  227. {
  228. private:
  229. friend struct set_intersection_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
  230. using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
  231. using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
  232. using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
  233. pred_ref_ pred_;
  234. proj1_ref_ proj1_;
  235. proj2_ref_ proj2_;
  236. template<typename T>
  237. using constify_if = meta::const_if_c<IsConst, T>;
  238. using R1 = constify_if<Rng1>;
  239. using R2 = constify_if<Rng2>;
  240. iterator_t<R1> it1_;
  241. sentinel_t<R1> end1_;
  242. iterator_t<R2> it2_;
  243. sentinel_t<R2> end2_;
  244. void satisfy()
  245. {
  246. while(it1_ != end1_ && it2_ != end2_)
  247. {
  248. if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
  249. ++it1_;
  250. else
  251. {
  252. if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
  253. return;
  254. ++it2_;
  255. }
  256. }
  257. }
  258. public:
  259. using value_type = range_value_t<R1>;
  260. using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
  261. single_pass_iterator_<iterator_t<R2>>>;
  262. set_intersection_cursor() = default;
  263. set_intersection_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
  264. iterator_t<R1> it1, sentinel_t<R1> end1,
  265. iterator_t<R2> it2, sentinel_t<R2> end2)
  266. : pred_(std::move(pred))
  267. , proj1_(std::move(proj1))
  268. , proj2_(std::move(proj2))
  269. , it1_(std::move(it1))
  270. , end1_(std::move(end1))
  271. , it2_(std::move(it2))
  272. , end2_(std::move(end2))
  273. {
  274. satisfy();
  275. }
  276. CPP_template(bool Other)( //
  277. requires IsConst && (!Other)) //
  278. set_intersection_cursor(
  279. set_intersection_cursor<Other, Rng1, Rng2, C, P1, P2> that)
  280. : pred_(std::move(that.pred_))
  281. , proj1_(std::move(that.proj1_))
  282. , proj2_(std::move(that.proj2_))
  283. , it1_(std::move(that.it1_))
  284. , end1_(std::move(that.end1_))
  285. , it2_(std::move(that.it2_))
  286. , end2_(std::move(that.end2_))
  287. {}
  288. // clang-format off
  289. auto CPP_auto_fun(read)()(const)
  290. (
  291. return *it1_
  292. )
  293. // clang-format on
  294. void next()
  295. {
  296. ++it1_;
  297. ++it2_;
  298. satisfy();
  299. }
  300. CPP_member
  301. auto equal(set_intersection_cursor const & that) const -> CPP_ret(bool)( //
  302. requires forward_range<Rng1>)
  303. {
  304. // does not support comparing iterators from different ranges
  305. return it1_ == that.it1_;
  306. }
  307. bool equal(default_sentinel_t) const
  308. {
  309. return (it1_ == end1_) || (it2_ == end2_);
  310. }
  311. // clang-format off
  312. auto CPP_auto_fun(move)()(const)
  313. (
  314. return iter_move(it1_)
  315. )
  316. // clang-format on
  317. };
  318. constexpr cardinality set_intersection_cardinality(cardinality c1, cardinality c2)
  319. {
  320. return (c1 == unknown) || (c2 == unknown)
  321. ? unknown
  322. : (c1 >= 0 || c1 == finite) || (c2 >= 0 || c2 == finite) ? finite
  323. : unknown;
  324. }
  325. } // namespace detail
  326. /// \endcond
  327. template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
  328. using set_intersection_view =
  329. detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_intersection_cursor,
  330. detail::set_intersection_cardinality(
  331. range_cardinality<Rng1>::value,
  332. range_cardinality<Rng2>::value)>;
  333. namespace views
  334. {
  335. struct set_intersection_fn
  336. {
  337. public:
  338. template<typename Rng1, typename Rng2, typename C = less,
  339. typename P1 = identity, typename P2 = identity>
  340. auto operator()(Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{},
  341. P2 proj2 = P2{}) const
  342. -> CPP_ret(set_intersection_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>)( //
  343. requires viewable_range<Rng1> && input_range<Rng1> &&
  344. viewable_range<Rng2> && input_range<Rng2> &&
  345. indirect_relation<C, projected<iterator_t<Rng1>, P1>,
  346. projected<iterator_t<Rng2>, P2>>)
  347. {
  348. return {all(static_cast<Rng1 &&>(rng1)),
  349. all(static_cast<Rng2 &&>(rng2)),
  350. std::move(pred),
  351. std::move(proj1),
  352. std::move(proj2)};
  353. }
  354. };
  355. /// \relates set_intersection_fn
  356. /// \ingroup group-views
  357. RANGES_INLINE_VARIABLE(view<set_intersection_fn>, set_intersection)
  358. } // namespace views
  359. /// @}
  360. /// \cond
  361. namespace detail
  362. {
  363. template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
  364. typename P2>
  365. struct set_union_cursor
  366. {
  367. private:
  368. friend struct set_union_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
  369. using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
  370. using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
  371. using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
  372. pred_ref_ pred_;
  373. proj1_ref_ proj1_;
  374. proj2_ref_ proj2_;
  375. template<typename T>
  376. using constify_if = meta::const_if_c<IsConst, T>;
  377. using R1 = constify_if<Rng1>;
  378. using R2 = constify_if<Rng2>;
  379. iterator_t<R1> it1_;
  380. sentinel_t<R1> end1_;
  381. iterator_t<R2> it2_;
  382. sentinel_t<R2> end2_;
  383. enum class state_t
  384. {
  385. FIRST,
  386. SECOND
  387. } state;
  388. void satisfy()
  389. {
  390. if(it1_ == end1_)
  391. {
  392. state = state_t::SECOND;
  393. return;
  394. }
  395. if(it2_ == end2_)
  396. {
  397. state = state_t::FIRST;
  398. return;
  399. }
  400. if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
  401. {
  402. state = state_t::SECOND;
  403. return;
  404. }
  405. if(!invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
  406. ++it2_;
  407. state = state_t::FIRST;
  408. }
  409. public:
  410. using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
  411. using reference_type =
  412. common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
  413. using rvalue_reference_type =
  414. common_reference_t<range_rvalue_reference_t<R1>,
  415. range_rvalue_reference_t<R2>>;
  416. using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
  417. single_pass_iterator_<iterator_t<R2>>>;
  418. set_union_cursor() = default;
  419. set_union_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
  420. iterator_t<R1> it1, sentinel_t<R1> end1, iterator_t<R2> it2,
  421. sentinel_t<R2> end2)
  422. : pred_(std::move(pred))
  423. , proj1_(std::move(proj1))
  424. , proj2_(std::move(proj2))
  425. , it1_(std::move(it1))
  426. , end1_(std::move(end1))
  427. , it2_(std::move(it2))
  428. , end2_(std::move(end2))
  429. {
  430. satisfy();
  431. }
  432. CPP_template(bool Other)( //
  433. requires IsConst && (!Other))
  434. set_union_cursor(set_union_cursor<Other, Rng1, Rng2, C, P1, P2> that)
  435. : pred_(std::move(that.pred_))
  436. , proj1_(std::move(that.proj1_))
  437. , proj2_(std::move(that.proj2_))
  438. , it1_(std::move(that.it1_))
  439. , end1_(std::move(that.end1_))
  440. , it2_(std::move(that.it2_))
  441. , end2_(std::move(that.end2_))
  442. {}
  443. reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
  444. {
  445. if(state == state_t::SECOND)
  446. return *it2_;
  447. else
  448. return *it1_;
  449. }
  450. void next()
  451. {
  452. if(state == state_t::FIRST)
  453. ++it1_;
  454. else
  455. ++it2_;
  456. satisfy();
  457. }
  458. CPP_member
  459. auto equal(set_union_cursor const & that) const -> CPP_ret(bool)( //
  460. requires forward_range<Rng1> && forward_range<Rng2>)
  461. {
  462. // does not support comparing iterators from different ranges
  463. return (it1_ == that.it1_) && (it2_ == that.it2_);
  464. }
  465. bool equal(default_sentinel_t) const
  466. {
  467. return (it1_ == end1_) && (it2_ == end2_);
  468. }
  469. rvalue_reference_type move() const
  470. noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
  471. {
  472. if(state == state_t::SECOND)
  473. return iter_move(it2_);
  474. else
  475. return iter_move(it1_);
  476. }
  477. };
  478. constexpr cardinality set_union_cardinality(cardinality c1, cardinality c2)
  479. {
  480. return (c1 == infinite) || (c2 == infinite)
  481. ? infinite
  482. : (c1 == unknown) || (c2 == unknown) ? unknown : finite;
  483. }
  484. } // namespace detail
  485. /// \endcond
  486. template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
  487. using set_union_view =
  488. detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_union_cursor,
  489. detail::set_union_cardinality(
  490. range_cardinality<Rng1>::value,
  491. range_cardinality<Rng2>::value)>;
  492. namespace views
  493. {
  494. struct set_union_fn
  495. {
  496. public:
  497. template<typename Rng1, typename Rng2, typename C = less,
  498. typename P1 = identity, typename P2 = identity>
  499. auto operator()(Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{},
  500. P2 proj2 = P2{}) const
  501. -> CPP_ret(set_union_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>)( //
  502. requires viewable_range<Rng1> && input_range<Rng1> &&
  503. viewable_range<Rng2> && input_range<Rng2> && common_with<
  504. range_value_t<Rng1>, range_value_t<Rng2>> &&
  505. common_reference_with<range_reference_t<Rng1>,
  506. range_reference_t<Rng2>> &&
  507. common_reference_with<range_rvalue_reference_t<Rng1>,
  508. range_rvalue_reference_t<Rng2>> &&
  509. indirect_relation<C, projected<iterator_t<Rng1>, P1>,
  510. projected<iterator_t<Rng2>, P2>>)
  511. {
  512. return {all(static_cast<Rng1 &&>(rng1)),
  513. all(static_cast<Rng2 &&>(rng2)),
  514. std::move(pred),
  515. std::move(proj1),
  516. std::move(proj2)};
  517. }
  518. };
  519. /// \relates set_union_fn
  520. /// \ingroup group-views
  521. RANGES_INLINE_VARIABLE(view<set_union_fn>, set_union)
  522. } // namespace views
  523. /// @}
  524. /// \cond
  525. namespace detail
  526. {
  527. template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
  528. typename P2>
  529. struct set_symmetric_difference_cursor
  530. {
  531. private:
  532. friend struct set_symmetric_difference_cursor<!IsConst, Rng1, Rng2, C, P1,
  533. P2>;
  534. using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
  535. using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
  536. using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
  537. pred_ref_ pred_;
  538. proj1_ref_ proj1_;
  539. proj2_ref_ proj2_;
  540. template<typename T>
  541. using constify_if = meta::const_if_c<IsConst, T>;
  542. using R1 = constify_if<Rng1>;
  543. using R2 = constify_if<Rng2>;
  544. iterator_t<R1> it1_;
  545. sentinel_t<R1> end1_;
  546. iterator_t<R2> it2_;
  547. sentinel_t<R2> end2_;
  548. enum class state_t
  549. {
  550. FIRST,
  551. SECOND,
  552. ONLY_FIRST,
  553. ONLY_SECOND
  554. } state;
  555. void satisfy()
  556. {
  557. while(it1_ != end1_)
  558. {
  559. if(it2_ == end2_)
  560. {
  561. state = state_t::ONLY_FIRST;
  562. return;
  563. }
  564. if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
  565. {
  566. state = state_t::FIRST;
  567. return;
  568. }
  569. else
  570. {
  571. if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
  572. {
  573. state = state_t::SECOND;
  574. return;
  575. }
  576. else
  577. {
  578. ++it1_;
  579. ++it2_;
  580. }
  581. }
  582. }
  583. state = state_t::ONLY_SECOND;
  584. }
  585. public:
  586. using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
  587. using reference_type =
  588. common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
  589. using rvalue_reference_type =
  590. common_reference_t<range_rvalue_reference_t<R1>,
  591. range_rvalue_reference_t<R2>>;
  592. using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
  593. single_pass_iterator_<iterator_t<R2>>>;
  594. set_symmetric_difference_cursor() = default;
  595. set_symmetric_difference_cursor(pred_ref_ pred, proj1_ref_ proj1,
  596. proj2_ref_ proj2, iterator_t<R1> it1,
  597. sentinel_t<R1> end1, iterator_t<R2> it2,
  598. sentinel_t<R2> end2)
  599. : pred_(std::move(pred))
  600. , proj1_(std::move(proj1))
  601. , proj2_(std::move(proj2))
  602. , it1_(std::move(it1))
  603. , end1_(std::move(end1))
  604. , it2_(std::move(it2))
  605. , end2_(std::move(end2))
  606. , state()
  607. {
  608. satisfy();
  609. }
  610. CPP_template(bool Other)( //
  611. requires IsConst && (!Other)) //
  612. set_symmetric_difference_cursor(
  613. set_symmetric_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
  614. : pred_(std::move(that.pred_))
  615. , proj1_(std::move(that.proj1_))
  616. , proj2_(std::move(that.proj2_))
  617. , it1_(std::move(that.it1_))
  618. , end1_(std::move(that.end1_))
  619. , it2_(std::move(that.it2_))
  620. , end2_(std::move(that.end2_))
  621. , state(that.state)
  622. {}
  623. reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
  624. {
  625. if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
  626. return *it2_;
  627. else
  628. return *it1_;
  629. }
  630. void next()
  631. {
  632. switch(state)
  633. {
  634. case state_t::FIRST:
  635. ++it1_;
  636. satisfy();
  637. break;
  638. case state_t::ONLY_FIRST:
  639. ++it1_;
  640. break;
  641. case state_t::SECOND:
  642. ++it2_;
  643. satisfy();
  644. break;
  645. case state_t::ONLY_SECOND:
  646. ++it2_;
  647. break;
  648. }
  649. }
  650. CPP_member
  651. auto equal(set_symmetric_difference_cursor const & that) const
  652. -> CPP_ret(bool)( //
  653. requires forward_range<R1> && forward_range<R2>)
  654. {
  655. // does not support comparing iterators from different ranges:
  656. return (it1_ == that.it1_) && (it2_ == that.it2_);
  657. }
  658. bool equal(default_sentinel_t) const
  659. {
  660. return (it1_ == end1_) && (it2_ == end2_);
  661. }
  662. rvalue_reference_type move() const
  663. noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
  664. {
  665. if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
  666. return iter_move(it2_);
  667. else
  668. return iter_move(it1_);
  669. }
  670. };
  671. constexpr cardinality set_symmetric_difference_cardinality(cardinality c1,
  672. cardinality c2)
  673. {
  674. return (c1 == unknown) || (c2 == unknown)
  675. ? unknown
  676. : (c1 == infinite) != (c2 == infinite)
  677. ? infinite
  678. : (c1 == infinite) && (c2 == infinite) ? unknown : finite;
  679. }
  680. } // namespace detail
  681. /// \endcond
  682. template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
  683. using set_symmetric_difference_view = detail::set_algorithm_view<
  684. Rng1, Rng2, C, P1, P2, detail::set_symmetric_difference_cursor,
  685. detail::set_symmetric_difference_cardinality(range_cardinality<Rng1>::value,
  686. range_cardinality<Rng2>::value)>;
  687. namespace views
  688. {
  689. struct set_symmetric_difference_fn
  690. {
  691. public:
  692. template<typename Rng1, typename Rng2, typename C = less,
  693. typename P1 = identity, typename P2 = identity>
  694. auto operator()(Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{},
  695. P2 proj2 = P2{}) const
  696. -> CPP_ret(set_symmetric_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1,
  697. P2>)( //
  698. requires viewable_range<Rng1> && input_range<Rng1> &&
  699. viewable_range<Rng2> && input_range<Rng2> && common_with<
  700. range_value_t<Rng1>, range_value_t<Rng2>> &&
  701. common_reference_with<range_reference_t<Rng1>,
  702. range_reference_t<Rng2>> &&
  703. common_reference_with<range_rvalue_reference_t<Rng1>,
  704. range_rvalue_reference_t<Rng2>> &&
  705. indirect_relation<C, projected<iterator_t<Rng1>, P1>,
  706. projected<iterator_t<Rng2>, P2>>)
  707. {
  708. return {all(static_cast<Rng1 &&>(rng1)),
  709. all(static_cast<Rng2 &&>(rng2)),
  710. std::move(pred),
  711. std::move(proj1),
  712. std::move(proj2)};
  713. }
  714. };
  715. /// \relates set_symmetric_difference_fn
  716. /// \ingroup group-views
  717. RANGES_INLINE_VARIABLE(view<set_symmetric_difference_fn>,
  718. set_symmetric_difference)
  719. } // namespace views
  720. /// @}
  721. } // namespace ranges
  722. #endif