// Range v3 library // // Copyright Eric Niebler 2014-present // Copyright Tomislav Ivek 2015-2016 // // 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 #include #include "../simple_test.hpp" #include "../test_utils.hpp" int main() { using namespace ranges; int i1_finite[] = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; int i2_finite[] = { -3, 2, 4, 4, 6, 9}; auto i1_infinite = views::ints | views::stride(3); auto i2_infinite = views::ints | views::transform([](int x) { return x * x; }); // difference between two finite ranges/sets { auto res = views::set_difference(i1_finite, i2_finite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R = decltype(res); CPP_assert(same_as, int>); CPP_assert(same_as, int&>); CPP_assert(same_as); static_assert(range_cardinality::value == ranges::finite, "Cardinality of difference between two finite ranges should be finite!"); ::check_equal(res, {1, 2, 3, 3, 3, 4, 4}); // check if the final result agrees with the greedy algorithm std::vector diff; set_difference(i1_finite, i2_finite, back_inserter(diff)); ::check_equal(res, diff); CHECK(&*begin(res) == &*(begin(i1_finite))); } // difference between two infinite ranges { auto res = views::set_difference(i1_infinite, i2_infinite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R = decltype(res); CPP_assert(same_as, int>); CPP_assert(same_as, range_reference_t>); CPP_assert(same_as>); static_assert(range_cardinality::value == ranges::unknown, "Cardinality of difference of infinite ranges should be unknown!"); ::check_equal(res | views::take(5), {3, 6, 12, 15, 18}); // check if the final result agrees with the greedy algorithm std::vector diff; set_difference(i1_infinite | views::take(1000), i2_infinite | views::take(1000), back_inserter(diff)); ::check_equal(res | views::take(5), diff | views::take(5)); } // difference between a finite and an infinite range { auto res = views::set_difference(i1_finite, i2_infinite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R = decltype(res); CPP_assert(same_as, int>); CPP_assert(same_as, range_reference_t>); CPP_assert(same_as>); static_assert(range_cardinality::value == ranges::finite, "Cardinality of difference between a finite range and any other range should be finite!"); ::check_equal(res, {2, 2, 3, 3, 3, 4, 4, 4}); } // difference between an infinite and a finite range { auto res = views::set_difference(i1_infinite, i2_finite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R = decltype(res); CPP_assert(same_as, int>); CPP_assert(same_as, range_reference_t>); CPP_assert(same_as, range_rvalue_reference_t>); static_assert(range_cardinality::value == ranges::infinite, "Cardinality of difference between an infinite and finite range should be infinite!"); ::check_equal(res | views::take(5), {0, 3, 12, 15, 18}); } // differences involving unknown cardinalities { auto rng0 = views::iota(10) | views::drop_while([](int i) { return i < 25; }); static_assert(range_cardinality::value == ranges::unknown, ""); auto res1 = views::set_difference(i2_finite, rng0); static_assert(range_cardinality::value == ranges::finite, "Difference between a finite and unknown cardinality set should have finite cardinality!"); auto res2 = views::set_difference(rng0, i2_finite); static_assert(range_cardinality::value == ranges::unknown, "Difference between an unknown cardinality and finite set should have unknown cardinality!"); auto res3 = views::set_difference(i1_infinite, rng0); static_assert(range_cardinality::value == ranges::unknown, "Difference between an unknown cardinality and finite set should have unknown cardinality!"); auto res4 = views::set_difference(rng0, i1_infinite); static_assert(range_cardinality::value == ranges::unknown, "Difference between an unknown and infinite cardinality set should have unknown cardinality!"); } // test const ranges { auto res1 = views::set_difference(views::const_(i1_finite), views::const_(i2_finite)); using R1 = decltype(res1); CPP_assert(same_as, int>); CPP_assert(same_as, const int&>); CPP_assert(same_as, const int&&>); auto res2 = views::set_difference(views::const_(i1_finite), i2_finite); using R2 = decltype(res2); CPP_assert(same_as, int>); CPP_assert(same_as, const int&>); CPP_assert(same_as, const int&&>); } // test different orderings { auto res = views::set_difference(views::reverse(i1_finite), views::reverse(i2_finite), [](int a, int b) { return a > b; }); ::check_equal(res, {4, 4, 3, 3, 3, 2, 1}); } // test projections and sets with different element types struct S { int val; bool operator==(const S& other) const { return val == other.val; } }; S s_finite[] = {S{-20}, S{-10}, S{1}, S{3}, S{3}, S{6}, S{8}, S{20}}; { auto res1 = views::set_difference(s_finite, views::ints(-2, 10), less(), &S::val, identity() ); using R1 = decltype(res1); CPP_assert(same_as, S>); CPP_assert(same_as, S&>); CPP_assert(same_as, S&&>); ::check_equal(res1, {S{-20}, S{-10}, S{3}, S{20}}); auto res2 = views::set_difference(views::ints(-2, 10), s_finite, less(), identity(), [](const S& x){ return x.val; } ); using R2 = decltype(res2); CPP_assert(same_as, int>); CPP_assert(same_as, int>); CPP_assert(same_as, int>); ::check_equal(res2, {-2, -1, 0, 2, 4, 5, 7, 9}); } // move { auto v0 = to>({"a","b","b","c","x","x"}); auto v1 = to>({"b","x","y","z"}); auto res = views::set_difference(v0, v1, [](const MoveOnlyString& a, const MoveOnlyString& b){return a expected; move(res, back_inserter(expected)); ::check_equal(expected, {"a","b","c","x"}); ::check_equal(v1, {"b","x","y","z"}); ::check_equal(v0, {"","b","","","x",""}); auto v0_greedy = to>({"a","b","b","c","x","x"}); auto v1_greedy = to>({"b","x","y","z"}); std::vector expected_greedy; set_difference(v0_greedy, v1_greedy, move_into(back_inserter(expected_greedy)), [](const MoveOnlyString& a, const MoveOnlyString& b){return a, MoveOnlyString>); CPP_assert(same_as, MoveOnlyString &>); CPP_assert(same_as, MoveOnlyString &&>); } // WARNING: set_difference between two infinite ranges can create infinite loops! // { // auto empty_range = views::set_difference(views::ints, views::ints); // begin(empty_range); // infinite loop! // } { auto rng = views::set_difference( debug_input_view{i1_finite}, debug_input_view{i2_finite} ); ::check_equal(rng, {1, 2, 3, 3, 3, 4, 4}); } return test_result(); }