zip.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Range v3 library
  2. //
  3. // Copyright Eric Niebler 2014-present
  4. //
  5. // Use, modification and distribution is subject to the
  6. // Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // Project home: https://github.com/ericniebler/range-v3
  11. #include <algorithm>
  12. #include <memory>
  13. #include <sstream>
  14. #include <string>
  15. #include <vector>
  16. #include <range/v3/core.hpp>
  17. #include <range/v3/algorithm/copy.hpp>
  18. #include <range/v3/algorithm/move.hpp>
  19. #include <range/v3/algorithm/find_if.hpp>
  20. #include <range/v3/utility/copy.hpp>
  21. #include <range/v3/iterator/operations.hpp>
  22. #include <range/v3/iterator/insert_iterators.hpp>
  23. #include <range/v3/view/common.hpp>
  24. #include <range/v3/view/filter.hpp>
  25. #include <range/v3/view/for_each.hpp>
  26. #include <range/v3/view/iota.hpp>
  27. #include <range/v3/view/map.hpp>
  28. #include <range/v3/view/move.hpp>
  29. #include <range/v3/view/stride.hpp>
  30. #include <range/v3/view/take_while.hpp>
  31. #include <range/v3/view/take.hpp>
  32. #include <range/v3/view/zip.hpp>
  33. #include <range/v3/view/zip_with.hpp>
  34. #include "../simple_test.hpp"
  35. #include "../test_utils.hpp"
  36. #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911
  37. // See https://github.com/ericniebler/range-v3/issues/1480
  38. void test_bug1480()
  39. {
  40. std::vector<char> const first{};
  41. std::vector<char> const second{};
  42. auto zip_view = ::ranges::views::zip(first, second);
  43. auto fn = [&] ([[maybe_unused]] auto && ch)
  44. {
  45. };
  46. std::ranges::for_each(zip_view, fn);
  47. }
  48. #endif
  49. int main()
  50. {
  51. using namespace ranges;
  52. std::vector<int> vi{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  53. std::vector<std::string> const vs{"hello", "goodbye", "hello", "goodbye"};
  54. // All common ranges, but one single-pass
  55. {
  56. std::stringstream str{"john paul george ringo"};
  57. using V = std::tuple<int, std::string, std::string>;
  58. auto rng = views::zip(vi, vs, istream<std::string>(str) | views::common);
  59. using Rng = decltype(rng);
  60. CPP_assert(view_<decltype(rng)>);
  61. CPP_assert(!common_range<decltype(rng)>);
  62. CPP_assert(!sized_range<decltype(rng)>);
  63. CPP_assert(same_as<
  64. range_value_t<Rng>,
  65. std::tuple<int, std::string, std::string>>);
  66. CPP_assert(same_as<
  67. range_reference_t<Rng>,
  68. common_tuple<int &, std::string const &, std::string &>>);
  69. CPP_assert(same_as<
  70. range_rvalue_reference_t<Rng>,
  71. common_tuple<int &&, std::string const &&, std::string &&>>);
  72. CPP_assert(convertible_to<range_value_t<Rng> &&,
  73. range_rvalue_reference_t<Rng>>);
  74. CPP_assert(input_iterator<decltype(begin(rng))>);
  75. CPP_assert(!forward_iterator<decltype(begin(rng))>);
  76. has_cardinality<cardinality::finite>(rng);
  77. auto expected = to_vector(rng);
  78. ::check_equal(expected, {V{0, "hello", "john"},
  79. V{1, "goodbye", "paul"},
  80. V{2, "hello", "george"},
  81. V{3, "goodbye", "ringo"}});
  82. }
  83. // Mixed ranges and common ranges
  84. {
  85. std::stringstream str{"john paul george ringo"};
  86. using V = std::tuple<int, std::string, std::string>;
  87. auto rng = views::zip(vi, vs, istream<std::string>(str));
  88. CPP_assert(view_<decltype(rng)>);
  89. CPP_assert(!sized_range<decltype(rng)>);
  90. CPP_assert(!common_range<decltype(rng)>);
  91. CPP_assert(input_iterator<decltype(begin(rng))>);
  92. CPP_assert(!forward_iterator<decltype(begin(rng))>);
  93. has_cardinality<cardinality::finite>(rng);
  94. std::vector<V> expected;
  95. copy(rng, ranges::back_inserter(expected));
  96. ::check_equal(expected, {V{0, "hello", "john"},
  97. V{1, "goodbye", "paul"},
  98. V{2, "hello", "george"},
  99. V{3, "goodbye", "ringo"}});
  100. }
  101. auto rnd_rng = views::zip(vi, vs);
  102. using Ref = range_reference_t<decltype(rnd_rng)>;
  103. static_assert(std::is_same<Ref, common_pair<int &,std::string const &>>::value, "");
  104. CPP_assert(view_<decltype(rnd_rng)>);
  105. CPP_assert(common_range<decltype(rnd_rng)>);
  106. CPP_assert(sized_range<decltype(rnd_rng)>);
  107. CPP_assert(random_access_iterator<decltype(begin(rnd_rng))>);
  108. has_cardinality<cardinality::finite>(rnd_rng);
  109. auto tmp = cbegin(rnd_rng) + 3;
  110. CHECK(std::get<0>(*tmp) == 3);
  111. CHECK(std::get<1>(*tmp) == "goodbye");
  112. CHECK((rnd_rng.end() - rnd_rng.begin()) == 4);
  113. CHECK((rnd_rng.begin() - rnd_rng.end()) == -4);
  114. CHECK(rnd_rng.size() == 4u);
  115. // zip_with
  116. {
  117. std::vector<std::string> v0{"a","b","c"};
  118. std::vector<std::string> v1{"x","y","z"};
  119. auto rng = views::zip_with(std::plus<std::string>{}, v0, v1);
  120. std::vector<std::string> expected;
  121. copy(rng, ranges::back_inserter(expected));
  122. ::check_equal(expected, {"ax","by","cz"});
  123. auto rng2 = views::zip_with([] { return 42; });
  124. static_assert(std::is_same<range_value_t<decltype(rng2)>, int>::value, "");
  125. }
  126. // Move from a zip view
  127. {
  128. auto v0 = to<std::vector<MoveOnlyString>>({"a","b","c"});
  129. auto v1 = to<std::vector<MoveOnlyString>>({"x","y","z"});
  130. auto rng = views::zip(v0, v1);
  131. CPP_assert(random_access_range<decltype(rng)>);
  132. std::vector<std::pair<MoveOnlyString, MoveOnlyString>> expected;
  133. move(rng, ranges::back_inserter(expected));
  134. ::check_equal(expected | views::keys, {"a","b","c"});
  135. ::check_equal(expected | views::values, {"x","y","z"});
  136. ::check_equal(v0, {"","",""});
  137. ::check_equal(v1, {"","",""});
  138. move(expected, rng.begin());
  139. ::check_equal(expected | views::keys, {"","",""});
  140. ::check_equal(expected | views::values, {"","",""});
  141. ::check_equal(v0, {"a","b","c"});
  142. ::check_equal(v1, {"x","y","z"});
  143. std::vector<MoveOnlyString> res;
  144. using R = decltype(rng);
  145. auto proj =
  146. [](range_reference_t<R> p) -> MoveOnlyString& {return p.first;};
  147. auto rng2 = rng | views::transform(proj);
  148. move(rng2, ranges::back_inserter(res));
  149. ::check_equal(res, {"a","b","c"});
  150. ::check_equal(v0, {"","",""});
  151. ::check_equal(v1, {"x","y","z"});
  152. using R2 = decltype(rng2);
  153. CPP_assert(same_as<range_value_t<R2>, MoveOnlyString>);
  154. CPP_assert(same_as<range_reference_t<R2>, MoveOnlyString &>);
  155. CPP_assert(same_as<range_rvalue_reference_t<R2>, MoveOnlyString &&>);
  156. }
  157. {
  158. auto const v = to<std::vector<MoveOnlyString>>({"a","b","c"});
  159. auto rng = views::zip(v, v);
  160. using Rng = decltype(rng);
  161. using I = iterator_t<Rng>;
  162. CPP_assert(indirectly_readable<I>);
  163. CPP_assert(same_as<
  164. range_value_t<Rng>,
  165. std::pair<MoveOnlyString, MoveOnlyString>>);
  166. CPP_assert(same_as<
  167. range_reference_t<Rng>,
  168. common_pair<MoveOnlyString const &, MoveOnlyString const &>>);
  169. CPP_assert(same_as<
  170. range_rvalue_reference_t<Rng>,
  171. common_pair<MoveOnlyString const &&, MoveOnlyString const &&>>);
  172. CPP_assert(same_as<
  173. range_common_reference_t<Rng>,
  174. common_pair<MoveOnlyString const &, MoveOnlyString const &>>);
  175. }
  176. {
  177. std::vector<int> v{1,2,3,4};
  178. auto moved = v | views::move;
  179. using Moved = decltype(moved);
  180. CPP_assert(same_as<range_reference_t<Moved>, int &&>);
  181. auto zipped = views::zip(moved);
  182. using Zipped = decltype(zipped);
  183. CPP_assert(same_as<range_reference_t<Zipped>, common_tuple<int &&> >);
  184. }
  185. // This is actually a test of the logic of view_adaptor. Since the stride view
  186. // does not redefine the current member function, the base range's iter_move
  187. // function gets picked up automatically.
  188. {
  189. auto rng0 = views::zip(vi, vs);
  190. auto rng1 = views::stride(rng0, 2);
  191. CPP_assert(same_as<range_rvalue_reference_t<decltype(rng1)>, range_rvalue_reference_t<decltype(rng0)>>);
  192. CPP_assert(same_as<range_value_t<decltype(rng1)>, range_value_t<decltype(rng0)>>);
  193. }
  194. // Test for noexcept iter_move
  195. {
  196. static_assert(noexcept(std::declval<std::unique_ptr<int>&>() = std::declval<std::unique_ptr<int>&&>()), "");
  197. std::unique_ptr<int> rg1[10], rg2[10];
  198. auto x = views::zip(rg1, rg2);
  199. std::pair<std::unique_ptr<int>, std::unique_ptr<int>> p = iter_move(x.begin());
  200. auto it = x.begin();
  201. static_assert(noexcept(iter_move(it)), "");
  202. }
  203. // Really a test for common_iterator's iter_move, but this is a good place for it.
  204. {
  205. std::unique_ptr<int> rg1[10], rg2[10];
  206. auto rg3 = rg2 | views::take_while([](std::unique_ptr<int> &){return true;});
  207. auto x = views::zip(rg1, rg3);
  208. CPP_assert(!common_range<decltype(x)>);
  209. auto y = x | views::common;
  210. std::pair<std::unique_ptr<int>, std::unique_ptr<int>> p = iter_move(y.begin());
  211. auto it = x.begin();
  212. static_assert(noexcept(iter_move(it)), "");
  213. }
  214. // Regression test for #439.
  215. {
  216. std::vector<int> vec{0,1,2};
  217. auto rng = vec | views::for_each([](int i) { return ranges::yield(i); });
  218. ranges::distance(views::zip(views::iota(0), rng) | views::common);
  219. }
  220. {
  221. int const i1[] = {0,1,2,3};
  222. int const i2[] = {4,5,6,7};
  223. auto rng = views::zip(
  224. debug_input_view<int const>{i1},
  225. debug_input_view<int const>{i2}
  226. );
  227. using P = std::pair<int, int>;
  228. has_cardinality<cardinality::finite>(rng);
  229. ::check_equal(rng, {P{0,4},P{1,5}, P{2,6}, P{3,7}});
  230. }
  231. {
  232. // Test with no ranges
  233. auto rng = views::zip();
  234. using R = decltype(rng);
  235. CPP_assert(same_as<range_value_t<R>, std::tuple<>>);
  236. CPP_assert(contiguous_range<R>);
  237. has_cardinality<cardinality(0)>(rng);
  238. CHECK(ranges::begin(rng) == ranges::end(rng));
  239. CHECK(ranges::size(rng) == 0u);
  240. }
  241. {
  242. // test dangling
  243. auto true_ = [](auto&&){ return true; };
  244. CHECK(!::is_dangling(ranges::find_if(views::zip(vi, vs), true_)));
  245. CHECK(!::is_dangling(ranges::find_if(views::zip(
  246. vi | views::move,
  247. vs | views::common
  248. ), true_)));
  249. CHECK(::is_dangling(ranges::find_if(views::zip(
  250. vi | views::filter(true_)), true_)));
  251. }
  252. {
  253. // test zip with infinite range
  254. int const i1[] = {0,1,2,3};
  255. auto rng = views::zip(i1, views::iota(4));
  256. has_cardinality<cardinality(4)>(rng);
  257. using P = std::pair<int, int>;
  258. ::check_equal(rng, {P{0,4},P{1,5}, P{2,6}, P{3,7}});
  259. }
  260. {
  261. // test zip with infinite ranges only
  262. auto rng = views::zip(views::iota(0), views::iota(4));
  263. has_cardinality<cardinality::infinite>(rng);
  264. using P = std::pair<int, int>;
  265. ::check_equal(rng | views::take(4), {P{0,4},P{1,5}, P{2,6}, P{3,7}});
  266. }
  267. {
  268. // test unknown cardinality
  269. std::stringstream str{};
  270. auto rng = views::zip(istream<std::string>(str));
  271. has_cardinality<cardinality::unknown>(rng);
  272. }
  273. return test_result();
  274. }