#include <algorithm>
#include <numeric>
#include "check_assertion.h"
#include "test_execution_policies.h"
#include "test_iterators.h"
template <class F>
void assert_non_throwing(F f) {
EXPECT_STD_TERMINATE([&] {
bool threw = false;
try {
f();
} catch (...) {
threw = true;
}
if (!threw)
std::terminate();
});
}
struct ThrowToken {
void activate() { active_ = true; }
void deactivate() { active_ = false; }
bool active() const { return active_; }
private:
bool active_{false};
};
template <class Func>
struct on_scope_exit {
explicit on_scope_exit(Func func) : func_(func) {}
~on_scope_exit() { func_(); }
private:
Func func_;
};
template <class Func>
on_scope_exit(Func) -> on_scope_exit<Func>;
int main(int, char**) {
test_execution_policies([&](auto&& policy) {
int a[] = {1, 2, 3, 4};
int b[] = {1, 2, 3};
int n = 2;
int storage[999];
int val = 99;
int init = 1;
ThrowToken tokens[7];
for (ThrowToken& t : tokens) {
t.activate();
on_scope_exit _([&] { t.deactivate(); });
auto first1 = util::throw_on_move_iterator(std::begin(a), tokens[0].active() ? 1 : -1);
auto last1 = util::throw_on_move_iterator(std::end(a), tokens[1].active() ? 1 : -1);
auto first2 = util::throw_on_move_iterator(std::begin(b), tokens[2].active() ? 1 : -1);
auto last2 = util::throw_on_move_iterator(std::end(b), tokens[3].active() ? 1 : -1);
auto dest = util::throw_on_move_iterator(std::end(storage), tokens[4].active() ? 1 : -1);
auto maybe_throw = [](ThrowToken const& token, auto f) {
return [&token, f](auto... args) {
if (token.active())
throw 1;
return f(args...);
};
};
{
auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; });
assert_non_throwing([=, &policy] { (void)std::all_of(policy, std::move(first1), std::move(last1), pred); });
assert_non_throwing([=, &policy] { (void)std::any_of(policy, std::move(first1), std::move(last1), pred); });
assert_non_throwing([=, &policy] { (void)std::none_of(policy, std::move(first1), std::move(last1), pred); });
}
{
assert_non_throwing([=, &policy] {
(void)std::copy(policy, std::move(first1), std::move(last1), std::move(dest));
});
assert_non_throwing([=, &policy] { (void)std::copy_n(policy, std::move(first1), n, std::move(dest)); });
}
{
auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; });
assert_non_throwing([=, &policy] { (void)std::count(policy, std::move(first1), std::move(last1), val); });
assert_non_throwing([=, &policy] { (void)std::count_if(policy, std::move(first1), std::move(last1), pred); });
}
{
auto binary_pred = maybe_throw(tokens[5], [](int x, int y) -> bool { return x == y; });
assert_non_throwing([=, &policy] {
(void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2));
});
assert_non_throwing([=, &policy] {
(void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2), binary_pred);
});
assert_non_throwing([=, &policy] {
(void)std::equal(policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2));
});
assert_non_throwing([=, &policy] {
(void)std::equal(
policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), binary_pred);
});
}
{
assert_non_throwing([=, &policy] { (void)std::fill(policy, std::move(first1), std::move(last1), val); });
assert_non_throwing([=, &policy] { (void)std::fill_n(policy, std::move(first1), n, val); });
}
{
auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; });
assert_non_throwing([=, &policy] { (void)std::find(policy, std::move(first1), std::move(last1), val); });
assert_non_throwing([=, &policy] { (void)std::find_if(policy, std::move(first1), std::move(last1), pred); });
assert_non_throwing([=, &policy] {
(void)std::find_if_not(policy, std::move(first1), std::move(last1), pred);
});
}
{
auto func = maybe_throw(tokens[5], [](int) {});
assert_non_throwing([=, &policy] { (void)std::for_each(policy, std::move(first1), std::move(last1), func); });
assert_non_throwing([=, &policy] { (void)std::for_each_n(policy, std::move(first1), n, func); });
}
{
auto gen = maybe_throw(tokens[5], []() -> int { return 42; });
assert_non_throwing([=, &policy] { (void)std::generate(policy, std::move(first1), std::move(last1), gen); });
assert_non_throwing([=, &policy] { (void)std::generate_n(policy, std::move(first1), n, gen); });
}
{
auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; });
assert_non_throwing([=, &policy] {
(void)std::is_partitioned(policy, std::move(first1), std::move(last1), pred);
});
}
{
auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
assert_non_throwing([=, &policy] {
(void)std::merge(
policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), std::move(dest));
});
assert_non_throwing([=, &policy] {
(void)std::merge(
policy,
std::move(first1),
std::move(last1),
std::move(first2),
std::move(last2),
std::move(dest),
compare);
});
}
{
assert_non_throwing([=, &policy] {
(void)std::move(policy, std::move(first1), std::move(last1), std::move(dest));
});
}
{
auto pred = maybe_throw(tokens[5], [](int x) -> bool { return x % 2 == 0; });
assert_non_throwing([=, &policy] {
(void)std::replace_if(policy, std::move(first1), std::move(last1), pred, val);
});
assert_non_throwing([=, &policy] {
(void)std::replace(policy, std::move(first1), std::move(last1), val, val);
});
assert_non_throwing([=, &policy] {
(void)std::replace_copy_if(policy, std::move(first1), std::move(last1), std::move(dest), pred, val);
});
assert_non_throwing([=, &policy] {
(void)std::replace_copy(policy, std::move(first1), std::move(last1), std::move(dest), val, val);
});
}
{
auto mid1 = util::throw_on_move_iterator(std::begin(a) + 2, tokens[5].active() ? 1 : -1);
assert_non_throwing([=, &policy] {
(void)std::rotate_copy(policy, std::move(first1), std::move(mid1), std::move(last1), std::move(dest));
});
}
{
auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
assert_non_throwing([=, &policy] { (void)std::sort(policy, std::move(first1), std::move(last1)); });
assert_non_throwing([=, &policy] { (void)std::sort(policy, std::move(first1), std::move(last1), compare); });
assert_non_throwing([=, &policy] { (void)std::stable_sort(policy, std::move(first1), std::move(last1)); });
assert_non_throwing([=, &policy] {
(void)std::stable_sort(policy, std::move(first1), std::move(last1), compare);
});
}
{
auto unary = maybe_throw(tokens[5], [](int x) -> int { return x * 2; });
auto binary = maybe_throw(tokens[5], [](int x, int y) -> int { return x * y; });
assert_non_throwing([=, &policy] {
(void)std::transform(policy, std::move(first1), std::move(last1), std::move(dest), unary);
});
assert_non_throwing([=, &policy] {
(void)std::transform(policy, std::move(first1), std::move(last1), std::move(first2), std::move(dest), binary);
});
}
{
auto reduction = maybe_throw(tokens[5], [](int x, int y) -> int { return x + y; });
auto transform_unary = maybe_throw(tokens[6], [](int x) -> int { return x * 2; });
auto transform_binary = maybe_throw(tokens[6], [](int x, int y) -> int { return x * y; });
assert_non_throwing([=, &policy] {
(void)std::transform_reduce(policy, std::move(first1), std::move(last1), std::move(first2), init);
});
assert_non_throwing([=, &policy] {
(void)std::transform_reduce(policy, std::move(first1), std::move(last1), init, reduction, transform_unary);
});
assert_non_throwing([=, &policy] {
(void)std::transform_reduce(
policy, std::move(first1), std::move(last1), std::move(first2), init, reduction, transform_binary);
});
}
{
auto reduction = maybe_throw(tokens[5], [](int x, int y) -> int { return x + y; });
assert_non_throwing([=, &policy] { (void)std::reduce(policy, std::move(first1), std::move(last1)); });
assert_non_throwing([=, &policy] { (void)std::reduce(policy, std::move(first1), std::move(last1), init); });
assert_non_throwing([=, &policy] {
(void)std::reduce(policy, std::move(first1), std::move(last1), init, reduction);
});
}
}
});
}