cartesian_product.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-2014.
  5. // Copyright Casey Carter 2017.
  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. #include <climits>
  15. #include <iostream>
  16. #include <range/v3/range/access.hpp>
  17. #include <range/v3/range/primitives.hpp>
  18. #include <range/v3/range_for.hpp>
  19. #include <range/v3/view/span.hpp>
  20. #include <range/v3/utility/tuple_algorithm.hpp>
  21. #include <range/v3/view/cartesian_product.hpp>
  22. #include <range/v3/view/chunk.hpp>
  23. #include <range/v3/view/empty.hpp>
  24. #include <range/v3/view/filter.hpp>
  25. #include <range/v3/view/indices.hpp>
  26. #include <range/v3/view/iota.hpp>
  27. #include <range/v3/view/reverse.hpp>
  28. #include <range/v3/view/single.hpp>
  29. #include <range/v3/view/take_exactly.hpp>
  30. #include <range/v3/view/transform.hpp>
  31. #include <range/v3/view/filter.hpp>
  32. #include <range/v3/view/enumerate.hpp>
  33. #include "../simple_test.hpp"
  34. #include "../test_utils.hpp"
  35. RANGES_DIAGNOSTIC_IGNORE_RANGE_LOOP_ANALYSIS
  36. using namespace ranges;
  37. struct printer
  38. {
  39. std::ostream &os_;
  40. bool &first_;
  41. template<typename T>
  42. void operator()(T const &t) const
  43. {
  44. if (first_) first_ = false;
  45. else os_ << ',';
  46. os_ << t;
  47. }
  48. };
  49. namespace std
  50. {
  51. template<typename... Ts>
  52. std::ostream &operator<<(std::ostream &os, std::tuple<Ts...> const &t)
  53. {
  54. os << '(';
  55. auto first = true;
  56. ::ranges::tuple_for_each(t, ::printer{os, first});
  57. os << ')';
  58. return os;
  59. }
  60. }
  61. void test_empty_set()
  62. {
  63. auto rng = views::cartesian_product();
  64. using Rng = decltype(rng);
  65. CPP_assert(range_cardinality<Rng>::value ==
  66. static_cast<cardinality>(0));
  67. CPP_assert(random_access_range<Rng> && view_<Rng>);
  68. CPP_assert(common_range<Rng>);
  69. CPP_assert(sized_range<Rng>);
  70. CHECK(size(rng) == 0u);
  71. CHECK(empty(rng));
  72. CPP_assert(std::is_same<
  73. range_value_t<Rng>,
  74. std::tuple<>>());
  75. CPP_assert(std::is_same<
  76. range_reference_t<Rng>,
  77. std::tuple<>&>());
  78. std::initializer_list<common_tuple<>> control{};
  79. ::check_equal(rng, control);
  80. ::check_equal(views::reverse(rng), views::reverse(control));
  81. auto const first = begin(rng);
  82. auto const last = end(rng);
  83. CHECK(decltype(size(rng))(last - first) == size(rng));
  84. for(auto i = 0; i <= distance(rng); ++i)
  85. {
  86. for(auto j = 0; j <= distance(rng); ++j)
  87. {
  88. CHECK((next(first, i) - next(first, j)) == i - j);
  89. }
  90. }
  91. }
  92. void test_empty_range()
  93. {
  94. int some_ints[] = {0,1,2,3};
  95. auto e = views::empty<char>;
  96. auto rng = views::cartesian_product(
  97. span<int, size(some_ints)>{some_ints},
  98. e
  99. );
  100. using Rng = decltype(rng);
  101. CPP_assert(range_cardinality<Rng>::value ==
  102. static_cast<cardinality>(0));
  103. CPP_assert(random_access_range<Rng> && view_<Rng>);
  104. CPP_assert(common_range<Rng>);
  105. CPP_assert(sized_range<Rng>);
  106. CHECK(size(rng) == 0u);
  107. CPP_assert(std::is_same<
  108. range_value_t<Rng>,
  109. std::tuple<int, char>>());
  110. CPP_assert(std::is_same<
  111. range_reference_t<Rng>,
  112. common_tuple<int &, char &>>());
  113. using CT = common_tuple<int, char>;
  114. std::initializer_list<CT> control = {};
  115. ::check_equal(rng, control);
  116. ::check_equal(views::reverse(rng), views::reverse(control));
  117. auto const first = begin(rng);
  118. auto const last = end(rng);
  119. CHECK((last - first) == (std::intmax_t) size(rng));
  120. for(auto i = 0; i <= distance(rng); ++i)
  121. {
  122. for(auto j = 0; j <= distance(rng); ++j)
  123. {
  124. CHECK((next(first, i) - next(first, j)) == i - j);
  125. }
  126. }
  127. }
  128. void test_bug_820()
  129. {
  130. // https://github.com/ericniebler/range-v3/issues/820
  131. using CT = common_tuple<int, int>;
  132. std::initializer_list<CT> control = {
  133. CT{0, 0}, CT{0, 1}, CT{0, 2},
  134. CT{1, 0}, CT{1, 1}, CT{1, 2},
  135. CT{2, 0}, CT{2, 1}, CT{2, 2}
  136. };
  137. auto x = ranges::views::iota(0) | ranges::views::take_exactly(3);
  138. auto y = ranges::views::cartesian_product(x, x);
  139. ::check_equal(y, control);
  140. }
  141. void test_bug_823()
  142. {
  143. // https://github.com/ericniebler/range-v3/issues/823
  144. auto three = ranges::views::iota(0) | ranges::views::take_exactly(3);
  145. CPP_assert(ranges::random_access_range<decltype(three)> && ranges::view_<decltype(three)>);
  146. CPP_assert(!(ranges::random_access_range<const decltype(three)> && ranges::view_<const decltype(three)>));
  147. auto prod = ranges::views::cartesian_product(three, three);
  148. CPP_assert(ranges::random_access_range<decltype(prod)> && ranges::view_<decltype(prod)>);
  149. CPP_assert(!(ranges::random_access_range<const decltype(prod)> && ranges::view_<const decltype(prod)>));
  150. CPP_assert(ranges::sized_range<decltype(prod)>);
  151. CHECK(ranges::size(prod) == 9u);
  152. {
  153. int i = 0;
  154. RANGES_FOR(auto&& x, prod) {
  155. (void)x;
  156. RANGES_ENSURE(i++ < 3 * 3);
  157. }
  158. CHECK(i == 3 * 3);
  159. }
  160. auto twoD = prod | ranges::views::chunk(3);
  161. CPP_assert(ranges::random_access_range<decltype(twoD)> && ranges::view_<decltype(twoD)>);
  162. CPP_assert(!(ranges::random_access_range<const decltype(twoD)> && ranges::view_<const decltype(twoD)>));
  163. {
  164. int i = 0;
  165. RANGES_FOR(auto&& row, twoD) {
  166. (void)row;
  167. RANGES_ENSURE(i++ < 3);
  168. }
  169. CHECK(i == 3);
  170. }
  171. {
  172. int i = 0;
  173. RANGES_FOR(auto&& row, twoD) {
  174. RANGES_ENSURE(i++ < 3);
  175. int j = 0;
  176. RANGES_FOR(auto&& col, row) {
  177. (void)col;
  178. RANGES_ENSURE(j++ < 3);
  179. }
  180. CHECK(j == 3);
  181. }
  182. CHECK(i == 3);
  183. }
  184. }
  185. void test_bug_919()
  186. {
  187. // https://github.com/ericniebler/range-v3/issues/919
  188. int some_ints[] = {0,1,2,3};
  189. char const * some_strings[] = {"John", "Paul", "George", "Ringo"};
  190. auto rng = views::cartesian_product(
  191. span<int, size(some_ints)>{some_ints},
  192. span<char const*, size(some_strings)>{some_strings}
  193. );
  194. constexpr std::intmax_t n = size(rng);
  195. static_assert(n == 16, "");
  196. for (std::intmax_t i = 0; i <= n; ++i) {
  197. auto const x = rng.begin() + i;
  198. CHECK((x == rng.end() - (n - i)));
  199. for (std::intmax_t j = 0; j <= n; ++j)
  200. CHECK((rng.begin() + j == x + (j - i)));
  201. }
  202. }
  203. void test_bug_978()
  204. {
  205. // https://github.com/ericniebler/range-v3/issues/978
  206. int rgi[] = {1};
  207. ranges::views::cartesian_product(
  208. rgi | ranges::views::filter([](int){ return true; }),
  209. rgi
  210. );
  211. }
  212. void test_bug_1269()
  213. {
  214. // https://github.com/ericniebler/range-v3/issues/1269
  215. int data0[2]{}, data1[3]{}, data2[5]{}, data3[7]{};
  216. constexpr std::size_t N = ranges::size(data0) * ranges::size(data1) *
  217. ranges::size(data2) * ranges::size(data3);
  218. CPP_assert(N < INT_MAX);
  219. auto rng = ranges::views::cartesian_product(data0, data1, data2, data3);
  220. CPP_assert(ranges::sized_range<decltype(rng)>);
  221. CHECK(ranges::size(rng) == N);
  222. CPP_assert(ranges::random_access_range<decltype(rng)>);
  223. CPP_assert(ranges::sized_sentinel_for<ranges::sentinel_t<decltype(rng)>, ranges::iterator_t<decltype(rng)>>);
  224. for (int i = 0; i < int{N}; ++i)
  225. {
  226. auto pos = ranges::begin(rng) + i;
  227. CHECK((ranges::end(rng) - pos) == std::intmax_t{N} - i);
  228. }
  229. }
  230. void test_bug_1279()
  231. {
  232. // https://github.com/ericniebler/range-v3/issues/1279
  233. auto const xs = ranges::views::indices(std::size_t{0}, std::size_t{10});
  234. auto const ys = ranges::views::indices(std::size_t{0}, std::size_t{10});
  235. for(auto r : ranges::views::cartesian_product(ys, xs))
  236. {
  237. (void) r;
  238. }
  239. }
  240. void test_bug_1296()
  241. {
  242. // https://github.com/ericniebler/range-v3/issues/1296
  243. auto v = ranges::views::cartesian_product(ranges::views::single(42))
  244. | ranges::views::transform([](std::tuple<int> a) {
  245. return std::get<0>(a);
  246. });
  247. CHECK(ranges::size(v) == 1u);
  248. CHECK(*ranges::begin(v) == 42);
  249. }
  250. // https://github.com/ericniebler/range-v3/issues/1422
  251. void test_1422()
  252. {
  253. int v1[] = {1,2,3};
  254. auto e = v1 | ranges::views::enumerate;
  255. auto cp = ranges::views::cartesian_product(e, e);
  256. using CP = decltype(cp);
  257. CPP_assert(ranges::input_range<CP>);
  258. }
  259. int main()
  260. {
  261. int some_ints[] = {0,1,2,3};
  262. char const * some_strings[] = {"John", "Paul", "George", "Ringo"};
  263. auto rng = views::cartesian_product(
  264. span<int, size(some_ints)>{some_ints},
  265. span<char const*, size(some_strings)>{some_strings}
  266. );
  267. using Rng = decltype(rng);
  268. CPP_assert(range_cardinality<Rng>::value ==
  269. range_cardinality<decltype(some_ints)>::value *
  270. range_cardinality<decltype(some_strings)>::value);
  271. CPP_assert(random_access_range<Rng> && view_<Rng>);
  272. CPP_assert(common_range<Rng>);
  273. CPP_assert(sized_range<Rng>);
  274. CHECK(size(rng) == size(some_ints) * size(some_strings));
  275. CPP_assert(std::is_same<
  276. range_value_t<Rng>,
  277. std::tuple<int, char const *>>());
  278. CPP_assert(std::is_same<
  279. range_reference_t<Rng>,
  280. common_tuple<int &, char const * &>>());
  281. using CT = common_tuple<int, std::string>;
  282. std::initializer_list<CT> control = {
  283. CT{0, "John"}, CT{0, "Paul"}, CT{0, "George"}, CT{0, "Ringo"},
  284. CT{1, "John"}, CT{1, "Paul"}, CT{1, "George"}, CT{1, "Ringo"},
  285. CT{2, "John"}, CT{2, "Paul"}, CT{2, "George"}, CT{2, "Ringo"},
  286. CT{3, "John"}, CT{3, "Paul"}, CT{3, "George"}, CT{3, "Ringo"}
  287. };
  288. ::check_equal(rng, control);
  289. ::check_equal(views::reverse(rng), views::reverse(control));
  290. auto const first = begin(rng);
  291. auto const last = end(rng);
  292. CHECK((last - first) == (std::intmax_t) size(rng));
  293. for(auto i = 0; i <= distance(rng); ++i)
  294. {
  295. for(auto j = 0; j <= distance(rng); ++j)
  296. {
  297. CHECK((next(first, i) - next(first, j)) == i - j);
  298. }
  299. }
  300. test_empty_set();
  301. test_empty_range();
  302. test_bug_820();
  303. test_bug_823();
  304. test_bug_919();
  305. test_bug_978();
  306. test_bug_1269();
  307. test_bug_1279();
  308. test_bug_1296();
  309. return test_result();
  310. }