| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- // Range v3 library
- //
- // Copyright Andrey Diduh 2019
- //
- // 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 <vector>
- #include <cstdlib>
- #include <ctime>
- #include <random>
- #include <range/v3/action/unstable_remove_if.hpp>
- #include <range/v3/action/remove_if.hpp>
- #include <range/v3/action/sort.hpp>
- #include "../array.hpp"
- #include "../simple_test.hpp"
- #include "../test_utils.hpp"
- void logic_test()
- {
- using namespace ranges;
- const auto make_vector = []() -> std::vector<int> {
- return {1,2,3,4,5};
- };
- // empty
- {
- std::vector<int> vec;
- vec |= actions::unstable_remove_if([](int) { return true; });
- CHECK(vec.empty());
- }
- // all stay
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int) { return false; });
- check_equal(vec, {1,2,3,4,5});
- }
- // all remove
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int) { return true; });
- CHECK(vec.empty());
- }
- // remove one in the middle
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 2; });
- check_equal(vec, {1,5,3,4});
- }
- // remove first
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 1; });
- check_equal(vec, {5,2,3,4});
- }
- // remove last
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 5; });
- check_equal(vec, {1,2,3,4});
- }
- // remove group in the middle
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 2 || i == 3 || i == 4; });
- check_equal(vec, {1,5});
- }
- // remove group in the begin
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 1 || i == 2 || i == 3; });
- check_equal(vec, {5,4});
- }
- // remove group in the end
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i == 3 || i == 4 || i == 5; });
- check_equal(vec, {1,2});
- }
- // remains one in the middle
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return i != 3; });
- check_equal(vec, {3});
- }
- // remains group in the middle
- {
- std::vector<int> vec = make_vector();
- vec |= actions::unstable_remove_if([](int i) { return (i != 3) && (i != 4); });
- check_equal(vec, {4,3});
- }
- }
- void num_pred_calls_test()
- {
- // std::ranges::remove_if requires:
- // "Exactly N applications of the corresponding predicate and any projection, where N = (last - first)"
- // https://en.cppreference.com/w/cpp/algorithm/ranges/remove
- // so expect the same of unstable_remove_if
- using namespace ranges;
- int pred_invocation_counter = 0;
- auto is_zero_count_invocations = [&pred_invocation_counter](int i) {
- ++pred_invocation_counter;
- return i == 0;
- };
- {
- std::vector<int> vec{0};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 1);
- }
- {
- std::vector<int> vec{1,1,1};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 3);
- }
- {
- std::vector<int> vec{1,0};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 2);
- }
- {
- std::vector<int> vec{1,2,0};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 3);
- }
- {
- std::vector<int> vec{0,0,0,0};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 4);
- }
- {
- std::vector<int> vec{1,2,3,0,0,0,0,4,5};
- pred_invocation_counter = 0;
- vec |= actions::unstable_remove_if(is_zero_count_invocations);
- check_equal(pred_invocation_counter, 9);
- }
- }
- class fuzzy_test_fn
- {
- int size;
- #if defined(__GLIBCXX__) && defined(RANGES_WORKAROUND_VALGRIND_RDRAND)
- std::random_device rd{"/dev/urandom"};
- #else
- std::random_device rd;
- #endif
- std::mt19937 eng{rd()};
- std::uniform_int_distribution<int> distr;
- public:
- explicit fuzzy_test_fn(int sz)
- : size(sz)
- , distr{0, sz}
- {}
- void operator()()
- {
- struct Int
- {
- int value;
- explicit Int(int v)
- : value(v)
- {}
- Int(Int const &) = default;
- Int(Int&& other) noexcept
- : value(0)
- {
- *this = std::move(other);
- }
- Int &operator=(Int const &) = default;
- Int &operator=(Int&& other) noexcept
- {
- const int sentinel = -1;
- CHECK(other.value != sentinel);
- value = other.value;
- other.value = sentinel;
- return *this;
- }
- RANGES_DIAGNOSTIC_PUSH
- RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_MEMBER
- bool operator==(Int const &other) const
- {
- return value == other.value;
- }
- bool operator!=(Int const &other) const
- {
- return value != other.value;
- }
- bool operator<(Int const &other) const
- {
- return value < other.value;
- }
- bool operator>(Int const &other) const
- {
- return value > other.value;
- }
- bool operator<=(Int const &other) const
- {
- return value <= other.value;
- }
- bool operator>=(Int const &other) const
- {
- return value >= other.value;
- }
- RANGES_DIAGNOSTIC_POP
- };
- using namespace ranges;
- std::vector<Int> ordered_list;
- std::vector<Int> unordered_list;
- // fill
- for(int i=0; i < size; ++i)
- {
- ordered_list.emplace_back(i);
- unordered_list.emplace_back(i);
- }
- // erase
- const int erase_count = distr(eng);
- for(int i=0; i < erase_count; ++i)
- {
- const int value = distr(eng);
- const auto pred = [value](Int j) { return j.value == value; };
- unordered_list |= actions::unstable_remove_if(pred);
- ordered_list |= actions::remove_if(pred);
- }
- // compare
- unordered_list |= actions::sort;
- CHECK(ordered_list == unordered_list);
- }
- };
- int main()
- {
- logic_test();
- num_pred_calls_test();
- {
- const int size = 100;
- const int repeats = 1000;
- fuzzy_test_fn fuzzy_test(size);
- for(int i=0; i < repeats; ++i)
- fuzzy_test();
- }
- return ::test_result();
- }
|