Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
282 lines
7.4 KiB
C++
282 lines
7.4 KiB
C++
// 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();
|
|
}
|