flatten 20260225
This commit is contained in:
105
tjp/core/iterators/_tests/enumerate.cpp
Executable file
105
tjp/core/iterators/_tests/enumerate.cpp
Executable file
@@ -0,0 +1,105 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "../../testing/catch.hpp"
|
||||
#include "../enumerate.hpp"
|
||||
|
||||
#include "../../containers/Vector.hpp"
|
||||
#include "../../containers/List.hpp"
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::enumerate")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42, 1);
|
||||
|
||||
WHEN("iterating")
|
||||
{
|
||||
size_t last = 0;
|
||||
for (auto [e, v]: enumerate(l))
|
||||
{
|
||||
last = e;
|
||||
REQUIRE(v == 1);
|
||||
}
|
||||
|
||||
auto expected = l.size() - 1;
|
||||
REQUIRE(last == expected);
|
||||
}
|
||||
|
||||
WHEN("iterating and setting")
|
||||
{
|
||||
size_t last = 0;
|
||||
for (auto [e, v]: enumerate(l))
|
||||
{
|
||||
v = (int)e;
|
||||
}
|
||||
|
||||
for (auto [e, v]: enumerate(l))
|
||||
{
|
||||
last = e;
|
||||
REQUIRE(v == (int)e);
|
||||
}
|
||||
|
||||
auto expected = l.size() - 1;
|
||||
REQUIRE(last == expected);
|
||||
}
|
||||
|
||||
WHEN("iterating const")
|
||||
{
|
||||
const auto &lc = l;
|
||||
size_t last = 0;
|
||||
for (auto [e, v]: enumerate(lc))
|
||||
{
|
||||
last = e;
|
||||
REQUIRE(v == 1);
|
||||
}
|
||||
|
||||
auto expected = l.size() - 1;
|
||||
REQUIRE(last == expected);
|
||||
}
|
||||
|
||||
WHEN("iterating value")
|
||||
{
|
||||
const auto &lc = l;
|
||||
size_t last = 0;
|
||||
for (auto [e, v]: enumerate_value(lc))
|
||||
{
|
||||
last = e;
|
||||
REQUIRE(v == 1);
|
||||
}
|
||||
|
||||
auto expected = l.size() - 1;
|
||||
REQUIRE(last == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("a list")
|
||||
{
|
||||
List<int> l;
|
||||
l.resize(42, 1);
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t last = 0;
|
||||
for (auto [e, v]: enumerate(l))
|
||||
{
|
||||
last = e;
|
||||
REQUIRE(v == 1);
|
||||
}
|
||||
|
||||
auto expected = l.size() - 1;
|
||||
REQUIRE(last == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
31
tjp/core/iterators/_tests/fail_on_copy_vector.hpp
Executable file
31
tjp/core/iterators/_tests/fail_on_copy_vector.hpp
Executable file
@@ -0,0 +1,31 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/no_first.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
template<typename T>
|
||||
struct fail_on_copy_vector : Vector<T> {
|
||||
|
||||
fail_on_copy_vector(const fail_on_copy_vector &) {
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
fail_on_copy_vector(fail_on_copy_vector &&) {
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
fail_on_copy_vector(std::initializer_list<T> &&v) :
|
||||
Vector<T>(v)
|
||||
{}
|
||||
|
||||
fail_on_copy_vector() {}
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
42
tjp/core/iterators/_tests/is_first.cpp
Executable file
42
tjp/core/iterators/_tests/is_first.cpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/is_first.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::is_first")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42, 1);
|
||||
int expected = 10;
|
||||
l[0] = expected;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
int value = 0;
|
||||
is_first first;
|
||||
for (auto &v: l)
|
||||
{
|
||||
if (first)
|
||||
value = v;
|
||||
}
|
||||
|
||||
REQUIRE(value == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
76
tjp/core/iterators/_tests/no_first.cpp
Executable file
76
tjp/core/iterators/_tests/no_first.cpp
Executable file
@@ -0,0 +1,76 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/no_first.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::no_first")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42, 1);
|
||||
l.front() = 10;
|
||||
l.back() = 100;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto v: no_first(l))
|
||||
sum += v;
|
||||
|
||||
auto expected = 100 + 40;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("a list")
|
||||
{
|
||||
List<int> l;
|
||||
l.resize(42, 1);
|
||||
l.front() = 10;
|
||||
l.back() = 100;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto v: no_first(l))
|
||||
sum += v;
|
||||
|
||||
auto expected = 100 + 40;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("an empty list")
|
||||
{
|
||||
List<int> l;
|
||||
|
||||
WHEN("iterating")
|
||||
{
|
||||
size_t sum = 0;
|
||||
size_t count = 0;
|
||||
for (auto v: no_first(l))
|
||||
{
|
||||
sum += v;
|
||||
++count;
|
||||
}
|
||||
|
||||
REQUIRE(sum == 0);
|
||||
REQUIRE(count == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
76
tjp/core/iterators/_tests/no_last.cpp
Executable file
76
tjp/core/iterators/_tests/no_last.cpp
Executable file
@@ -0,0 +1,76 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/no_last.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::no_last")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42, 1);
|
||||
l.front() = 10;
|
||||
l.back() = 100;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto v: no_last(l))
|
||||
sum += v;
|
||||
|
||||
auto expected = 10 + 40;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("a list")
|
||||
{
|
||||
List<int> l;
|
||||
l.resize(42, 1);
|
||||
l.front() = 10;
|
||||
l.back() = 100;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto v: no_last(l))
|
||||
sum += v;
|
||||
|
||||
auto expected = 10 + 40;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("an empty list")
|
||||
{
|
||||
List<int> l;
|
||||
|
||||
WHEN("iterating")
|
||||
{
|
||||
size_t sum = 0;
|
||||
size_t count = 0;
|
||||
for (auto v: no_last(l))
|
||||
{
|
||||
sum += v;
|
||||
++count;
|
||||
}
|
||||
|
||||
REQUIRE(sum == 0);
|
||||
REQUIRE(count == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
61
tjp/core/iterators/_tests/range.cpp
Executable file
61
tjp/core/iterators/_tests/range.cpp
Executable file
@@ -0,0 +1,61 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/range.hpp>
|
||||
#include <tjp/core/algorithm/unused.hpp>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::range")
|
||||
{
|
||||
GIVEN("a range")
|
||||
{
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
auto X = 100;
|
||||
auto j = 0;
|
||||
for (auto i: range(X))
|
||||
{
|
||||
unused(i);
|
||||
j++;
|
||||
}
|
||||
|
||||
REQUIRE(j == X);
|
||||
}
|
||||
|
||||
WHEN("iterating X to Y")
|
||||
{
|
||||
auto X = 50, Y = 100;
|
||||
auto j = 0;
|
||||
for (auto i: range(X, Y))
|
||||
{
|
||||
unused(i);
|
||||
j++;
|
||||
}
|
||||
|
||||
REQUIRE(j == (Y-X));
|
||||
}
|
||||
|
||||
WHEN("iterating Y to X")
|
||||
{
|
||||
auto X = 50, Y = 100;
|
||||
auto j = 0;
|
||||
for (auto i: range(Y, X, -1))
|
||||
{
|
||||
unused(i);
|
||||
j++;
|
||||
}
|
||||
|
||||
REQUIRE(j == (Y-X));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
57
tjp/core/iterators/_tests/range_with.cpp
Executable file
57
tjp/core/iterators/_tests/range_with.cpp
Executable file
@@ -0,0 +1,57 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/range_with.hpp>
|
||||
#include <tjp/core/iterators/enumerate.hpp>
|
||||
#include <tjp/core/algorithm/unused.hpp>
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::range_with")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42);
|
||||
for (auto [i, v]: enumerate(l))
|
||||
v = (int)i;
|
||||
|
||||
GIVEN("a range")
|
||||
{
|
||||
WHEN("iterating first 5")
|
||||
{
|
||||
auto X = 5;
|
||||
auto j = 0;
|
||||
for (auto i: range_with(l, X))
|
||||
{
|
||||
unused(i);
|
||||
j += i;
|
||||
}
|
||||
|
||||
REQUIRE(j == (0+1+2+3+4));
|
||||
}
|
||||
|
||||
WHEN("iterating next 5")
|
||||
{
|
||||
auto X = 5;
|
||||
auto j = 0;
|
||||
for (auto i: range_with(l, X, X))
|
||||
{
|
||||
unused(i);
|
||||
j += i;
|
||||
}
|
||||
|
||||
REQUIRE(j == (5+6+7+8+9));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
43
tjp/core/iterators/_tests/reverse.cpp
Executable file
43
tjp/core/iterators/_tests/reverse.cpp
Executable file
@@ -0,0 +1,43 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/is_first.hpp>
|
||||
#include <tjp/core/iterators/reverse.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::reverse")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
l.resize(42, 1);
|
||||
int expected = 10;
|
||||
l.back() = expected;
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
int value = 0;
|
||||
is_first first;
|
||||
for (auto &v: reverse(l))
|
||||
{
|
||||
if (first)
|
||||
value = v;
|
||||
}
|
||||
|
||||
REQUIRE(value == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
85
tjp/core/iterators/_tests/safe_next.cpp
Executable file
85
tjp/core/iterators/_tests/safe_next.cpp
Executable file
@@ -0,0 +1,85 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/safe_next.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::safe_next")
|
||||
{
|
||||
GIVEN("a list")
|
||||
{
|
||||
List<int> l;
|
||||
l.resize(42, 1);
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
auto v = 0;
|
||||
for (auto i: safe_next(l))
|
||||
v += *i;
|
||||
|
||||
REQUIRE(v == 42);
|
||||
}
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
auto v = 0;
|
||||
auto e = -1;
|
||||
for (auto i: safe_next(l))
|
||||
{
|
||||
++e;
|
||||
v += *i;
|
||||
|
||||
if (e % 2 == 0)
|
||||
{
|
||||
l.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(v == 42);
|
||||
}
|
||||
|
||||
WHEN("iterating to X with vaue")
|
||||
{
|
||||
auto v = 0;
|
||||
for (auto x: safe_next_value(l))
|
||||
v += x;
|
||||
|
||||
REQUIRE(v == 42);
|
||||
}
|
||||
|
||||
WHEN("iterating to X with value")
|
||||
{
|
||||
auto v = 0;
|
||||
auto e = -1;
|
||||
auto i = l.begin();
|
||||
for (auto &x: safe_next_value(l))
|
||||
{
|
||||
auto n = i;
|
||||
n++;
|
||||
|
||||
++e;
|
||||
v += x;
|
||||
|
||||
if (e % 2 == 0)
|
||||
{
|
||||
l.erase(i);
|
||||
}
|
||||
|
||||
i = n;
|
||||
}
|
||||
|
||||
REQUIRE(v == 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
75
tjp/core/iterators/_tests/transform_with.cpp
Executable file
75
tjp/core/iterators/_tests/transform_with.cpp
Executable file
@@ -0,0 +1,75 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "../../testing/catch.hpp"
|
||||
#include "../transform_with.hpp"
|
||||
#include "../enumerate.hpp"
|
||||
|
||||
#include "../../containers/Vector.hpp"
|
||||
#include "../../containers/List.hpp"
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::transform_with")
|
||||
{
|
||||
GIVEN("a vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l = { 1, 3, 5, 7, 9 };
|
||||
auto make_even = [](auto &v) { return v + 1; };
|
||||
|
||||
WHEN("transform_with")
|
||||
{
|
||||
for (auto v: transform_with(l, make_even))
|
||||
{
|
||||
auto is_even = (v % 2) == 0;
|
||||
REQUIRE(is_even);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("transform_with with enumerate")
|
||||
{
|
||||
for (auto [e, v]: enumerate_value(transform_with(l, make_even)))
|
||||
{
|
||||
auto is_even = (v % 2) == 0;
|
||||
REQUIRE(is_even);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("transform_with reference")
|
||||
{
|
||||
auto make_even = [](auto &v) -> int & { v+=1; return v; };
|
||||
|
||||
for (auto v: transform_with(l, make_even))
|
||||
{
|
||||
auto is_even = (v % 2) == 0;
|
||||
REQUIRE(is_even);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("transform_with reference enumerate")
|
||||
{
|
||||
auto make_even = [](auto &v) -> int & { ++v; return v; };
|
||||
|
||||
for (auto [e, v]: enumerate(transform_with(l, make_even)))
|
||||
{
|
||||
auto is_even = (v % 2) == 0;
|
||||
REQUIRE(is_even);
|
||||
|
||||
v = e;
|
||||
}
|
||||
|
||||
for (auto [e, v]: enumerate_value(transform_with(l, make_even)))
|
||||
{
|
||||
REQUIRE(v == e+1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
96
tjp/core/iterators/_tests/zip.cpp
Executable file
96
tjp/core/iterators/_tests/zip.cpp
Executable file
@@ -0,0 +1,96 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/iterators/zip.hpp>
|
||||
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/containers/List.hpp>
|
||||
|
||||
#include "fail_on_copy_vector.hpp"
|
||||
|
||||
namespace tjp::core {
|
||||
namespace {
|
||||
|
||||
SCENARIO("core::iterators::zip")
|
||||
{
|
||||
constexpr size_t size = 42;
|
||||
GIVEN("two vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
fail_on_copy_vector<char> r;
|
||||
l.resize(size);
|
||||
r.resize(size);
|
||||
|
||||
for (auto [lv, rv]: zip(l, r))
|
||||
{
|
||||
lv = 1;
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto [lv, rv]: zip(l, r))
|
||||
sum += lv + rv;
|
||||
|
||||
auto expected = size * 2;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("three vector")
|
||||
{
|
||||
fail_on_copy_vector<int> l;
|
||||
fail_on_copy_vector<char> r;
|
||||
fail_on_copy_vector<char> u;
|
||||
l.resize(size);
|
||||
r.resize(size);
|
||||
u.resize(size);
|
||||
|
||||
for (auto [lv, rv, uv]: zip(l, r, u))
|
||||
{
|
||||
lv = 1;
|
||||
rv = 1;
|
||||
uv = 1;
|
||||
}
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto [lv, rv, uv]: zip(l, r, u))
|
||||
sum += lv + rv + uv;
|
||||
|
||||
auto expected = size * 3;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
GIVEN("two list")
|
||||
{
|
||||
List<int> l;
|
||||
List<char> r;
|
||||
l.resize(size);
|
||||
r.resize(size);
|
||||
|
||||
for (auto [lv, rv]: zip(l, r))
|
||||
{
|
||||
lv = 1;
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
WHEN("iterating to X")
|
||||
{
|
||||
size_t sum = 0;
|
||||
for (auto [lv, rv]: zip(l, r))
|
||||
sum += lv + rv;
|
||||
|
||||
auto expected = size * 2;
|
||||
REQUIRE(sum == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
88
tjp/core/iterators/enumerate.hpp
Executable file
88
tjp/core/iterators/enumerate.hpp
Executable file
@@ -0,0 +1,88 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template <typename T, typename I, typename R>
|
||||
struct enumerate_wrapper {
|
||||
T iterable;
|
||||
};
|
||||
|
||||
template <typename I, typename R>
|
||||
struct enumerate_iterator
|
||||
{
|
||||
size_t i;
|
||||
I iter;
|
||||
|
||||
bool operator != (const enumerate_iterator & other) const
|
||||
{
|
||||
return iter != other.iter;
|
||||
}
|
||||
|
||||
void operator ++ ()
|
||||
{
|
||||
++i;
|
||||
++iter;
|
||||
}
|
||||
auto operator * () const
|
||||
{
|
||||
return std::tuple<size_t, R>(i, *iter);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename I, typename R>
|
||||
auto begin (enumerate_wrapper<T, I, R> w)
|
||||
{
|
||||
return enumerate_iterator<I, R> { 0, begin(w.iterable) };
|
||||
}
|
||||
|
||||
template <typename T, typename I, typename R>
|
||||
auto end (enumerate_wrapper<T, I, R> w)
|
||||
{
|
||||
return enumerate_iterator<I, R> { 0, end(w.iterable) };
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename I = decltype(begin(std::declval<T>())),
|
||||
typename = decltype(end(std::declval<T>()))>
|
||||
constexpr auto enumerate_ref(T && iterable)
|
||||
{
|
||||
using V = decltype(*std::declval<I>());
|
||||
using R = V &;
|
||||
|
||||
return enumerate_wrapper<T, I, R> { std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename I = decltype(begin(std::declval<T>())),
|
||||
typename = decltype(end(std::declval<T>()))>
|
||||
constexpr auto enumerate_value(T && iterable)
|
||||
{
|
||||
using V = decltype(*std::declval<I>());
|
||||
|
||||
return enumerate_wrapper<T, I, V> { std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
|
||||
// TODO: the default c++ iteration is by value but here we have by ref, should it be by value?
|
||||
|
||||
template<typename T>
|
||||
constexpr auto enumerate(T && iterable)
|
||||
{
|
||||
return enumerate_ref(std::forward<T>(iterable));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::enumerate;
|
||||
using iterators::enumerate_ref;
|
||||
using iterators::enumerate_value;
|
||||
|
||||
} // namespace
|
||||
39
tjp/core/iterators/is_first.hpp
Executable file
39
tjp/core/iterators/is_first.hpp
Executable file
@@ -0,0 +1,39 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
struct is_first
|
||||
{
|
||||
bool v = true;
|
||||
|
||||
bool check ()
|
||||
{
|
||||
auto r = v;
|
||||
v = false;
|
||||
return r;
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return check();
|
||||
}
|
||||
|
||||
bool operator()()
|
||||
{
|
||||
return check();
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::is_first;
|
||||
|
||||
} // namespace
|
||||
|
||||
14
tjp/core/iterators/macro_min_max.h
Executable file
14
tjp/core/iterators/macro_min_max.h
Executable file
@@ -0,0 +1,14 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
#define macro_min(a,b) ((a<b)?a:b)
|
||||
#define macro_max(a,b) ((a>b)?a:b)
|
||||
|
||||
} // namespace utilities
|
||||
} // namespace
|
||||
42
tjp/core/iterators/no_first.hpp
Executable file
42
tjp/core/iterators/no_first.hpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template <typename T>
|
||||
struct no_first_wrapper
|
||||
{
|
||||
T iterable;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto begin (no_first_wrapper<T> w)
|
||||
{
|
||||
auto b = std::begin(w.iterable);
|
||||
auto e = std::end(w.iterable);
|
||||
return (b == e) ? e : std::next(b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto end (no_first_wrapper<T> w)
|
||||
{
|
||||
return end(w.iterable);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
no_first_wrapper<T> no_first (T&& iterable)
|
||||
{
|
||||
return { std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::no_first;
|
||||
|
||||
} // namespace
|
||||
|
||||
42
tjp/core/iterators/no_last.hpp
Executable file
42
tjp/core/iterators/no_last.hpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template <typename T>
|
||||
struct no_last_wrapper
|
||||
{
|
||||
T iterable;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto begin (no_last_wrapper<T> w)
|
||||
{
|
||||
return begin(w.iterable);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto end (no_last_wrapper<T> w)
|
||||
{
|
||||
auto b = std::begin(w.iterable);
|
||||
auto e = std::end(w.iterable);
|
||||
return (b == e) ? e : std::prev(e);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
no_last_wrapper<T> no_last (T&& iterable)
|
||||
{
|
||||
return { std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::no_last;
|
||||
|
||||
} // namespace
|
||||
85
tjp/core/iterators/range.hpp
Executable file
85
tjp/core/iterators/range.hpp
Executable file
@@ -0,0 +1,85 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include "macro_min_max.h"
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template<typename T=size_t>
|
||||
class range {
|
||||
public:
|
||||
class iterator {
|
||||
friend class range;
|
||||
public:
|
||||
T operator *() const { return i_; }
|
||||
|
||||
const iterator &operator ++() {
|
||||
int inc = inc_;
|
||||
|
||||
while(inc > 0) {
|
||||
++i_;
|
||||
--inc;
|
||||
}
|
||||
|
||||
while(inc < 0) {
|
||||
--i_;
|
||||
++inc;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator ++(int)
|
||||
{
|
||||
iterator copy(*this);
|
||||
++(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool operator ==(const iterator &other) const { return i_ == other.i_; }
|
||||
bool operator !=(const iterator &other) const { return i_ != other.i_; }
|
||||
|
||||
protected:
|
||||
iterator(T start, int inc) : i_ (start), inc_(inc) { }
|
||||
iterator(T start) : i_ (start), inc_(1) { }
|
||||
|
||||
private:
|
||||
int inc_;
|
||||
T i_;
|
||||
};
|
||||
|
||||
iterator begin() const { return begin_; }
|
||||
iterator end() const { return end_; }
|
||||
|
||||
range(T end) :
|
||||
begin_(macro_min(T(0), end)),
|
||||
end_(end)
|
||||
{}
|
||||
|
||||
range(T begin, T end) :
|
||||
begin_(macro_min(begin, end)),
|
||||
end_(end)
|
||||
{}
|
||||
|
||||
range(T begin, T end, int inc) :
|
||||
begin_(inc > 0 ? macro_min(begin,end) : macro_max(begin,end), inc),
|
||||
end_(end)
|
||||
{}
|
||||
|
||||
private:
|
||||
iterator begin_;
|
||||
iterator end_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::range;
|
||||
|
||||
} // namespace
|
||||
|
||||
70
tjp/core/iterators/range_with.hpp
Executable file
70
tjp/core/iterators/range_with.hpp
Executable file
@@ -0,0 +1,70 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template<typename T>
|
||||
struct range_over
|
||||
{
|
||||
T begin_;
|
||||
T end_;
|
||||
|
||||
T begin() { return begin_; }
|
||||
T end() { return end_; }
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
auto range_with(T begin, T end)
|
||||
{
|
||||
return range_over<T> { begin, end };
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto range_with(T &t)
|
||||
{
|
||||
return range_over { t.begin(), t.end() };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto range_with(const T &t)
|
||||
{
|
||||
return range_over { t.begin(), t.end() };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto range_with(T &t, size_t num)
|
||||
{
|
||||
return range_over<typename T::iterator> { t.begin(), t.begin() + num };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto range_with(const T &t, size_t num)
|
||||
{
|
||||
return range_over<typename T::const_iterator> { t.begin(), t.begin() + num };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto range_with(T &t, size_t from, size_t num)
|
||||
{
|
||||
return range_over<typename T::iterator> { t.begin() + from, t.begin() + from + num };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto range_with(const T &t, size_t from, size_t num)
|
||||
{
|
||||
return range_over<typename T::const_iterator> { t.begin() + from, t.begin() + from + num };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::range_with;
|
||||
|
||||
} // namespace
|
||||
|
||||
30
tjp/core/iterators/reverse.hpp
Executable file
30
tjp/core/iterators/reverse.hpp
Executable file
@@ -0,0 +1,30 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
|
||||
template <typename T>
|
||||
struct reversion_wrapper { T iterable; };
|
||||
|
||||
template <typename T>
|
||||
auto begin (reversion_wrapper<T> w) { return rbegin(w.iterable); }
|
||||
|
||||
template <typename T>
|
||||
auto end (reversion_wrapper<T> w) { return rend(w.iterable); }
|
||||
|
||||
template <typename T>
|
||||
reversion_wrapper<T> reverse (T&& iterable) { return { std::forward<T>(iterable) }; }
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::reverse;
|
||||
|
||||
} // namespace
|
||||
|
||||
89
tjp/core/iterators/safe_next.hpp
Executable file
89
tjp/core/iterators/safe_next.hpp
Executable file
@@ -0,0 +1,89 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
|
||||
template <typename T,
|
||||
typename TI = decltype(std::begin(std::declval<T>())),
|
||||
typename = decltype(std::end(std::declval<T>()))>
|
||||
constexpr auto safe_next(T && iterable)
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
TI iter;
|
||||
TI end;
|
||||
TI next;
|
||||
|
||||
iterator(TI iter_, TI end_) :
|
||||
iter(iter_),
|
||||
next(iter_),
|
||||
end(end_)
|
||||
{
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
bool operator != (const iterator & other) const { return iter != other.iter; }
|
||||
void operator ++ ()
|
||||
{
|
||||
iter = next;
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
const TI &operator * () const { return iter; }
|
||||
TI &operator * () { return iter; }
|
||||
};
|
||||
struct iterable_wrapper
|
||||
{
|
||||
T &iterable;
|
||||
auto begin() { return iterator(std::begin(iterable), std::end(iterable)); }
|
||||
auto end() { return iterator(std::end(iterable), std::end(iterable)); }
|
||||
};
|
||||
return iterable_wrapper{ std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename TI = decltype(std::begin(std::declval<T>())),
|
||||
typename = decltype(std::end(std::declval<T>()))>
|
||||
constexpr auto safe_next_value(T && iterable)
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
TI iter;
|
||||
TI end;
|
||||
TI next;
|
||||
|
||||
iterator(TI iter_, TI end_) :
|
||||
iter(iter_),
|
||||
next(iter_),
|
||||
end(end_)
|
||||
{
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
bool operator != (const iterator & other) const { return iter != other.iter; }
|
||||
void operator ++ ()
|
||||
{
|
||||
iter = next;
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
auto &operator * () const { return *iter; }
|
||||
auto &operator * () { return *iter; }
|
||||
};
|
||||
struct iterable_wrapper
|
||||
{
|
||||
T &iterable;
|
||||
auto begin() { return iterator(std::begin(iterable), std::end(iterable)); }
|
||||
auto end() { return iterator(std::end(iterable), std::end(iterable)); }
|
||||
};
|
||||
return iterable_wrapper{ std::forward<T>(iterable) };
|
||||
}
|
||||
|
||||
87
tjp/core/iterators/safe_next_with.hpp
Executable file
87
tjp/core/iterators/safe_next_with.hpp
Executable file
@@ -0,0 +1,87 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
|
||||
template <typename T,
|
||||
typename TI = decltype(std::begin(std::declval<T>())),
|
||||
typename = decltype(std::end(std::declval<T>()))>
|
||||
constexpr auto safe_next_with(T && iterable, TI iter)
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
TI iter;
|
||||
TI end;
|
||||
TI next;
|
||||
|
||||
iterator(TI iter_, TI end_) :
|
||||
iter(iter_),
|
||||
next(iter_),
|
||||
end(end_)
|
||||
{
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
bool operator != (const iterator & other) const { return iter != other.iter; }
|
||||
void operator ++ ()
|
||||
{
|
||||
iter = next;
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
const TI &operator * () const { return iter; }
|
||||
TI &operator * () { return iter; }
|
||||
|
||||
bool operator !=(const TI &rhs)
|
||||
{
|
||||
return iter != rhs;
|
||||
}
|
||||
};
|
||||
|
||||
return iterator{ iter, iterable.end() };
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename TI = decltype(std::begin(std::declval<T>())),
|
||||
typename = decltype(std::end(std::declval<T>()))>
|
||||
constexpr auto safe_next_with_value(T && iterable, TI iter)
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
TI iter;
|
||||
TI end;
|
||||
TI next;
|
||||
|
||||
iterator(TI iter_, TI end_) :
|
||||
iter(iter_),
|
||||
next(iter_),
|
||||
end(end_)
|
||||
{
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
bool operator != (const iterator & other) const { return iter != other.iter; }
|
||||
void operator ++ ()
|
||||
{
|
||||
iter = next;
|
||||
if (next != end)
|
||||
++next;
|
||||
}
|
||||
|
||||
auto &operator * () const { return *iter; }
|
||||
auto &operator * () { return *iter; }
|
||||
|
||||
bool operator !=(const TI &rhs)
|
||||
{
|
||||
return iter != rhs;
|
||||
}
|
||||
};
|
||||
|
||||
return iterator{ iter, iterable.end() };
|
||||
}
|
||||
67
tjp/core/iterators/transform_with.hpp
Executable file
67
tjp/core/iterators/transform_with.hpp
Executable file
@@ -0,0 +1,67 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace iterators {
|
||||
|
||||
template <typename T,
|
||||
typename F,
|
||||
typename I = decltype(begin(std::declval<T>()))
|
||||
>
|
||||
struct transform_with_iterator : I
|
||||
{
|
||||
typedef I Super;
|
||||
F f;
|
||||
using R = decltype(std::declval<F>()(*std::declval<I>()));
|
||||
|
||||
transform_with_iterator(Super i, F &f_) :
|
||||
Super(i),
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
R operator *() const
|
||||
{
|
||||
return f(Super::operator*());
|
||||
}
|
||||
} ;
|
||||
|
||||
template <typename T, typename F>
|
||||
struct transform_with_wrapper {
|
||||
T iterable;
|
||||
F f;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename F>
|
||||
auto begin (transform_with_wrapper<T, F> w)
|
||||
{
|
||||
return transform_with_iterator<T, F>(begin(w.iterable), w.f);
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
auto end (transform_with_wrapper<T, F> w)
|
||||
{
|
||||
return transform_with_iterator<T, F>(end(w.iterable), w.f);
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
transform_with_wrapper<T, F> transform_with (T&& iterable, F &&f)
|
||||
{
|
||||
return { std::forward<T>(iterable), std::forward<F>(f) };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using iterators::transform_with;
|
||||
using iterators::transform_with_wrapper;
|
||||
using iterators::transform_with_iterator;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
151
tjp/core/iterators/zip.hpp
Executable file
151
tjp/core/iterators/zip.hpp
Executable file
@@ -0,0 +1,151 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::iterators {
|
||||
namespace zip_detail {
|
||||
|
||||
template <typename Iter>
|
||||
using select_access_type_for = std::conditional_t<
|
||||
std::is_same_v<Iter, std::vector<bool>::iterator> ||
|
||||
std::is_same_v<Iter, std::vector<bool>::const_iterator>,
|
||||
typename Iter::value_type,
|
||||
typename Iter::reference
|
||||
>;
|
||||
|
||||
|
||||
template <typename ... Args, std::size_t ... Index>
|
||||
auto any_match_impl(std::tuple<Args...> const & lhs,
|
||||
std::tuple<Args...> const & rhs,
|
||||
std::index_sequence<Index...>) -> bool
|
||||
{
|
||||
auto result = false;
|
||||
result = (... | (std::get<Index>(lhs) == std::get<Index>(rhs)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename ... Args>
|
||||
auto any_match(std::tuple<Args...> const & lhs, std::tuple<Args...> const & rhs)
|
||||
-> bool
|
||||
{
|
||||
return any_match_impl(lhs, rhs, std::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename ... Iters>
|
||||
class zip_iterator
|
||||
{
|
||||
public:
|
||||
|
||||
using value_type = std::tuple<
|
||||
select_access_type_for<Iters>...
|
||||
>;
|
||||
|
||||
zip_iterator() = delete;
|
||||
|
||||
zip_iterator(Iters && ... iters)
|
||||
: m_iters {std::forward<Iters>(iters)...}
|
||||
{
|
||||
}
|
||||
|
||||
auto operator++() -> zip_iterator&
|
||||
{
|
||||
std::apply(
|
||||
[](auto && ... args) {
|
||||
(
|
||||
(++args),
|
||||
...
|
||||
);
|
||||
},
|
||||
m_iters
|
||||
);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator++(int) -> zip_iterator
|
||||
{
|
||||
auto tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
auto operator!=(zip_iterator const & other)
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
auto operator==(zip_iterator const & other)
|
||||
{
|
||||
return any_match(m_iters, other.m_iters);
|
||||
}
|
||||
|
||||
auto operator*() -> value_type
|
||||
{
|
||||
return std::apply([](auto && ... args){
|
||||
return value_type(*args...);
|
||||
}, m_iters);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<Iters...> m_iters;
|
||||
};
|
||||
|
||||
|
||||
/* std::decay needed because T is a reference, and is not a complete type */
|
||||
template <typename T>
|
||||
using select_iterator_for = std::conditional_t<
|
||||
std::is_const_v<std::remove_reference_t<T>>,
|
||||
typename std::decay_t<T>::const_iterator,
|
||||
typename std::decay_t<T>::iterator>;
|
||||
|
||||
|
||||
|
||||
template <typename ... T>
|
||||
class zipper
|
||||
{
|
||||
public:
|
||||
using zip_type = zip_iterator<select_iterator_for<T> ...>;
|
||||
|
||||
template <typename ... Args>
|
||||
zipper(Args && ... args)
|
||||
: m_args{std::forward<Args>(args)...}
|
||||
{
|
||||
}
|
||||
|
||||
auto begin() -> zip_type
|
||||
{
|
||||
return std::apply([](auto && ... args){
|
||||
return zip_type(std::begin(args)...);
|
||||
}, m_args);
|
||||
}
|
||||
auto end() -> zip_type
|
||||
{
|
||||
return std::apply([](auto && ... args){
|
||||
return zip_type(std::end(args)...);
|
||||
}, m_args);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<T ...> m_args;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename ... T>
|
||||
auto zip(T && ... t)
|
||||
{
|
||||
return zipper<T ...>{std::forward<T>(t)...};
|
||||
}
|
||||
|
||||
} // namespace zip_detail
|
||||
} // namespace
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
using iterators::zip_detail::zip;
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user