/// \file // Range v3 library // // Copyright Eric Niebler 2013-2014. // Copyright Casey Carter 2017. // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../simple_test.hpp" #include "../test_utils.hpp" RANGES_DIAGNOSTIC_IGNORE_RANGE_LOOP_ANALYSIS using namespace ranges; struct printer { std::ostream &os_; bool &first_; template void operator()(T const &t) const { if (first_) first_ = false; else os_ << ','; os_ << t; } }; namespace std { template std::ostream &operator<<(std::ostream &os, std::tuple const &t) { os << '('; auto first = true; ::ranges::tuple_for_each(t, ::printer{os, first}); os << ')'; return os; } } void test_empty_set() { auto rng = views::cartesian_product(); using Rng = decltype(rng); CPP_assert(range_cardinality::value == static_cast(0)); CPP_assert(random_access_range && view_); CPP_assert(common_range); CPP_assert(sized_range); CHECK(size(rng) == 0u); CHECK(empty(rng)); CPP_assert(std::is_same< range_value_t, std::tuple<>>()); CPP_assert(std::is_same< range_reference_t, std::tuple<>&>()); std::initializer_list> control{}; ::check_equal(rng, control); ::check_equal(views::reverse(rng), views::reverse(control)); auto const first = begin(rng); auto const last = end(rng); CHECK(decltype(size(rng))(last - first) == size(rng)); for(auto i = 0; i <= distance(rng); ++i) { for(auto j = 0; j <= distance(rng); ++j) { CHECK((next(first, i) - next(first, j)) == i - j); } } } void test_empty_range() { int some_ints[] = {0,1,2,3}; auto e = views::empty; auto rng = views::cartesian_product( span{some_ints}, e ); using Rng = decltype(rng); CPP_assert(range_cardinality::value == static_cast(0)); CPP_assert(random_access_range && view_); CPP_assert(common_range); CPP_assert(sized_range); CHECK(size(rng) == 0u); CPP_assert(std::is_same< range_value_t, std::tuple>()); CPP_assert(std::is_same< range_reference_t, common_tuple>()); using CT = common_tuple; std::initializer_list control = {}; ::check_equal(rng, control); ::check_equal(views::reverse(rng), views::reverse(control)); auto const first = begin(rng); auto const last = end(rng); CHECK((last - first) == (std::intmax_t) size(rng)); for(auto i = 0; i <= distance(rng); ++i) { for(auto j = 0; j <= distance(rng); ++j) { CHECK((next(first, i) - next(first, j)) == i - j); } } } void test_bug_820() { // https://github.com/ericniebler/range-v3/issues/820 using CT = common_tuple; std::initializer_list control = { CT{0, 0}, CT{0, 1}, CT{0, 2}, CT{1, 0}, CT{1, 1}, CT{1, 2}, CT{2, 0}, CT{2, 1}, CT{2, 2} }; auto x = ranges::views::iota(0) | ranges::views::take_exactly(3); auto y = ranges::views::cartesian_product(x, x); ::check_equal(y, control); } void test_bug_823() { // https://github.com/ericniebler/range-v3/issues/823 auto three = ranges::views::iota(0) | ranges::views::take_exactly(3); CPP_assert(ranges::random_access_range && ranges::view_); CPP_assert(!(ranges::random_access_range && ranges::view_)); auto prod = ranges::views::cartesian_product(three, three); CPP_assert(ranges::random_access_range && ranges::view_); CPP_assert(!(ranges::random_access_range && ranges::view_)); CPP_assert(ranges::sized_range); CHECK(ranges::size(prod) == 9u); { int i = 0; RANGES_FOR(auto&& x, prod) { (void)x; RANGES_ENSURE(i++ < 3 * 3); } CHECK(i == 3 * 3); } auto twoD = prod | ranges::views::chunk(3); CPP_assert(ranges::random_access_range && ranges::view_); CPP_assert(!(ranges::random_access_range && ranges::view_)); { int i = 0; RANGES_FOR(auto&& row, twoD) { (void)row; RANGES_ENSURE(i++ < 3); } CHECK(i == 3); } { int i = 0; RANGES_FOR(auto&& row, twoD) { RANGES_ENSURE(i++ < 3); int j = 0; RANGES_FOR(auto&& col, row) { (void)col; RANGES_ENSURE(j++ < 3); } CHECK(j == 3); } CHECK(i == 3); } } void test_bug_919() { // https://github.com/ericniebler/range-v3/issues/919 int some_ints[] = {0,1,2,3}; char const * some_strings[] = {"John", "Paul", "George", "Ringo"}; auto rng = views::cartesian_product( span{some_ints}, span{some_strings} ); constexpr std::intmax_t n = size(rng); static_assert(n == 16, ""); for (std::intmax_t i = 0; i <= n; ++i) { auto const x = rng.begin() + i; CHECK((x == rng.end() - (n - i))); for (std::intmax_t j = 0; j <= n; ++j) CHECK((rng.begin() + j == x + (j - i))); } } void test_bug_978() { // https://github.com/ericniebler/range-v3/issues/978 int rgi[] = {1}; ranges::views::cartesian_product( rgi | ranges::views::filter([](int){ return true; }), rgi ); } void test_bug_1269() { // https://github.com/ericniebler/range-v3/issues/1269 int data0[2]{}, data1[3]{}, data2[5]{}, data3[7]{}; constexpr std::size_t N = ranges::size(data0) * ranges::size(data1) * ranges::size(data2) * ranges::size(data3); CPP_assert(N < INT_MAX); auto rng = ranges::views::cartesian_product(data0, data1, data2, data3); CPP_assert(ranges::sized_range); CHECK(ranges::size(rng) == N); CPP_assert(ranges::random_access_range); CPP_assert(ranges::sized_sentinel_for, ranges::iterator_t>); for (int i = 0; i < int{N}; ++i) { auto pos = ranges::begin(rng) + i; CHECK((ranges::end(rng) - pos) == std::intmax_t{N} - i); } } void test_bug_1279() { // https://github.com/ericniebler/range-v3/issues/1279 auto const xs = ranges::views::indices(std::size_t{0}, std::size_t{10}); auto const ys = ranges::views::indices(std::size_t{0}, std::size_t{10}); for(auto r : ranges::views::cartesian_product(ys, xs)) { (void) r; } } void test_bug_1296() { // https://github.com/ericniebler/range-v3/issues/1296 auto v = ranges::views::cartesian_product(ranges::views::single(42)) | ranges::views::transform([](std::tuple a) { return std::get<0>(a); }); CHECK(ranges::size(v) == 1u); CHECK(*ranges::begin(v) == 42); } // https://github.com/ericniebler/range-v3/issues/1422 void test_1422() { int v1[] = {1,2,3}; auto e = v1 | ranges::views::enumerate; auto cp = ranges::views::cartesian_product(e, e); using CP = decltype(cp); CPP_assert(ranges::input_range); } int main() { int some_ints[] = {0,1,2,3}; char const * some_strings[] = {"John", "Paul", "George", "Ringo"}; auto rng = views::cartesian_product( span{some_ints}, span{some_strings} ); using Rng = decltype(rng); CPP_assert(range_cardinality::value == range_cardinality::value * range_cardinality::value); CPP_assert(random_access_range && view_); CPP_assert(common_range); CPP_assert(sized_range); CHECK(size(rng) == size(some_ints) * size(some_strings)); CPP_assert(std::is_same< range_value_t, std::tuple>()); CPP_assert(std::is_same< range_reference_t, common_tuple>()); using CT = common_tuple; std::initializer_list control = { CT{0, "John"}, CT{0, "Paul"}, CT{0, "George"}, CT{0, "Ringo"}, CT{1, "John"}, CT{1, "Paul"}, CT{1, "George"}, CT{1, "Ringo"}, CT{2, "John"}, CT{2, "Paul"}, CT{2, "George"}, CT{2, "Ringo"}, CT{3, "John"}, CT{3, "Paul"}, CT{3, "George"}, CT{3, "Ringo"} }; ::check_equal(rng, control); ::check_equal(views::reverse(rng), views::reverse(control)); auto const first = begin(rng); auto const last = end(rng); CHECK((last - first) == (std::intmax_t) size(rng)); for(auto i = 0; i <= distance(rng); ++i) { for(auto j = 0; j <= distance(rng); ++j) { CHECK((next(first, i) - next(first, j)) == i - j); } } test_empty_set(); test_empty_range(); test_bug_820(); test_bug_823(); test_bug_919(); test_bug_978(); test_bug_1269(); test_bug_1279(); test_bug_1296(); return test_result(); }