set_union.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // Range v3 library
  2. //
  3. // Copyright Eric Niebler 2014-present
  4. // Copyright Tomislav Ivek 2015-2016
  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. #include <vector>
  13. #include <sstream>
  14. #include <range/v3/core.hpp>
  15. #include <range/v3/algorithm/set_algorithm.hpp>
  16. #include <range/v3/algorithm/move.hpp>
  17. #include <range/v3/functional/identity.hpp>
  18. #include <range/v3/iterator/operations.hpp>
  19. #include <range/v3/iterator/insert_iterators.hpp>
  20. #include <range/v3/utility/common_type.hpp>
  21. #include <range/v3/utility/copy.hpp>
  22. #include <range/v3/view/all.hpp>
  23. #include <range/v3/view/const.hpp>
  24. #include <range/v3/view/drop_while.hpp>
  25. #include <range/v3/view/iota.hpp>
  26. #include <range/v3/view/move.hpp>
  27. #include <range/v3/view/reverse.hpp>
  28. #include <range/v3/view/set_algorithm.hpp>
  29. #include <range/v3/view/stride.hpp>
  30. #include <range/v3/view/take.hpp>
  31. #include <range/v3/view/transform.hpp>
  32. #include "../simple_test.hpp"
  33. #include "../test_utils.hpp"
  34. int main()
  35. {
  36. using namespace ranges;
  37. int i1_finite[] = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
  38. int i2_finite[] = { -3, 2, 4, 4, 6, 9};
  39. auto i1_infinite = views::ints | views::stride(3);
  40. auto i2_infinite = views::ints | views::transform([](int x)
  41. {
  42. return x * x;
  43. });
  44. // simple identity check
  45. {
  46. ::check_equal(views::set_union(i1_infinite, i1_infinite) | views::take(100), i1_infinite | views::take(100));
  47. }
  48. // union of two finite ranges/sets
  49. {
  50. auto res = views::set_union(i1_finite, i2_finite);
  51. CPP_assert(view_<decltype(res)>);
  52. CPP_assert(forward_range<decltype(res)>);
  53. CPP_assert(!random_access_range<decltype(res)>);
  54. CPP_assert(!common_range<decltype(res)>);
  55. using R = decltype(res);
  56. CPP_assert(same_as<range_value_t<R>, int>);
  57. CPP_assert(same_as<range_reference_t<R>, int&>);
  58. CPP_assert(same_as<decltype(iter_move(begin(res))), int&&>);
  59. static_assert(range_cardinality<R>::value == ranges::finite, "Cardinality of union of finite ranges should be finite!");
  60. ::check_equal(res, {-3, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 6, 9});
  61. // check if the final result agrees with the greedy algorithm
  62. std::vector<int> greedy_union;
  63. set_union(i1_finite, i2_finite, back_inserter(greedy_union));
  64. ::check_equal(res, greedy_union);
  65. auto it = begin(res);
  66. CHECK(&*it == &*(begin(i2_finite)));
  67. ++it;
  68. CHECK(&*it == &*(begin(i1_finite)));
  69. }
  70. // union of two infinite ranges
  71. {
  72. auto res = views::set_union(i1_infinite, i2_infinite);
  73. CPP_assert(view_<decltype(res)>);
  74. CPP_assert(forward_range<decltype(res)>);
  75. CPP_assert(!random_access_range<decltype(res)>);
  76. CPP_assert(!common_range<decltype(res)>);
  77. using R = decltype(res);
  78. CPP_assert(same_as<range_value_t<R>,
  79. common_type_t<range_value_t<decltype(i1_infinite)>,
  80. range_value_t<decltype(i2_infinite)>>>);
  81. CPP_assert(same_as<range_reference_t<R>,
  82. common_reference_t<range_reference_t<decltype(i1_infinite)>,
  83. range_reference_t<decltype(i2_infinite)>>
  84. >);
  85. CPP_assert(same_as<range_rvalue_reference_t<R>,
  86. common_reference_t<range_rvalue_reference_t<decltype(i1_infinite)>,
  87. range_rvalue_reference_t<decltype(i2_infinite)>>
  88. >);
  89. static_assert(range_cardinality<R>::value == ranges::infinite, "Cardinality of union of infinite ranges should be infinite!");
  90. ::check_equal(res | views::take(6), {0, 1, 3, 4, 6, 9});
  91. // check if the final result agrees with the greedy algorithm
  92. std::vector<int> greedy_union;
  93. set_union(i1_infinite | views::take(10), i2_infinite | views::take(10), back_inserter(greedy_union));
  94. ::check_equal(res | views::take(6), greedy_union | views::take(6));
  95. }
  96. // union of a finite and an infinite range
  97. {
  98. auto res = views::set_union(i1_finite, i2_infinite);
  99. CPP_assert(view_<decltype(res)>);
  100. CPP_assert(forward_range<decltype(res)>);
  101. CPP_assert(!random_access_range<decltype(res)>);
  102. CPP_assert(!common_range<decltype(res)>);
  103. using R = decltype(res);
  104. CPP_assert(same_as<range_value_t<R>, int>);
  105. CPP_assert(same_as<range_reference_t<R>, int>); // our infinite range does not give out references
  106. CPP_assert(same_as<range_rvalue_reference_t<R>, int>);
  107. static_assert(range_cardinality<R>::value == ranges::infinite, "Cardinality of union with an infinite range should be infinite!");
  108. ::check_equal(res | views::take(5), {0, 1, 2, 2, 3});
  109. }
  110. // union of an infinite and a finite range
  111. {
  112. auto res = views::set_union(i1_infinite, i2_finite);
  113. CPP_assert(view_<decltype(res)>);
  114. CPP_assert(forward_range<decltype(res)>);
  115. CPP_assert(!random_access_range<decltype(res)>);
  116. CPP_assert(!common_range<decltype(res)>);
  117. using R = decltype(res);
  118. CPP_assert(same_as<range_value_t<R>, int>);
  119. CPP_assert(same_as<range_reference_t<R>, int>); // our infinite range does not give out references
  120. CPP_assert(same_as<range_rvalue_reference_t<R>, int>);
  121. static_assert(range_cardinality<R>::value == ranges::infinite, "Cardinality of union with an infinite range should be infinite!");
  122. ::check_equal(res | views::take(7), {-3, 0, 2, 3, 4, 4, 6});
  123. }
  124. // unions involving unknown cardinalities
  125. {
  126. auto rng0 = views::iota(10) | views::drop_while([](int i)
  127. {
  128. return i < 25;
  129. });
  130. static_assert(range_cardinality<decltype(rng0)>::value == ranges::unknown, "");
  131. auto res1 = views::set_union(i2_finite, rng0);
  132. static_assert(range_cardinality<decltype(res1)>::value == ranges::unknown, "Union of a finite and unknown cardinality set should have unknown cardinality!");
  133. auto res2 = views::set_union(rng0, i2_finite);
  134. static_assert(range_cardinality<decltype(res2)>::value == ranges::unknown, "Union of an unknown and finite cardinality set should have unknown cardinality!");
  135. auto res3 = views::set_union(i1_infinite, rng0);
  136. static_assert(range_cardinality<decltype(res3)>::value == ranges::infinite, "Union of an infinite and unknown cardinality set should have infinite cardinality!");
  137. auto res4 = views::set_union(rng0, i1_infinite);
  138. static_assert(range_cardinality<decltype(res4)>::value == ranges::infinite, "Union of an unknown and infinite cardinality set should have infinite cardinality!");
  139. auto res5 = views::set_union(rng0, rng0);
  140. static_assert(range_cardinality<decltype(res5)>::value == ranges::unknown, "Union of two unknown cardinality sets should have unknown cardinality!");
  141. ::check_equal(res5 | views::take(100), rng0 | views::take(100));
  142. }
  143. // test const ranges
  144. {
  145. auto res1 = views::set_union(views::const_(i1_finite), views::const_(i2_finite));
  146. using R1 = decltype(res1);
  147. CPP_assert(same_as<range_value_t<R1>, int>);
  148. CPP_assert(same_as<range_reference_t<R1>, const int&>);
  149. CPP_assert(same_as<range_rvalue_reference_t<R1>, const int&&>);
  150. auto res2 = views::set_union(views::const_(i1_finite), i2_finite);
  151. using R2 = decltype(res2);
  152. CPP_assert(same_as<range_value_t<R2>, int>);
  153. CPP_assert(same_as<range_reference_t<R2>, const int&>);
  154. CPP_assert(same_as<range_rvalue_reference_t<R2>, const int&&>);
  155. }
  156. // test different orderings
  157. {
  158. auto res = views::set_union(views::reverse(i1_finite), views::reverse(i2_finite), [](int a, int b)
  159. {
  160. return a > b;
  161. });
  162. ::check_equal(res, {9, 6, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1, -3});
  163. }
  164. struct B
  165. {
  166. int val;
  167. B(int i): val{i} {}
  168. bool operator==(const B& other) const
  169. {
  170. return val == other.val;
  171. }
  172. };
  173. struct D: public B
  174. {
  175. D(int i): B{i} {}
  176. D(B b): B{std::move(b)} {}
  177. };
  178. B b_finite[] = {B{-20}, B{-10}, B{1}, B{3}, B{3}, B{6}, B{8}, B{20}};
  179. D d_finite[] = {D{0}, D{2}, D{4}, D{6}};
  180. // sets with different element types, custom orderings
  181. {
  182. auto res = views::set_union(b_finite, d_finite, [](const B& a, const D& b){ return a.val < b.val; });
  183. using R = decltype(res);
  184. CPP_assert(same_as<range_value_t<R>, B>);
  185. CPP_assert(same_as<range_reference_t<R>, B&>);
  186. CPP_assert(same_as<range_rvalue_reference_t<R>, B&&>);
  187. ::check_equal(res, {B{-20}, B{-10}, B{0}, B{1}, B{2}, B{3}, B{3}, B{4}, B{6}, B{8}, B{20}});
  188. auto it = begin(res);
  189. CHECK(&*it == &*begin(b_finite));
  190. advance(it, 2);
  191. CHECK(&*it == &*begin(d_finite));
  192. }
  193. // projections
  194. {
  195. auto res1 = views::set_union(b_finite, d_finite,
  196. less(),
  197. &B::val,
  198. &D::val
  199. );
  200. using R1 = decltype(res1);
  201. CPP_assert(same_as<range_value_t<R1>, B>);
  202. CPP_assert(same_as<range_reference_t<R1>, B&>);
  203. CPP_assert(same_as<range_rvalue_reference_t<R1>, B&&>);
  204. ::check_equal(res1, {B{-20}, B{-10}, B{0}, B{1}, B{2}, B{3}, B{3}, B{4}, B{6}, B{8}, B{20}});
  205. auto res2 = views::set_union(views::ints(-2, 10), b_finite,
  206. less(),
  207. identity(),
  208. [](const B& x){ return x.val; }
  209. );
  210. using R2 = decltype(res2);
  211. CPP_assert(same_as<range_value_t<R2>, B>);
  212. CPP_assert(same_as<range_reference_t<R2>, B>);
  213. CPP_assert(same_as<range_rvalue_reference_t<R2>, B>);
  214. ::check_equal(res2, {B{-20}, B{-10}, B{-2}, B{-1}, B{0}, B{1}, B{2}, B{3}, B{3}, B{4}, B{5}, B{6}, B{7}, B{8}, B{9}, B{20}});
  215. }
  216. // move
  217. {
  218. auto v0 = to<std::vector<MoveOnlyString>>({"a","b","c","x"});
  219. auto v1 = to<std::vector<MoveOnlyString>>({"b","x","y","z"});
  220. auto res = views::set_union(v0, v1, [](const MoveOnlyString& a, const MoveOnlyString& b){return a<b;});
  221. std::vector<MoveOnlyString> expected;
  222. move(res, back_inserter(expected));
  223. ::check_equal(expected, {"a","b","c","x","y","z"});
  224. ::check_equal(v0, {"","","",""});
  225. ::check_equal(v1, {"b","x","",""});
  226. using R = decltype(res);
  227. CPP_assert(same_as<range_value_t<R>, MoveOnlyString>);
  228. CPP_assert(same_as<range_reference_t<R>, MoveOnlyString &>);
  229. CPP_assert(same_as<range_rvalue_reference_t<R>, MoveOnlyString &&>);
  230. }
  231. // iterator (in)equality
  232. {
  233. int r1[] = {1, 2, 3};
  234. int r2[] = { 2, 3, 4, 5};
  235. auto res = views::set_union(r1, r2); // 1, 2, 3, 4, 5
  236. auto it1 = ranges::next(res.begin(), 3); // *it1 == 4, member iterator into r1 points to r1.end()
  237. auto it2 = ranges::next(it1); // *it2 == 5, member iterator into r1 also points to r1.end()
  238. auto sentinel = res.end();
  239. CHECK(*it1 == 4);
  240. CHECK(*it2 == 5);
  241. CHECK(it1 != it2); // should be different even though member iterators into r1 are the same
  242. CHECK(it1 != sentinel);
  243. CHECK(ranges::next(it1, 2) == sentinel);
  244. CHECK(it2 != sentinel);
  245. CHECK(ranges::next(it2, 1) == sentinel);
  246. }
  247. {
  248. auto rng = views::set_union(
  249. debug_input_view<int const>{i1_finite},
  250. debug_input_view<int const>{i2_finite}
  251. );
  252. ::check_equal(rng, {-3, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 6, 9});
  253. }
  254. return test_result();
  255. }