based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 0bc4b5da4aea6b51681aeaea21ddffcfe87b9510
parent d1259323ef4d4cf80573dc14c76064af133a49bd
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Sat, 5 Apr 2025 18:04:10 +0200

Test new algorithms and fix some issues

Diffstat:
M include/based/algorithm.hpp | +++++++++++++++++++++++++++ ----------------------------
M include/based/type_traits.hpp | ++++++++++++ --
M test/CMakeLists.txt | +++++
A test/source/count_if_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/source/count_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/source/find_if_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/source/find_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/source/for_each_test.cpp | ++++++++++++++++++++++++++++++++++++++++++++

8 files changed, 721 insertions(+), 30 deletions(-)


diff --git a/ include/based/algorithm.hpp b/ include/based/algorithm.hpp

@@ -168,7 +168,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 == next(f);
f = next(f);
}
return f;
}

@@ -178,7 +178,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 == next(f);
f = next(f);
}
return f;
}

@@ -189,7 +189,7 @@ I find_if(I f, I d, P p)

{
// Precondition: readable_bounded_range(f, d);
while (f != d && !p(*f)) {
f == next(f);
f = next(f);
}
return f;
}

@@ -200,7 +200,7 @@ I find_if_not(I f, I d, P p)

{
// Precondition: readable_bounded_range(f, d);
while (f != d && p(*f)) {
f == next(f);
f = next(f);
}
return f;
}

@@ -226,7 +226,7 @@ template<ReadableIterator I, UnaryPredicate P>

bool not_all(I f, I d, P p)
{
// Precondition: readable_bounded_range(f, d);
return find_if_not(f, d, p) != d;
return f == d || find_if_not(f, d, p) != d;
}

template<ReadableIterator I, UnaryPredicate P>

@@ -237,13 +237,12 @@ bool some(I f, I d, P p)

return find_if(f, d, p) != d;
}

template<ReadableIterator I, UnaryPredicate P, Iterator J>
requires SameAs<iter_value_t<I>, domain_t<P>>
J count_if(I f, I d, P p, J j)
template<ReadableIterator I, Iterator J>
J count(I f, I d, const iter_value_t<I>& x, J j)
{
// Precondition: readable_bounded_range(f, d);
while (f != d) {
if (p(*f)) {
if (*f == x) {
j = next(j);
}
f = next(f);

@@ -251,20 +250,18 @@ J count_if(I f, I d, P p, J j)

return j;
}

template<ReadableIterator I, UnaryPredicate P>
requires SameAs<iter_value_t<I>, domain_t<P>>
iter_dist_t<I> count_if(I f, I d, P p)
template<ReadableIterator I>
iter_dist_t<I> count(I f, I d, const iter_value_t<I>& x)
{
// Precondition: readable_bounded_range(f, d);
return count_if(f, d, p, iter_dist_t<I> {0});
return count(f, d, x, iter_dist_t<I> {0});
}

template<ReadableIterator I, Iterator J>
J count(I f, I d, const iter_value_t<I>& x, J j)
J count_not(I f, I d, const iter_value_t<I>& x, J j)
{
// Precondition: readable_bounded_range(f, d);
while (f != d) {
if (*f == x) {
if (*f != x) {
j = next(j);
}
f = next(f);

@@ -273,19 +270,19 @@ J count(I f, I d, const iter_value_t<I>& x, J j)

}

template<ReadableIterator I>
iter_dist_t<I> count(I f, I d, const iter_value_t<I>& x)
iter_dist_t<I> count_not(I f, I d, const iter_value_t<I>& x)
{
// Precondition: readable_bounded_range(f, d);
return count(f, d, x, iter_dist_t<I> {0});
return count_not(f, d, x, iter_dist_t<I> {0});
}

template<ReadableIterator I, UnaryPredicate P, Iterator J>
requires SameAs<iter_value_t<I>, domain_t<P>>
J count_if_not(I f, I d, P p, J j)
J count_if(I f, I d, P p, J j)
{
// Precondition: readable_bounded_range(f, d);
while (f != d) {
if (!p(*f)) {
if (p(*f)) {
j = next(j);
}
f = next(f);

@@ -295,18 +292,19 @@ J count_if_not(I f, I d, P p, J j)


template<ReadableIterator I, UnaryPredicate P>
requires SameAs<iter_value_t<I>, domain_t<P>>
iter_dist_t<I> count_if_not(I f, I d, P p)
iter_dist_t<I> count_if(I f, I d, P p)
{
// Precondition: readable_bounded_range(f, d);
return count_if_not(f, d, p, iter_dist_t<I> {0});
return count_if(f, d, p, iter_dist_t<I> {0});
}

template<ReadableIterator I, Iterator J>
J count_not(I f, I d, const iter_value_t<I>& x, J j)
template<ReadableIterator I, UnaryPredicate P, Iterator J>
requires SameAs<iter_value_t<I>, domain_t<P>>
J count_if_not(I f, I d, P p, J j)
{
// Precondition: readable_bounded_range(f, d);
while (f != d) {
if (*f != x) {
if (!p(*f)) {
j = next(j);
}
f = next(f);

@@ -314,11 +312,12 @@ J count_not(I f, I d, const iter_value_t<I>& x, J j)

return j;
}

template<ReadableIterator I>
iter_dist_t<I> count_not(I f, I d, const iter_value_t<I>& x)
template<ReadableIterator I, UnaryPredicate P>
requires SameAs<iter_value_t<I>, domain_t<P>>
iter_dist_t<I> count_if_not(I f, I d, P p)
{
// Precondition: readable_bounded_range(f, d);
return count_not(f, d, x, iter_dist_t<I> {0});
return count_if_not(f, d, p, iter_dist_t<I> {0});
}

} // namespace based

diff --git a/ include/based/type_traits.hpp b/ include/based/type_traits.hpp

@@ -50,12 +50,22 @@ concept BareSameAs = SameAs<bare_t<T>, bare_t<U>>;

namespace detail {
template<typename I>
struct iterator_traits {
using value_type = I;
using distance_type = std::uint64_t;
using pointer_type = I&;
using reference_type = I*;
};

template<typename I>
requires std::input_or_output_iterator<I>
struct iterator_traits<I> {
using value_type = std::iterator_traits<I>::value_type;
using distance_type = std::iterator_traits<I>::difference_type;
using pointer_type = std::iterator_traits<I>::pointer;
using reference_type = std::iterator_traits<I>::reference;
};


} // namespace detail


@@ -74,8 +84,8 @@ using iter_ref_t = detail::iterator_traits<T>::reference;

template<typename T>
concept Readable = requires(T t) {
requires(Regular<T>);
typename T::value_type;
{ *t } -> std::same_as<typename T::value_type>;
typename iter_value_t<T>;
{ *t } -> BareSameAs<iter_value_t<T>>;
};

template<typename T>

diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt

@@ -27,6 +27,11 @@ add_test(min_element_test)

add_test(max_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)
add_test(count_test)
add_test(count_if_test)

# ---- List ----
add_test(list_test)

diff --git a/ test/source/count_if_test.cpp b/ test/source/count_if_test.cpp

@@ -0,0 +1,126 @@

#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 return type", "[algorithm/count_if]")
{
std::array<int, 0> arr = {};

REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_if(
std::begin(arr), std::end(arr), predicate {0}))>);

REQUIRE(based::SameAs<std::uint8_t,
decltype(based::count_if(std::begin(arr),
std::end(arr),
predicate {0},
std::uint8_t {0}))>);
}

TEST_CASE("count_if(empty)", "[algorithm/count_if]")
{
std::array<int, 0> arr = {};

const auto count =
based::count_if(std::begin(arr), std::end(arr), predicate {0});

REQUIRE(count == 0);
}

TEST_CASE("count_if(homogeneous)", "[algorithm/count_if]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});

REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}

TEST_CASE("count_if(non homogeneous)", "[algorithm/count_if]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

const auto count0 =
based::count_if(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if(std::begin(arr), std::end(arr), predicate {2});

REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}

TEST_CASE("count_if_not return type", "[algorithm/count_if_not]")
{
std::array<int, 0> arr = {};

REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_if_not(
std::begin(arr), std::end(arr), predicate {0}))>);

REQUIRE(based::SameAs<std::uint8_t,
decltype(based::count_if_not(std::begin(arr),
std::end(arr),
predicate {0},
std::uint8_t {0}))>);
}

TEST_CASE("count_if_not(empty)", "[algorithm/count_if_not]")
{
std::array<int, 0> arr = {};

const auto count =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});

REQUIRE(count == 0);
}

TEST_CASE("count_if_not(homogeneous)", "[algorithm/count_if_not]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});

REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}

TEST_CASE("count_if_not(non homogeneous)", "[algorithm/count_if_not]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

const auto count0 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto count1 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto count2 =
based::count_if_not(std::begin(arr), std::end(arr), predicate {2});

REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}

diff --git a/ test/source/count_test.cpp b/ test/source/count_test.cpp

@@ -0,0 +1,100 @@

#include <array>

#include <catch2/catch_test_macros.hpp>

#include "based/algorithm.hpp"
#include "based/type_traits.hpp"

TEST_CASE("count return type", "[algorithm/count]")
{
std::array<int, 0> arr = {};

REQUIRE(
based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count(std::begin(arr), std::end(arr), 0))>);

REQUIRE(
based::SameAs<std::uint8_t,
decltype(based::count(
std::begin(arr), std::end(arr), 0, std::uint8_t {0}))>);
}

TEST_CASE("count(empty)", "[algorithm/count]")
{
std::array<int, 0> arr = {};

const auto count = based::count(std::begin(arr), std::end(arr), 0);

REQUIRE(count == 0);
}

TEST_CASE("count(homogeneous)", "[algorithm/count]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);

REQUIRE(count0 == 0);
REQUIRE(count1 == 6);
}

TEST_CASE("count(non homogeneous)", "[algorithm/count]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

const auto count0 = based::count(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count(std::begin(arr), std::end(arr), 2);

REQUIRE(count0 == 0);
REQUIRE(count1 == 4);
REQUIRE(count2 == 2);
}

TEST_CASE("count_not return type", "[algorithm/count_not]")
{
std::array<int, 0> arr = {};

REQUIRE(based::SameAs<based::iter_dist_t<decltype(arr)::iterator>,
decltype(based::count_not(
std::begin(arr), std::end(arr), 0))>);

REQUIRE(
based::SameAs<std::uint8_t,
decltype(based::count_not(
std::begin(arr), std::end(arr), 0, std::uint8_t {0}))>);
}

TEST_CASE("count_not(empty)", "[algorithm/count_not]")
{
std::array<int, 0> arr = {};

const auto count_not = based::count_not(std::begin(arr), std::end(arr), 0);

REQUIRE(count_not == 0);
}

TEST_CASE("count_not(homogeneous)", "[algorithm/count_not]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);

REQUIRE(count0 == 6);
REQUIRE(count1 == 0);
}

TEST_CASE("count_not(non homogeneous)", "[algorithm/count_not]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

const auto count0 = based::count_not(std::begin(arr), std::end(arr), 0);
const auto count1 = based::count_not(std::begin(arr), std::end(arr), 1);
const auto count2 = based::count_not(std::begin(arr), std::end(arr), 2);

REQUIRE(count0 == 6);
REQUIRE(count1 == 2);
REQUIRE(count2 == 4);
}

diff --git a/ test/source/find_if_test.cpp b/ test/source/find_if_test.cpp

@@ -0,0 +1,265 @@

#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(empty)", "[algorithm/find_if]")
{
std::array<int, 0> arr = {};
const auto* it =
based::find_if(std::begin(arr), std::end(arr), predicate {0});

REQUIRE(it == std::end(arr));
}

TEST_CASE("find_if(one) = found", "[algorithm/find_if]")
{
std::array arr = {0};

SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find_if(two) = found", "[algorithm/find_if]")
{
std::array arr = {0, 1};

SECTION("found 1")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("found 2")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}

SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {2});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}

TEST_CASE("find_if(multiple) = found", "[algorithm/find_if]")
{
std::array arr = {0, 0, 0, 0};

SECTION("found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr =
based::find_if(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}

TEST_CASE("find_if_not(empty)", "[algorithm/find_if_not]")
{
std::array<int, 0> arr = {};
const auto* it =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});

REQUIRE(it == std::end(arr));
}

TEST_CASE("find_if_not(one) = found", "[algorithm/find_if_not]")
{
std::array arr = {0};

SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});

const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find_if_not(two) = found", "[algorithm/find_if_not]")
{
std::array arr = {0, 1};

SECTION("found 1")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("found 2")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find_if_not(multiple) = found", "[algorithm/find_if_not]")
{
std::array arr = {0, 0, 0, 0};

SECTION("found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {1});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr =
based::find_if_not(std::begin(arr), std::end(arr), predicate {0});
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}

TEST_CASE("all(empty)", "[algorithm/all]")
{
std::array<int, 0> arr = {};

REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {0}));
}

TEST_CASE("all(homogeneous)", "[algorithm/all]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

REQUIRE(based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}

TEST_CASE("all(non homogenous)", "[algorithm/all]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::all(std::begin(arr), std::end(arr), predicate {2}));
}

TEST_CASE("none(empty)", "[algorithm/none]")
{
std::array<int, 0> arr = {};

REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
}

TEST_CASE("none(homogeneous)", "[algorithm/none]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}

TEST_CASE("none(non homogeneous)", "[algorithm/none]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

REQUIRE(based::none(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::none(std::begin(arr), std::end(arr), predicate {1}));
}

TEST_CASE("not_all(empty)", "[algorithm/not_all]")
{
std::array<int, 0> arr = {};

REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
}

TEST_CASE("not_all(homogeneous)", "[algorithm/not_all]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::not_all(std::begin(arr), std::end(arr), predicate {1}));
}

TEST_CASE("not_all(non homogeneous)", "[algorithm/not_all]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {0}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::not_all(std::begin(arr), std::end(arr), predicate {2}));
}

TEST_CASE("some(empty)", "[algorithm/some]")
{
std::array<int, 0> arr = {};

REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}

TEST_CASE("some(homogeneous)", "[algorithm/some]")
{
std::array arr = {1, 1, 1, 1, 1, 1};

REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {2}));
}

TEST_CASE("some(non homogeneous)", "[algorithm/some]")
{
std::array arr = {1, 2, 1, 1, 1, 2};

REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {1}));
REQUIRE(based::some(std::begin(arr), std::end(arr), predicate {2}));
REQUIRE(!based::some(std::begin(arr), std::end(arr), predicate {0}));
}

diff --git a/ test/source/find_test.cpp b/ test/source/find_test.cpp

@@ -0,0 +1,142 @@

#include <array>

#include <catch2/catch_test_macros.hpp>

#include "based/algorithm.hpp"

TEST_CASE("find(empty)", "[algorithm/find]")
{
std::array<int, 0> arr = {};
const auto* it = based::find(std::begin(arr), std::end(arr), 0);

REQUIRE(it == std::end(arr));
}

TEST_CASE("find(one) = found", "[algorithm/find]")
{
std::array arr = {0};

SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find(two) = found", "[algorithm/find]")
{
std::array arr = {0, 1};

SECTION("found 1")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("found 2")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}

SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 2);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 2);
}
}

TEST_CASE("find(multiple) = found", "[algorithm/find]")
{
std::array arr = {0, 0, 0, 0};

SECTION("found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr = based::find(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}

TEST_CASE("find_not(empty)", "[algorithm/find_not]")
{
std::array<int, 0> arr = {};
const auto* it = based::find_not(std::begin(arr), std::end(arr), 0);

REQUIRE(it == std::end(arr));
}

TEST_CASE("find_not(one) = found", "[algorithm/find_not]")
{
std::array arr = {0};

SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find_not(two) = found", "[algorithm/find_not]")
{
std::array arr = {0, 1};

SECTION("found 1")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("found 2")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 1);
}
}

TEST_CASE("find_not(multiple) = found", "[algorithm/find_not]")
{
std::array arr = {0, 0, 0, 0};

SECTION("found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 1);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 0);
}

SECTION("not found")
{
const auto* itr = based::find_not(std::begin(arr), std::end(arr), 0);
const auto idx = std::distance(std::cbegin(arr), itr);
REQUIRE(idx == 4);
}
}

diff --git a/ test/source/for_each_test.cpp b/ test/source/for_each_test.cpp

@@ -0,0 +1,44 @@

#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(empty)", "[algorithm/for_each]")
{
std::array<int, 0> arr = {};
const auto f = based::for_each(std::begin(arr), std::end(arr), functor {});

REQUIRE(f.sum == 0);
}

TEST_CASE("for_each(one)", "[algorithm/for_each]")
{
std::array arr = {1};
const auto f = based::for_each(std::begin(arr), std::end(arr), functor {});

REQUIRE(f.sum == 1);
}

TEST_CASE("for_each(two)", "[algorithm/for_each]")
{
std::array arr = {1, 2};
const auto f = based::for_each(std::begin(arr), std::end(arr), functor {});

REQUIRE(f.sum == 3);
}

TEST_CASE("for_each(three)", "[algorithm/for_each]")
{
std::array arr = {1, 2, 3};
const auto f = based::for_each(std::begin(arr), std::end(arr), functor {});

REQUIRE(f.sum == 6);
}