basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 04604e394557ca3e96f6ebc54d254543f694e1e1 |
parent | 7878c84a84832916d834b32a13cf5ff504896ef1 |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Tue, 8 Apr 2025 14:42:21 +0200 |
Counted Range version of algorithms, with tests
Diffstat:M | include/based/algorithm.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
M | include/based/iterator.hpp | | | +++--- |
M | test/CMakeLists.txt | | | +++++++++++++++++-- |
A | test/source/count_if_n_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/count_n_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/find_if_n_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/find_n_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | test/source/for_each_n_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
8 files changed, 1040 insertions(+), 36 deletions(-)
diff --git a/include/based/algorithm.hpp b/include/based/algorithm.hpp
@@ -12,6 +12,8 @@ namespace based
namespace detail
{
/* ----- Min and Max ----- */
template<typename P, typename Arg>
concept NoninputRelation = requires {
requires(RegularProcedure<P, Arg, Arg>);
@@ -38,6 +40,25 @@ decltype(auto) min(T&& lhs, U&& rhs)
std::forward<T>(lhs), std::forward<U>(rhs), std::less<bare_t<T>>());
}
// returns max element, second if equal
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> R>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs, R r)
{
return r(rhs, lhs) ? std::forward<T>(lhs) : std::forward<U>(rhs);
}
// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<bare_t<T>>());
}
/* ----- Bounded Range Algorithms ----- */
// return first min element
template<Iterator I, IterRelation<I> R>
I min_element(I first, I last, R r)
@@ -62,23 +83,6 @@ I min_element(I first, I last)
return based::min_element(first, last, std::less<iter_value_t<I>>());
}
// returns max element, second if equal
template<BareRegular T, BareRegular U, detail::NoninputRelation<T> R>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs, R r)
{
return r(rhs, lhs) ? std::forward<T>(lhs) : std::forward<U>(rhs);
}
// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<bare_t<T>>());
}
// return last max element
template<Iterator I, IterRelation<I> R>
I max_element(I first, I last, R r)
@@ -121,7 +125,7 @@ std::pair<I, I> minmax_element(I first, I last, R r)
std::swap(mini, maxi);
}
I next = based::next(first);
I next = successor(first);
while (first != last && next != last) {
I pmini = first;
I pmaxi = next;
@@ -166,7 +170,7 @@ Proc for_each(I f, I d, Proc proc)
// Precondition: readable_bounded_range(f, d);
while (f != d) {
proc(*f);
f++;
f = successor(f);
}
return proc;
}
@@ -176,7 +180,7 @@ I find(I f, I d, const iter_value_t<I>& x)
{
// Precondition: readable_bounded_range(f, d);
while (f != d && *f != x) {
f++;
f = successor(f);
}
return f;
}
@@ -186,7 +190,7 @@ I find_not(I f, I d, const iter_value_t<I>& x)
{
// Precondition: readable_bounded_range(f, d);
while (f != d && *f == x) {
f++;
f = successor(f);
}
return f;
}
@@ -196,7 +200,7 @@ I find_if(I f, I d, P p)
{
// Precondition: readable_bounded_range(f, d);
while (f != d && !p(*f)) {
f++;
f = successor(f);
}
return f;
}
@@ -206,7 +210,7 @@ I find_if_not(I f, I d, P p)
{
// Precondition: readable_bounded_range(f, d);
while (f != d && p(*f)) {
f++;
f = successor(f);
}
return f;
}
@@ -247,7 +251,7 @@ J count(I f, I d, const iter_value_t<I>& x, J j)
if (*f == x) {
j++;
}
f++;
f = successor(f);
}
return j;
}
@@ -267,7 +271,7 @@ J count_not(I f, I d, const iter_value_t<I>& x, J j)
if (*f != x) {
j++;
}
f++;
f = successor(f);
}
return j;
}
@@ -287,7 +291,7 @@ J count_if(I f, I d, P p, J j)
if (p(*f)) {
j++;
}
f++;
f = successor(f);
}
return j;
}
@@ -307,7 +311,7 @@ J count_if_not(I f, I d, P p, J j)
if (!p(*f)) {
j++;
}
f++;
f = successor(f);
}
return j;
}
@@ -327,10 +331,10 @@ auto reduce_nonempty(I f, I d, Op op, F fun)
// Precondition: partially_associative(op)
auto r = fun(f);
f++;
f = successor(f);
while (f != d) {
r = op(r, fun(f));
f++;
f = successor(f);
}
return r;
}
@@ -359,7 +363,7 @@ auto reduce_nonzero(
return z;
}
x = fun(f);
f++;
f = successor(f);
} while (x == z);
while (f != d) {
@@ -367,9 +371,179 @@ auto reduce_nonzero(
if (y != z) {
x = op(x, y);
}
f++;
f = successor(f);
}
return x;
}
/* ----- Counted Range Algorithms ----- */
template<ReadableIterator I, IterUnaryProcedure<I> Proc>
auto for_each_n(I f, iter_dist_t<I> n, Proc proc)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n)) {
n = predecessor(n);
proc(*f);
f = successor(f);
}
return std::make_pair(proc, f);
}
template<ReadableIterator I>
auto find_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n) && *f != x) {
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, n);
}
template<ReadableIterator I>
auto find_not_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n) && *f == x) {
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, n);
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
auto find_if_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n) && !p(*f)) {
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, n);
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
auto find_if_not_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n) && p(*f)) {
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, n);
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
bool all_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, d);
return find_if_not_n(f, n, p).second == 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
bool none_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
return find_if_n(f, n, p).second == 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
bool not_all_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
return n == 0 || find_if_not_n(f, n, p).second != 0;
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
bool some_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
return find_if_n(f, n, p).second != 0;
}
template<ReadableIterator I, Iterator J>
auto count_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x, J j)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n)) {
if (*f == x) {
j++;
}
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, j);
}
template<ReadableIterator I>
auto count_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x)
{
// Precondition: readable_weak_range(f, n);
return count_n(f, n, x, iter_dist_t<I> {0});
}
template<ReadableIterator I, Iterator J>
auto count_not_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x, J j)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n)) {
if (*f != x) {
j++;
}
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, j);
}
template<ReadableIterator I>
auto count_not_n(I f, iter_dist_t<I> n, const iter_value_t<I>& x)
{
// Precondition: readable_weak_range(f, n);
return count_not_n(f, n, x, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> P, Iterator J>
auto count_if_n(I f, iter_dist_t<I> n, P p, J j)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n)) {
if (p(*f)) {
j++;
}
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, j);
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
auto count_if_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
return count_if_n(f, n, p, iter_dist_t<I> {0});
}
template<ReadableIterator I, IterUnaryPredicate<I> P, Iterator J>
auto count_if_not_n(I f, iter_dist_t<I> n, P p, J j)
{
// Precondition: readable_weak_range(f, n);
while (!zero(n)) {
if (!p(*f)) {
j++;
}
n = predecessor(n);
f = successor(f);
}
return std::make_pair(f, j);
}
template<ReadableIterator I, IterUnaryPredicate<I> P>
auto count_if_not_n(I f, iter_dist_t<I> n, P p)
{
// Precondition: readable_weak_range(f, n);
return count_if_not_n(f, n, p, iter_dist_t<I> {0});
}
} // namespace based
diff --git a/include/based/iterator.hpp b/include/based/iterator.hpp
@@ -5,7 +5,7 @@ namespace based
{
template<Iterator I>
I next(I i)
I successor(I i)
{
return ++i;
}
@@ -23,7 +23,7 @@ I operator+(I f, distance_t<I> n)
// Precondition: n >= 0 & weak_range(f, n)
while (!zero(n)) {
n = predecessor(n);
f = based::next(f);
f = successor(f);
}
return f;
}
@@ -35,7 +35,7 @@ distance_t<I> operator-(I d, I f)
distance_t<I> n {0};
while (f != d) {
n = successor(n);
f = next(f);
f = successor(f);
}
return n;
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
@@ -20,13 +20,19 @@ function(add_test NAME)
catch_discover_tests("${NAME}")
endfunction()
# ---- Algorithm ----
# ----- Algorithm -----
## ----- Min and Max -----
add_test(min_test)
add_test(min_element_test)
add_test(max_test)
## ----- Bounden Range -----
add_test(min_element_test)
add_test(max_element_test)
add_test(minmax_element_test)
add_test(for_each_test)
add_test(find_test)
add_test(find_if_test)
@@ -34,6 +40,15 @@ add_test(count_test)
add_test(count_if_test)
add_test(reduce_test)
## ----- Bounden Range -----
add_test(for_each_n_test)
add_test(find_n_test)
add_test(find_if_n_test)
add_test(count_n_test)
add_test(count_if_n_test)
# ---- List ----
add_test(list_test)
diff --git a/test/source/count_if_n_test.cpp b/test/source/count_if_n_test.cpp
@@ -0,0 +1,156 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("count_if_n return type", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(
based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_if_n(
std::begin(arr), std::size(arr), predicate {0})
.second)>);
REQUIRE(based::SameAs<std::uint8_t,
decltype(based::count_if_n(std::begin(arr),
std::size(arr),
predicate {0},
std::uint8_t {0})
.second)>);
}
TEST_CASE("count_if_n(empty)", "[algorithm/count_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_n(homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_n(non homogeneous)", "[algorithm/count_if_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
TEST_CASE("count_if_not_n return type", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(
based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_if_not_n(
std::begin(arr), std::size(arr), predicate {0})
.second)>);
REQUIRE(based::SameAs<std::uint8_t,
decltype(based::count_if_not_n(std::begin(arr),
std::size(arr),
predicate {0},
std::uint8_t {0})
.second)>);
}
TEST_CASE("count_if_not_n(empty)", "[algorithm/count_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_if_not_n(homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_if_not_n(non homogeneous)", "[algorithm/count_if_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto [itr1, count1] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto [itr2, count2] =
based::count_if_not_n(std::begin(arr), std::size(arr), predicate {2});
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/test/source/count_n_test.cpp b/test/source/count_n_test.cpp
@@ -0,0 +1,138 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
#include "based/type_traits.hpp"
TEST_CASE("count_n return type", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::SameAs<
based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_n(std::begin(arr), std::size(arr), 0).second)>);
REQUIRE(based::SameAs<
std::uint8_t,
decltype(based::count_n(
std::begin(arr), std::size(arr), 0, std::uint8_t {0})
.second)>);
}
TEST_CASE("count_n(empty)", "[algorithm/count_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] = based::count_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_n(homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 6);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_n(non homogeneous)", "[algorithm/count_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 0);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 4);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 2);
REQUIRE(itr2 == std::end(arr));
}
TEST_CASE("count_not_n return type", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_not_n(
std::begin(arr), std::size(arr), 0)
.second)>);
REQUIRE(based::SameAs<
std::uint8_t,
decltype(based::count_not_n(
std::begin(arr), std::size(arr), 0, std::uint8_t {0})
.second)>);
}
TEST_CASE("count_not_n(empty)", "[algorithm/count_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, count] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
REQUIRE(count == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("count_not_n(homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 0);
REQUIRE(itr1 == std::end(arr));
}
TEST_CASE("count_not_n(non homogeneous)", "[algorithm/count_not_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
const auto [itr0, count0] =
based::count_not_n(std::begin(arr), std::size(arr), 0);
const auto [itr1, count1] =
based::count_not_n(std::begin(arr), std::size(arr), 1);
const auto [itr2, count2] =
based::count_not_n(std::begin(arr), std::size(arr), 2);
REQUIRE(count0 == 6);
REQUIRE(itr0 == std::end(arr));
REQUIRE(count1 == 2);
REQUIRE(itr1 == std::end(arr));
REQUIRE(count2 == 4);
REQUIRE(itr2 == std::end(arr));
}
diff --git a/test/source/find_if_n_test.cpp b/test/source/find_if_n_test.cpp
@@ -0,0 +1,290 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct predicate
{
int goal;
explicit predicate(int init)
: goal(init)
{
}
auto operator()(int n) const { return n == goal; }
};
TEST_CASE("find_if_n(empty)", "[algorithm/find_if_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_n(one) = found", "[algorithm/find_if_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(two) = found", "[algorithm/find_if_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_n(multiple) = found", "[algorithm/find_if_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(empty)", "[algorithm/find_if_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
REQUIRE(itr == std::end(arr));
}
TEST_CASE("find_if_not_n(one) = found", "[algorithm/find_if_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(two) = found", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_if_not_n(multiple) = found", "[algorithm/find_if_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_if_not_n(std::begin(arr), std::size(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("all_n(empty)", "[algorithm/all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("all_n(homogeneous)", "[algorithm/all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("all_n(non homogenous)", "[algorithm/all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("none_n(empty)", "[algorithm/none_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("none_n(homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("none_n(non homogeneous)", "[algorithm/none_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::none_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::none_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("not_all_n(empty)", "[algorithm/not_all_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("not_all_n(homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
}
TEST_CASE("not_all_n(non homogeneous)", "[algorithm/not_all_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {0}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::not_all_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("some_n(empty)", "[algorithm/some_n]")
{
const std::array<int, 0> arr = {};
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
TEST_CASE("some_n(homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 1, 1, 1, 1, 1};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {2}));
}
TEST_CASE("some_n(non homogeneous)", "[algorithm/some_n]")
{
const std::array arr = {1, 2, 1, 1, 1, 2};
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {1}));
REQUIRE(based::some_n(std::begin(arr), std::size(arr), predicate {2}));
REQUIRE(!based::some_n(std::begin(arr), std::size(arr), predicate {0}));
}
diff --git a/test/source/find_n_test.cpp b/test/source/find_n_test.cpp
@@ -0,0 +1,179 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
TEST_CASE("find_n(empty)", "[algorithm/find_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_n(one) = found", "[algorithm/find_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(two) = found", "[algorithm/find_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_n(multiple) = found", "[algorithm/find_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] = based::find_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(empty)", "[algorithm/find_not_n]")
{
const std::array<int, 0> arr = {};
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
TEST_CASE("find_not_n(one) = found", "[algorithm/find_not_n]")
{
const std::array arr = {0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(two) = found", "[algorithm/find_not_n]")
{
const std::array arr = {0, 1};
SECTION("found 1")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("found 2")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
REQUIRE(idx + left == std::size(arr));
}
}
TEST_CASE("find_not_n(multiple) = found", "[algorithm/find_not_n]")
{
const std::array arr = {0, 0, 0, 0};
SECTION("found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
REQUIRE(idx + left == std::size(arr));
}
SECTION("not found")
{
const auto [itr, left] =
based::find_not_n(std::begin(arr), std::size(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
REQUIRE(idx + left == std::size(arr));
}
}
diff --git a/test/source/for_each_n_test.cpp b/test/source/for_each_n_test.cpp
@@ -0,0 +1,52 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "based/algorithm.hpp"
struct functor
{
int operator()(int n) { return sum += n; }
int sum = 0;
};
TEST_CASE("for_each_n(empty)", "[algorithm/for_each_n]")
{
const std::array<int, 0> arr = {};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 0);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(one)", "[algorithm/for_each_n]")
{
const std::array arr = {1};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 1);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(two)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 3);
REQUIRE(itr == std::end(arr));
}
TEST_CASE("for_each_n(three)", "[algorithm/for_each_n]")
{
const std::array arr = {1, 2, 3};
const auto [f, itr] =
based::for_each_n(std::begin(arr), std::size(arr), functor {});
REQUIRE(f.sum == 6);
REQUIRE(itr == std::end(arr));
}