// 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 #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; }); // symmetric difference between two finite ranges/sets { auto res = views::set_symmetric_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 symmetric difference of finite ranges should be finite!"); ::check_equal(res, {-3, 1, 2, 3, 3, 3, 4, 4, 6, 9}); // check if the final result agrees with the greedy algorithm std::vector greedy_sd; set_symmetric_difference(i1_finite, i2_finite, back_inserter(greedy_sd)); ::check_equal(res, greedy_sd); auto it = begin(res); CHECK(&*it == &*(begin(i2_finite))); ++it; CHECK(&*it == &*(begin(i1_finite))); } // symmetric difference between two infinite ranges { auto res = views::set_symmetric_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, common_type_t, range_value_t>>); CPP_assert(same_as, common_reference_t, range_reference_t> >); CPP_assert(same_as, common_reference_t, range_rvalue_reference_t> >); static_assert(range_cardinality::value == ranges::unknown, "Cardinality of symmetric difference between infinite ranges should be unknown!"); ::check_equal(res | views::take(6), {1, 3, 4, 6, 12, 15}); // check if the final result agrees with the greedy algorithm std::vector greedy_sd; set_symmetric_difference(i1_infinite | views::take(10), i2_infinite | views::take(10), back_inserter(greedy_sd)); ::check_equal(res | views::take(6), greedy_sd | views::take(6)); } // symmetric difference between a finite and an infinite range { auto res1 = views::set_symmetric_difference(i1_finite, i2_infinite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R1 = decltype(res1); CPP_assert(same_as, int>); CPP_assert(same_as, int>); // our infinite range does not give out references CPP_assert(same_as, int>); static_assert(range_cardinality::value == ranges::infinite, "Cardinality of symmetric difference between a finite and an infinite range should be infinite!"); ::check_equal(res1 | views::take(10), {0, 2, 2, 3, 3, 3, 4, 4, 4, 9}); // now swap the operands: auto res2 = views::set_symmetric_difference(i2_infinite, i1_finite); CPP_assert(view_); CPP_assert(forward_range); CPP_assert(!random_access_range); CPP_assert(!common_range); using R2 = decltype(res2); CPP_assert(same_as, int>); CPP_assert(same_as, int>); // our infinite range does not give out references CPP_assert(same_as, int>); static_assert(range_cardinality::value == ranges::infinite, "Cardinality of symmetric difference between a finite and an infinite range should be infinite!"); ::check_equal(res1 | views::take(10), res2 | views::take(10)); } // symmetric 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_symmetric_difference(i2_finite, rng0); static_assert(range_cardinality::value == ranges::unknown, "Symmetric difference between a finite and unknown cardinality set should have unknown cardinality!"); auto res2 = views::set_symmetric_difference(rng0, i2_finite); static_assert(range_cardinality::value == ranges::unknown, "Symmetric difference between an unknown and finite cardinality set should have unknown cardinality!"); auto res3 = views::set_symmetric_difference(i1_infinite, rng0); static_assert(range_cardinality::value == ranges::unknown, "Symmetric difference between an infinite and unknown cardinality set should have unknown cardinality!"); auto res4 = views::set_symmetric_difference(rng0, i1_infinite); static_assert(range_cardinality::value == ranges::unknown, "Symmetric difference between an unknown and infinite cardinality set should have infinite cardinality!"); auto res5 = views::set_symmetric_difference(rng0, rng0); static_assert(range_cardinality::value == ranges::unknown, "Symmetric difference between two unknown cardinality sets should have unknown cardinality!"); } // test const ranges { auto res1 = views::set_symmetric_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_symmetric_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_symmetric_difference(views::reverse(i1_finite), views::reverse(i2_finite), [](int a, int b) { return a > b; }); ::check_equal(res, {9, 6, 4, 4, 3, 3, 3, 2, 1, -3}); CHECK(&*begin(res) == &*(begin(i2_finite) + 5)); } struct B { int val; B(int i): val{i} {} bool operator==(const B& other) const { return val == other.val; } }; struct D: public B { D(int i): B{i} {} D(B b): B{std::move(b)} {} }; B b_finite[] = {B{-20}, B{-10}, B{1}, B{3}, B{3}, B{6}, B{8}, B{20}}; D d_finite[] = {D{0}, D{2}, D{4}, D{6}}; // sets with different element types, custom orderings { auto res = views::set_symmetric_difference(b_finite, d_finite, [](const B& a, const D& b){ return a.val < b.val; }); CPP_assert(same_as, B>); CPP_assert(same_as, B&>); CPP_assert(same_as, B&&>); ::check_equal(res, {B{-20}, B{-10}, B{0}, B{1}, B{2}, B{3}, B{3}, B{4}, B{8}, B{20}}); auto it = begin(res); CHECK(&*it == &*begin(b_finite)); advance(it, 2); CHECK(&*it == &*begin(d_finite)); } // projections { auto res1 = views::set_symmetric_difference(b_finite, d_finite, less(), &B::val, &D::val ); CPP_assert(same_as, B>); CPP_assert(same_as, B&>); CPP_assert(same_as, B&&>); ::check_equal(res1, {B{-20}, B{-10}, B{0}, B{1}, B{2}, B{3}, B{3}, B{4}, B{8}, B{20}}); auto res2 = views::set_symmetric_difference(views::ints(-2, 10), b_finite, less(), identity(), [](const B& x){ return x.val; } ); CPP_assert(same_as, B>); CPP_assert(same_as, B>); CPP_assert(same_as, B>); ::check_equal(res2, {B{-20}, B{-10}, B{-2}, B{-1}, B{0}, B{2}, B{3}, B{4}, B{5}, B{7}, B{9}, B{20}}); } // move { auto v0 = to>({"a","b","b","c","x","x"}); auto v1 = to>({"b","x","y","z"}); auto res = views::set_symmetric_difference(v0, v1, [](const MoveOnlyString& a, const MoveOnlyString& b){return a expected; move(res, back_inserter(expected)); ::check_equal(expected, {"a","b","c","x","y","z"}); ::check_equal(v1, {"b","x","",""}); ::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_symmetric_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_symmetric_difference between two infinite ranges can create infinite loops! // { // auto empty_range = views::set_symmetric_difference(views::ints, views::ints); // begin(empty_range); // infinite loop! // } // iterator (in)equality { int r1[] = {1, 2, 3}; int r2[] = { 2, 3, 4, 5}; auto res = views::set_symmetric_difference(r1, r2); // 1, 4, 5 auto it1 = ranges::next(res.begin()); // *it1 == 4, member iterator into r1 points to r1.end() auto it2 = ranges::next(it1); // *it2 == 5, member iterator into r1 also points to r1.end() auto sentinel = res.end(); CHECK(*it1 == 4); CHECK(*it2 == 5); CHECK(it1 != it2); // should be different even though member iterators into r1 are the same CHECK(it1 != sentinel); CHECK(ranges::next(it1, 2) == sentinel); CHECK(it2 != sentinel); CHECK(ranges::next(it2, 1) == sentinel); } { auto rng = views::set_symmetric_difference( debug_input_view{i1_finite}, debug_input_view{i2_finite} ); ::check_equal(rng, {-3, 1, 2, 3, 3, 3, 4, 4, 6, 9}); } return test_result(); }