flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:43:06 -05:00
commit 996151a56a
521 changed files with 46722 additions and 0 deletions

29
tjp/core/Precompile.pch Normal file
View File

@@ -0,0 +1,29 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#define USE_PRECOMPILED_HEADERS
#ifdef USE_PRECOMPILED_HEADERS
#include <iostream>
#include <sstream>
#include <string>
#include <string_view>
#include <list>
#include <map>
#include <vector>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <thread>
#include <algorithm>
#include <memory>
#include <functional>
#endif

View File

@@ -0,0 +1,12 @@
// 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 {
struct ExecuteOnDestruct;
using OnDestruct = ExecuteOnDestruct;
} // namespace

View File

@@ -0,0 +1,73 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "ExecuteOnDestruct.h"
#include <functional>
#include "../threads/TestMutex.hpp"
#include "no_throw.hpp"
#include <utility>
namespace tjp::core {
struct ExecuteOnDestruct
{
typedef std::function<void()> F;
[[no_unique_address]]
TestMutex m;
F f;
struct Throws_{};
static constexpr Throws_ Throws = Throws_{};
ExecuteOnDestruct(const ExecuteOnDestruct &) = delete;
ExecuteOnDestruct() {}
ExecuteOnDestruct(ExecuteOnDestruct &&rhs):
f(rhs.move())
{}
template<typename FU>
ExecuteOnDestruct(FU &&f_) : f(no_throw(std::forward<FU>(f_)))
{}
// note: throwing on destruction, *can* cause termination, weird but true as of 2026
template<typename FU>
ExecuteOnDestruct(FU &&f_, Throws_) : f(std::forward<FU>(f_))
{}
F move()
{
auto l = lock_of(m);
F f_;
std::swap(f_, f);
return f_;
}
~ExecuteOnDestruct() noexcept(false)
{
execute();
}
void execute()
{
auto f = move();
if (f)
f();
}
void clear ()
{
move();
}
} ;
} // namespace

View 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/algorithm/all_are.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::all_are")
{
GIVEN("a vector of values")
{
Vector<int> v;
for (auto i=0; i<50; ++i)
v.push_back(42);
auto all_are_42 = all_are(v, [](auto &v) { return v == 42; });
REQUIRE(all_are_42);
WHEN("one is not 42")
{
v[5] = 43;
auto all_are_42 = all_are(v, [](auto &v) { return v == 42; });
REQUIRE(!all_are_42);
}
WHEN("multiple are not 42")
{
v[2] = 40;
v[13] = 39;
auto all_are_42 = all_are(v, [](auto &v) { return v == 42; });
REQUIRE(!all_are_42);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_erase_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_erase_if")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = container_erase_if(
v, [](auto &v) { return v == 10; }
);
REQUIRE(erased == 4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = container_erase_if(
v, [](auto &v) { return v == 10; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = container_erase_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,53 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_erase_if_one.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_erase_if_one")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is erased")
{
auto erased = container_erase_if_one(
v, [](auto &v) { return v == 42; }
);
REQUIRE(erased);
REQUIRE(v.size() == 99);
WHEN("42 is erased again")
{
auto erased = container_erase_if_one(
v, [](auto &v) { return v == 42; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 99);
}
}
WHEN("1000 is not erased")
{
auto erased = container_erase_if_one(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,47 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_erase_value_all.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_erase_value_all")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = container_erase_value_all(v, 10);
REQUIRE(erased==4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = container_erase_value_all(v, 10);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = container_erase_value_all(v, 1000);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,47 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_erase_value_one.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_erase_value_one")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = container_erase_value_one(v, 10);
REQUIRE(erased);
REQUIRE(v.size() == 99);
WHEN("10 is erased again")
{
auto erased = container_erase_value_one(v, 10);
REQUIRE(erased);
REQUIRE(v.size() == 98);
}
}
WHEN("1000 is not erased")
{
auto erased = container_erase_value_one(v, 1000);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,40 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_find_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_find_if")
{
GIVEN("a vector of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is found")
{
auto found = container_find_if(v, [](auto &v) { return v == 10; });
REQUIRE(found != v.end());
}
WHEN("1000 is not found")
{
auto found = container_find_if(v, [](auto &v) { return v == 1000; });
REQUIRE(found == v.end());
}
}
}
} // namespace
} // namespace

View 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/algorithm/container_get_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_get_if")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = container_get_if(
v, [](auto &v) { return v == 42; }
);
REQUIRE(found);
REQUIRE(*found == 42);
WHEN("1000 is not found")
{
auto found = container_get_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!found);
}
}
WHEN("1000 is not found")
{
auto found = container_get_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!found);
REQUIRE(v.size() == 100);
}
#ifdef CHECK_COMPILATION_FAILURE
WHEN("called with a temporary list")
{
int destructed = 0;
auto make_values = [&]() {
struct S {
int *destructed;
int value;
S(int *destructed_, int value_) :
destructed(destructed_),
value(value_)
{}
~S() { (*destructed)++; }
};
List<S> temp;
temp.emplace_back(&destructed, 5);
temp.emplace_back(&destructed, 42);
return temp;
};
auto found = container_get_if(
make_values(), [&](auto &s) {
REQUIRE(destructed == 0);
return s.value == 42;
}
);
REQUIRE(destructed == 0);
}
#endif
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,45 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_get_if_optional.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_get_if_optional")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = container_get_if_optional(
v, [](auto &v) { return v == 42; }
);
REQUIRE(found);
REQUIRE(*found == 42);
}
WHEN("1000 is not found")
{
auto found = container_get_if_optional(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!found);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_get_if_optional_erase.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_get_if_optional_erase")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is erased")
{
auto erased = container_get_if_optional_erase(
v, [](auto &v) { return v == 42; }
);
REQUIRE(erased);
REQUIRE(*erased == 42);
REQUIRE(v.size() == 99);
WHEN("42 is erased again")
{
auto erased = container_get_if_optional_erase(
v, [](auto &v) { return v == 42; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 99);
}
}
WHEN("1000 is not erased")
{
auto erased = container_get_if_optional_erase(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,48 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_get_optional_erase.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_get_optional_erase")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is erased")
{
auto erased = container_get_optional_erase(v, 42);
REQUIRE(erased);
REQUIRE(*erased == 42);
REQUIRE(v.size() == 99);
WHEN("42 is erased again")
{
auto erased = container_get_optional_erase(v, 42);
REQUIRE(!erased);
REQUIRE(v.size() == 99);
}
}
WHEN("1000 is not found")
{
auto found = container_get_optional_erase(v, 1000);
REQUIRE(!found);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,44 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_has.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_has")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = container_has(v, 42);
REQUIRE(found);
WHEN("1000 is not found")
{
auto found = container_has(v, 1000);
REQUIRE(!found);
}
}
WHEN("1000 is not found")
{
auto found = container_has(v, 1000);
REQUIRE(!found);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,50 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/container_has_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::container_has_if")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i);
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = container_has_if(
v, [](auto &v) { return v == 42; }
);
REQUIRE(found);
WHEN("1000 is not found")
{
auto found = container_has_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!found);
}
}
WHEN("1000 is not found")
{
auto found = container_has_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!found);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,38 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/copy_clear.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::copy_clear")
{
WHEN("simple value")
{
int i = 42;
auto v = copy_clear(i);
REQUIRE(i == 0);
REQUIRE(v == 42);
}
WHEN("complex value")
{
String i = "hello";
auto v = copy_clear(i);
REQUIRE(i == "");
REQUIRE(v == "hello");
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,38 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/copy_of.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::copy_of")
{
WHEN("simple value")
{
int i = 42;
auto v = copy_of(i);
REQUIRE(i == 42);
REQUIRE(v == 42);
}
WHEN("complex value")
{
String i = "hello";
auto v = copy_of(i);
REQUIRE(i == "hello");
REQUIRE(v == "hello");
}
}
} // namespace
} // namespace

View 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/algorithm/emplace.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::emplace")
{
WHEN("Vector value")
{
Vector<int> v;
WHEN("initializer list")
{
Vector<int> expected = { 1, 2, 3, 4, 5};
emplace(v, { 1, 2, 3, 4, 5});
REQUIRE(v == expected);
}
WHEN("init")
{
Vector<int> expected = { 1, 1 };
emplace(v, 2, 1);
REQUIRE(v == expected);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,38 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/empty_of.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::empty_of")
{
WHEN("simple value")
{
using T = Vector<int>;
auto &v = empty_of<T>();
REQUIRE(v.empty());
}
WHEN("complex value")
{
struct X { int y = 42; };
using T = X;
auto &v = empty_of<T>();
REQUIRE(v.y == 42);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,33 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/ends_with.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::ends_with")
{
WHEN("Vector value")
{
Vector<int> v = { 1, 2, 3, 4, 5 };
auto ends_with_345 = ends_with(v, Vector<int> {3, 4, 5});
REQUIRE(ends_with_345);
auto ends_with_456 = ends_with(v, Vector<int> {4,5,6});
REQUIRE(!ends_with_456);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,33 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/has_last.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::has_last")
{
WHEN("Vector value")
{
Vector<int> v = { 1, 2, 3, 4, 5 };
auto ends_with_5 = has_last(v, [](auto &v) { return v == 5; });
REQUIRE(ends_with_5);
auto ends_with_6 = has_last(v, [](auto &v) { return v == 6; });
REQUIRE(!ends_with_6);
}
}
} // namespace
} // namespace

View 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/algorithm/in_range_segment.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::in_range_segment")
{
WHEN("ranges")
{
static_assert(in_range_segment(1, 0, 10));
static_assert(!in_range_segment(0, 1, 10));
static_assert(!in_range_segment(11, 1, 10));
static_assert(in_range_segment(10, 1, 10));
}
}
} // namespace
} // namespace

View 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
#include <tjp/core/algorithm/is_in.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::is_in")
{
WHEN("ranges")
{
static_assert(is_in(0, 0, 1, 2, 3));
static_assert(is_in(1, 0, 1, 2, 3));
static_assert(!is_in(4, 0, 1, 2, 3));
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,34 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/is_zero.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::is_zero")
{
WHEN("ranges")
{
auto minus_one = [](auto &&v) { return v - 1; };
auto test_minus_one = is_zero(minus_one);
REQUIRE(test_minus_one(1));
REQUIRE(!test_minus_one(0));
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,29 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/last_of_parameter_pack.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::last_of_parameter_pack")
{
WHEN("ranges")
{
static_assert(last_of_parameter_pack(1,2,3,4) == 4);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/list_erase_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::list_erase_if")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = list_erase_if(
v, [](auto &v) { return v == 10; }
);
REQUIRE(erased == 4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = list_erase_if(
v, [](auto &v) { return v == 10; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = list_erase_if(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/list_erase_if_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::list_erase_if_value")
{
GIVEN("a list of values")
{
List<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = list_erase_if_value(
v, [](auto &v) { return v == 10; }
);
REQUIRE(erased == 4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = list_erase_if_value(
v, [](auto &v) { return v == 10; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = list_erase_if_value(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_erase.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_erase")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = map_erase(
v, 10
);
REQUIRE(erased);
REQUIRE(v.size() == 99);
WHEN("evens are erased again")
{
auto erased = map_erase(
v, 10
);
REQUIRE(!erased);
REQUIRE(v.size() == 99);
}
}
WHEN("1000 is not erased")
{
auto erased = map_erase(
v, 1000
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_erase_if.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_erase_if")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("evens are erased")
{
auto erased = map_erase_if(
v, [](auto &v) { return v.first % 2 == 0; }
);
REQUIRE(erased == 50);
REQUIRE(v.size() == 50);
WHEN("evens are erased again")
{
auto erased = map_erase_if(
v, [](auto &v) { return v.first % 2 == 0; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 50);
}
}
WHEN("1000 is not erased")
{
auto erased = map_erase_if(
v, [](auto &v) { return v.first == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_erase_if_key.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_erase_if_key")
{
GIVEN("a list of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("evens are erased")
{
auto erased = map_erase_if_key(
v, [](auto &v) { return v % 2 == 0; }
);
REQUIRE(erased == 50);
REQUIRE(v.size() == 50);
WHEN("evens are erased again")
{
auto erased = map_erase_if_key(
v, [](auto &v) { return v % 2 == 0; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 50);
}
}
WHEN("1000 is not erased")
{
auto erased = map_erase_if_key(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_erase_if_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_erase_if_value")
{
GIVEN("a list of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("evens are erased")
{
auto erased = map_erase_if_value(
v, [](auto &v) { return v % 2 == 0; }
);
REQUIRE(erased == 50);
REQUIRE(v.size() == 50);
WHEN("evens are erased again")
{
auto erased = map_erase_if_value(
v, [](auto &v) { return v % 2 == 0; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 50);
}
}
WHEN("1000 is not erased")
{
auto erased = map_erase_if_value(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,33 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_for_each_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_for_each_value")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = 1;
auto x = 0;
map_for_each_value(
v,
[&](auto &v) { x += v; }
);
REQUIRE(x == 100);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,44 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_has.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_has")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = map_has(v, 42);
REQUIRE(found);
WHEN("1000 is not found")
{
auto found = map_has(v, 1000);
REQUIRE(!found);
}
}
WHEN("1000 is not found")
{
auto found = map_has(v, 1000);
REQUIRE(!found);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,44 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_has_key.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_has_key")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
auto found = map_has_key(v, 42);
REQUIRE(found);
WHEN("1000 is not found")
{
auto found = map_has_key(v, 1000);
REQUIRE(!found);
}
}
WHEN("1000 is not found")
{
auto found = map_has_key(v, 1000);
REQUIRE(!found);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,34 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_iterator_or_insert.hpp>
#include <tjp/core/algorithm/map_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_iterator_or_insert")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
map_iterator_insert(v, 0)->second = 42;
map_iterator_insert(v, 1000)->second = 42;
REQUIRE(*map_value(v, 0) == 42);
REQUIRE(*map_value(v, 1000) == 42);
REQUIRE(*map_value(v, 1) == 1);
REQUIRE(map_value(v, 1001) == nullptr);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,37 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_value")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
REQUIRE(map_value(v, 42) != nullptr);
REQUIRE(*map_value(v, 42) == 42);
}
WHEN("1000 is not found")
{
REQUIRE(map_value(v, 1000) == nullptr);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,37 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/map_value_require.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Map.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::map_value_require")
{
GIVEN("a map of values")
{
Map<int, int> v;
for (auto i=0; i<100; ++i)
v[i] = i;
REQUIRE(v.size() == 100);
WHEN("42 is found")
{
REQUIRE_NOTHROW(map_value_require(v, 42));
REQUIRE(map_value_require(v, 42) == 42);
}
WHEN("1000 is not found")
{
REQUIRE_THROWS(map_value_require(v, 1000));
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,34 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/no_throw.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::no_throw")
{
GIVEN("throws")
{
auto throws = []() {
throw std::runtime_error("exception");
};
auto nthrows = no_throw(throws);
REQUIRE_NOTHROW(nthrows());
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,34 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/not_zero.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::not_zero")
{
WHEN("ranges")
{
auto minus_one = [](auto &&v) { return v - 1; };
auto test_minus_one = not_zero(minus_one);
REQUIRE(test_minus_one(2));
REQUIRE(!test_minus_one(1));
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,77 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/on_destruct.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::on_destruct")
{
GIVEN("a throw during destruct")
{
auto f = []() {
auto throws = []() {
throw std::runtime_error("exception");
};
ExecuteOnDestruct x(throws, ExecuteOnDestruct::Throws);
};
REQUIRE_THROWS(f());
}
GIVEN("no throw during destruct")
{
auto f = []() {
auto throws = []() {
throw std::runtime_error("exception");
};
ExecuteOnDestruct x(throws);
};
REQUIRE_NOTHROW(f());
}
GIVEN("a sequence of destructions")
{
Vector<int> destructs;
{
auto one = on_destruct([&](){destructs.push_back(1);});
auto two = on_destruct([&](){destructs.push_back(2);});
auto three = on_destruct([&](){destructs.push_back(3);});
auto four = on_destruct([&](){destructs.push_back(4);});
}
Vector<int> expected = { 4, 3, 2, 1 };
REQUIRE(destructs == expected);
}
GIVEN("a destruct on destructs once")
{
int i = 0;
REQUIRE(i==0);
{
auto destruct = on_destruct([&](){i++;});
destruct.execute();
REQUIRE(i==1);
destruct.execute();
REQUIRE(i==1);
}
REQUIRE(i==1);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,38 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/one_is.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::one_is")
{
GIVEN("a vector of values")
{
Vector<int> v;
for (auto i=0; i<50; ++i)
v.push_back(41);
WHEN("none are 42")
{
auto one_is_42 = one_is(v, [](auto &v) { return v == 42; });
REQUIRE(!one_is_42);
}
WHEN("one is 42")
{
v[13] = 42;
auto one_is_42 = one_is(v, [](auto &v) { return v == 42; });
REQUIRE(one_is_42);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,28 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/optional_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Optional.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::optional_value")
{
GIVEN("optional value")
{
Optional<int> five = 5;
REQUIRE(optional_value(five) != nullptr);
REQUIRE(*optional_value(five) == 5);
Optional<int> empty;
REQUIRE(optional_value(empty) == nullptr);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,27 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/optional_value_or_default.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Optional.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::optional_value_or_default")
{
GIVEN("optional value")
{
Optional<int> five = 5;
REQUIRE(optional_value_or_default(five, 42) == 5);
Optional<int> empty;
REQUIRE(optional_value_or_default(empty, 42) == 42);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,27 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/set_empty.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Set.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::set_empty")
{
GIVEN("optional value")
{
Set<int> not_empty = { 1, 2, 3 };
Set<int> empty = {};
REQUIRE(set_empty(empty));
REQUIRE(!set_empty(not_empty));
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,192 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/small_cmp.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/timer/Timer.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::small_cmp")
{
WHEN("cmp_small_a_lot")
{
Vector<Vector<size_t>> profiles;
profiles.push_back({ 1, 4, 3, 7, 9, 14, 16, 8, 23, 4, 2, 3 });
profiles.push_back({ 4, 4, 4, 4, 2, 2, 4, 4, 4, 8, 8, 8 });
profiles.push_back({ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 });
profiles.push_back({ 16, 16, 8, 8, 8, 3, 2, 1, 1, 1, 4, 8 });
profiles.push_back({ 4, 4, 8, 4, 8, 8, 4, 4, 2, 2, 2, 2 });
constexpr auto max = 2048;
char d_[max + 128];
char s_[max + 128];
auto sum = 0;
for (auto i=0; i<max+128; ++i)
{
d_[i] = 'a' + std::rand() % 3;
s_[i] = 'a' + std::rand() % 3;
}
auto numCycles = 32768;
for (auto &chunks : profiles)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Timer timer(false);
auto *reads = chunks.data();
auto numReads = chunks.size();
// ------
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
auto r0 = mem_cmp(d, readSize, s, readSize);
auto r1 = small_cmp(d, readSize, s, readSize);
auto r0v = r0 < 0 ? -1 : (r0 > 0 ? 1 : 0);
auto r1v = r1 < 0 ? -1 : (r1 > 0 ? 1 : 0);
if (r0v != r1v)
{
auto rx = small_cmp(d, readSize, s, readSize);
unused(rx);
REQUIRE(false);
}
d += readSize;
s += readSize;
size += readSize;
}
}
// -------
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
sum += small_cmp_v1(d, readSize, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV1Elapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
sum += small_cmp_v1a(d, readSize, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV1AElapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
sum += small_cmp_v2(d, readSize, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV2Elapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
sum += small_cmp_v3(d, readSize, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV3Elapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
sum += mem_cmp(d, readSize, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto memcpyElapsed = timer.stop();
std::cout << "small_cmp_v1 " << std::setprecision(16) << readSmallV1Elapsed << std::endl;
std::cout << "small_cmp_v1a " << std::setprecision(16) << readSmallV1AElapsed << std::endl;
std::cout << "small_cmp_v2 " << std::setprecision(16) << readSmallV2Elapsed << std::endl;
std::cout << "small_cmp_v3 " << std::setprecision(16) << readSmallV3Elapsed << std::endl;
std::cout << "memcmp " << memcpyElapsed << std::endl;
std::cout << "sum " << sum << std::endl;
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,127 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/small_copy.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/timer/Timer.hpp>
#include "../../log/LogOf.h"
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::small_copy")
{
WHEN("read_small_a_lot")
{
Vector<Vector<size_t>> profiles;
profiles.push_back({ 1, 4, 3, 7, 9, 14, 16, 8, 23, 4, 2, 3 });
profiles.push_back({ 4, 4, 4, 4, 2, 2, 4, 4, 4, 8, 8, 8 });
profiles.push_back({ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 });
profiles.push_back({ 16, 16, 8, 8, 8, 3, 2, 1, 1, 1, 4, 8 });
profiles.push_back({ 4, 4, 8, 4, 8, 8, 4, 4, 2, 2, 2, 2 });
constexpr auto max = 2048;
char d_[max + 128];
char s_[max + 128];
auto numCycles = 32768;
for (auto &chunks : profiles)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Timer timer(false);
auto *reads = chunks.data();
auto numReads = chunks.size();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
small_copy_v3(d, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV3Elapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
small_copy_v4a(d, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV4aElapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
small_copy_v4b(d, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto readSmallV4bElapsed = timer.stop();
timer.start();
for (auto i=0; i<numCycles; ++i)
{
char *d = d_;
char *s = s_;
auto size = 0;
while (size < max)
{
auto readSize = reads[i % numReads];
memcpy(d, s, readSize);
d += readSize;
s += readSize;
size += readSize;
}
}
auto memcpyElapsed = timer.stop();
std::cout << logVar(chunks) << std::endl;
std::cout << "small_copy_v3 " << readSmallV3Elapsed << std::endl;
std::cout << "small_copy_v4a " << readSmallV4aElapsed << std::endl;
std::cout << "small_copy_v4b " << readSmallV4bElapsed << std::endl;
std::cout << "memcpy " << memcpyElapsed << std::endl;
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,33 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/starts_with.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/unused.hpp>
#include <iomanip>
#include <iostream>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::starts_with")
{
WHEN("Vector value")
{
Vector<int> v = { 1, 2, 3, 4, 5 };
auto starts_with_123 = starts_with(v, Vector<int> {1,2,3});
REQUIRE(starts_with_123);
auto starts_with_456 = starts_with(v, Vector<int> {4,5,6});
REQUIRE(!starts_with_456);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,41 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/vector_append.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::vector_append")
{
GIVEN("vector")
{
WHEN("using an empty vector")
{
Vector<int> empty = {};
Vector<int> append = { 4, 5, 6 };
vector_append(empty, append);
auto expected = append;
REQUIRE(empty == expected);
}
WHEN("using a non empty vector")
{
Vector<int> not_empty = { 1, 2, 3 };
Vector<int> append = { 4, 5, 6 };
vector_append(not_empty, append);
Vector<int> expected = { 1, 2, 3, 4, 5, 6 };
REQUIRE(not_empty == expected);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::vector_erase_if_value")
{
GIVEN("a list of values")
{
Vector<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = vector_erase_if_value(
v, [](auto &v) { return v == 10; }
);
REQUIRE(erased == 4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = vector_erase_if_value(
v, [](auto &v) { return v == 10; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = vector_erase_if_value(
v, [](auto &v) { return v == 1000; }
);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,47 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/vector_erase_value_all.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::vector_erase_value_all")
{
GIVEN("a list of values")
{
Vector<int> v;
for (auto i=0; i<100; ++i)
v.push_back(i / 4);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = vector_erase_value_all(v, 10);
REQUIRE(erased==4);
REQUIRE(v.size() == 96);
WHEN("10 is erased again")
{
auto erased = vector_erase_value_all(v, 10);
REQUIRE(!erased);
REQUIRE(v.size() == 96);
}
}
WHEN("1000 is not erased")
{
auto erased = vector_erase_value_all(v, 1000);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,52 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/algorithm/vector_erase_value_one.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/Vector.h>
#include <tjp/core/algorithm/unused.hpp>
namespace tjp::core::algorithm {
namespace {
SCENARIO("core::algorithm::vector_erase_value_one")
{
GIVEN("a list of values")
{
Vector<int> v;
for (auto i=0; i<98; ++i)
v.push_back(i / 4);
v.push_back(9999);
v.push_back(999);
REQUIRE(v.size() == 100);
WHEN("10 is erased")
{
auto erased = vector_erase_value_one(v, 10);
REQUIRE(erased);
REQUIRE(v.size() == 99);
REQUIRE(v[10 * 4] == 999);
WHEN("10 is erased again")
{
auto erased = vector_erase_value_one(v, 10);
REQUIRE(erased);
REQUIRE(v.size() == 98);
REQUIRE(v[10 * 4 + 1] == 9999);
}
}
WHEN("1000 is not erased")
{
auto erased = vector_erase_value_one(v, 1000);
REQUIRE(!erased);
REQUIRE(v.size() == 100);
}
}
}
} // namespace
} // namespace

19
tjp/core/algorithm/all_are.hpp Executable file
View File

@@ -0,0 +1,19 @@
// 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 {
template<typename T, typename F>
bool all_are(const T &l, F &&f)
{
for (auto &v: l)
if (!f(v))
return false;
return true;
}
} // namespace

18
tjp/core/algorithm/cmp.hpp Executable file
View File

@@ -0,0 +1,18 @@
// 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 {
template<typename T>
int cmp(const T &l, const T &r)
{
if (l == r)
return 0;
return l < r ? -1 : 1;
}
} // namespace

View File

@@ -0,0 +1,22 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
size_t container_count_if (const T &c, F &&f)
{
size_t count = 0;
for (auto &v: c)
if (f(v))
count++;
return count;
}
} // namespace

View File

@@ -0,0 +1,27 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../iterators/safe_next.hpp"
namespace tjp::core {
template<typename T, typename F>
auto container_erase_if (T &c, F &&f)
{
size_t erased = 0;
for (auto i: safe_next(c))
{
if (f(*i))
{
c.erase(i);
++erased;
}
}
return erased;
}
} // namespace

View 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
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
auto container_erase_if_imp_use_iterator(T &v, F &&f)
{
size_t erased = 0;
auto i = v.begin();
while (i != v.end())
{
if (f(*i))
{
i = v.erase(i);
++erased;
}
else
++i;
}
return erased;
}
} // namespace

View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
auto container_erase_if_one (T &c, F &&f)
{
auto i = std::find_if(c.begin(), c.end(), std::forward<F>(f));
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
} // namespace

View 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
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename U>
auto container_erase_value_all (T &v, U &&u)
{
size_t erased = 0;
auto i = v.begin();
while (i != v.end())
{
if ((*i) == std::forward<U>(u))
{
i = v.erase(i);
++erased;
}
else
++i;
}
return erased;
}
} // namespace

View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename U>
auto container_erase_value_one (T &c, U &&u)
{
auto i = std::find(c.begin(), c.end(), std::forward<U>(u));
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
} // namespace

View File

@@ -0,0 +1,18 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
auto container_find_if (T &c, F &&f)
{
return std::find_if(c.begin(), c.end(), std::forward<F>(f));
}
} // namespace

View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
auto container_get_if (T &&c, F &&u)
{
static_assert(std::is_lvalue_reference_v<T&&>, "requires an lvalue");
auto i = std::find_if(c.begin(), c.end(), std::forward<F>(u));
if (i != c.end())
{
return &*i;
}
typedef decltype(&*i) R;
return (R)nullptr;
}
} // namespace

View File

@@ -0,0 +1,25 @@
// 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 <optional>
namespace tjp::core {
template<typename T, typename F>
auto container_get_if_optional (const T &c, F &&u)
{
auto i = std::find_if(c.begin(), c.end(), std::forward<F>(u));
if (i != c.end())
{
return std::make_optional(*i);
}
return std::optional<typename T::value_type>();
}
} // namespace

View File

@@ -0,0 +1,27 @@
// 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 <optional>
namespace tjp::core {
template<typename T, typename F>
auto container_get_if_optional_erase (T &c, F &&u)
{
auto i = std::find_if(c.begin(), c.end(), std::forward<F>(u));
if (i != c.end())
{
auto result = std::make_optional(std::move(*i));
c.erase(i);
return result;
}
return std::optional<typename T::value_type>();
}
} // namespace

View File

@@ -0,0 +1,27 @@
// 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 <optional>
namespace tjp::core {
template<typename T, typename U>
auto container_get_optional_erase (T &c, U &&u)
{
auto i = std::find(c.begin(), c.end(), std::forward<U>(u));
if (i != c.end())
{
auto result = std::make_optional(*i);
c.erase(i);
return result;
}
return std::optional<typename T::value_type>();
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename U>
bool container_has (const T &c, const U &v)
{
return std::find(c.begin(), c.end(), v) != c.end();
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename F>
bool container_has_if (const T &c, F &&f)
{
return std::find_if(c.begin(), c.end(), std::forward<F>(f)) != c.end();
}
} // namespace

View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <utility>
namespace tjp::core {
template<typename T, typename std::enable_if<(std::is_fundamental<T>::value || std::is_pointer<T>::value), T>::type* = nullptr>
T copy_clear(T &t)
{
T t_{0};
std::swap(t, t_);
return t_;
}
template<typename T, typename std::enable_if<!(std::is_fundamental<T>::value || std::is_pointer<T>::value), T>::type* = nullptr>
T copy_clear(T &t, T &&t_=T())
{
std::swap(t, t_);
return t_;
}
} // namespace

View File

@@ -0,0 +1,20 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <utility>
#include <memory>
namespace tjp::core {
template<typename T>
auto copy_clear_delete(T *&t)
{
T *t_{0};
std::swap(t, t_);
return unique_ptr<T>(t_);
}
} // namespace

15
tjp/core/algorithm/copy_of.hpp Executable file
View File

@@ -0,0 +1,15 @@
// 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 {
template<typename T>
T copy_of(const T &t)
{
return t;
}
} // namespace

23
tjp/core/algorithm/emplace.hpp Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename ... Args>
void emplace(T &t, Args && ...args)
{
t = T(std::forward<Args>(args)...);
}
template<typename T>
auto emplace(T &t, T &&rhs)
{
t = std::move(rhs);
}
} // namespace

16
tjp/core/algorithm/empty_of.hpp Executable file
View File

@@ -0,0 +1,16 @@
// 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 {
template<typename M>
const M &empty_of()
{
static M m;
return m;
}
} // namespace

View File

@@ -0,0 +1,40 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../string/StringView.hpp"
namespace tjp::core {
template<typename T, typename U>
bool ends_with (const T &c1, const U &c2)
{
if (c2.size() > c1.size())
return false;
auto offset = c1.size() - c2.size();
auto c1i = c1.begin() + offset;
auto c2i = c2.begin();
while (c2i != c2.end())
{
if (*c1i != *c2i)
return false;
++c1i;
++c2i;
}
return true;
}
template<typename T>
bool ends_with (const T &c1, const char *c2)
{
return ends_with(c1, StringView(c2));
}
} // namespace

15
tjp/core/algorithm/has_last.hpp Executable file
View File

@@ -0,0 +1,15 @@
// 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 {
template<typename T, typename F>
bool has_last(T &t, F &&f)
{
return !t.empty() && f(t.back());
}
} // namespace

View File

@@ -0,0 +1,38 @@
// 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 {
template<typename T, typename U>
bool has_sequence (const T &c1, const U &c2)
{
if (c2.size() > c1.size())
return false;
auto end = c1.size() - c2.size();
for (auto offset = 0; offset <= end; ++offset)
{
auto c1i = c1.begin() + offset;
auto c2i = c2.begin();
while (c2i != c2.end())
{
if (*c1i != *c2i)
break;
++c1i;
++c2i;
}
if (c2i == c2.end())
return true;
}
return false;
}
} // namespace

View File

@@ -0,0 +1,16 @@
// 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 {
template<typename V, typename L, typename R>
constexpr
bool in_range_segment(const V &v, const L &offset, const R &size)
{
return (v >= offset) && (v < (offset + size));
}
} // namespace

17
tjp/core/algorithm/is_in.hpp Executable file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
// https://stackoverflow.com/questions/15181579/c-most-efficient-way-to-compare-a-variable-to-multiple-values
#pragma once
namespace tjp::core {
template<typename First, typename ... T>
constexpr bool is_in(First &&first, const T & ... t)
{
return ((first == t) || ...);
}
} // namespace

14
tjp/core/algorithm/is_zero.hpp Executable file
View 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::core {
template<typename F>
constexpr auto is_zero(F &&f) {
return [f](auto &&v) { return f(v) == 0; };
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename... Args>
constexpr
decltype(auto) last_of_parameter_pack(Args&&... args){
return (std::forward<Args>(args), ...);
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "container_erase_if_imp_use_iterator.hpp"
namespace tjp::core {
template<typename T, typename F>
auto list_erase_if(T &v, F &&f)
{
return container_erase_if_imp_use_iterator(v, std::forward<F>(f));
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "list_erase_if.hpp"
namespace tjp::core {
template<typename T, typename F>
auto list_erase_if_value(T &v, F &&f)
{
return list_erase_if(v, std::forward<F>(f));
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "container_erase_value_all.hpp"
namespace tjp::core {
template<typename M, typename K>
bool list_erase_value_all(M &m, K &&k)
{
return container_erase_value_all(m, std::forward<K>(k));
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "container_erase_value_one.hpp"
namespace tjp::core {
template<typename M, typename K>
bool list_erase_value_one(M &m, K &&k)
{
return container_erase_value_one(m, std::forward<K>(k));
}
} // namespace

View File

@@ -0,0 +1,24 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename T, typename K>
auto map_erase(T &map, K &&k)
{
auto i = map.find(std::forward<K>(k));
if (i != map.end())
{
map.erase(i);
return true;
}
return false;
}
} // namespace

View File

@@ -0,0 +1,26 @@
// 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 <optional>
namespace tjp::core {
template<typename T, typename K>
auto map_erase_get_optional(T &map, K &&k)
{
auto i = map.find(std::forward<K>(k));
if (i != map.end())
{
auto v = std::make_optional(i->second);
map.erase(i);
return v;
}
return std::optional<typename T::mapped_type>();
}
} // namespace

View File

@@ -0,0 +1,29 @@
// 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 {
template<typename T, typename F>
auto map_erase_if(T &map, F &&f)
{
int erased = 0;
auto i = map.begin();
while (i != map.end())
{
if (f(*i))
{
++erased;
i = map.erase(i);
}
else
++i;
}
return erased;
}
} // namespace

View File

@@ -0,0 +1,29 @@
// 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 {
template<typename T, typename F>
auto map_erase_if_key(T &map, F &&f)
{
int erased = 0;
auto i = map.begin();
while (i != map.end())
{
if (f(i->first))
{
++erased;
i = map.erase(i);
}
else
++i;
}
return erased;
}
} // namespace

View File

@@ -0,0 +1,29 @@
// 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 {
template<typename T, typename F>
auto map_erase_if_value(T &map, F &&f)
{
int erased = 0;
auto i = map.begin();
while (i != map.end())
{
if (f(i->second))
{
++erased;
i = map.erase(i);
}
else
++i;
}
return erased;
}
} // namespace

View File

@@ -0,0 +1,16 @@
// 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 {
template<typename T, typename F>
auto map_for_each_value(T &map, F &&f)
{
for (auto i=map.begin(); i!=map.end(); ++i)
f(i->second);
}
} // namespace

17
tjp/core/algorithm/map_has.hpp Executable file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename M, typename K>
auto map_has(const M &m, K &&k)
{
return m.find(std::forward<K>(k)) != m.end();
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "map_has.hpp"
namespace tjp::core {
template<typename M, typename K>
bool map_has_key (const M &m, K &&k)
{
return map_has(m, std::forward<K>(k));
}
} // namespace

View File

@@ -0,0 +1,19 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <algorithm>
namespace tjp::core {
template<typename M, typename K, typename V>
auto map_insert(M &&m, K &&k, V &&v)
{
auto [i, inserted] = m.emplace(std::forward<K>(k), std::forward<V>(v));
return inserted;
}
} // namespace

View File

@@ -0,0 +1,35 @@
// 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 {
template<typename M, typename K>
auto map_iterator_insert(M &m, const K &k)
{
typedef typename M::mapped_type R;
auto i = m.find(k);
if (i != m.end())
return i;
auto [j, inserted] = m.emplace(k, R());
return j;
}
template<typename M, typename K, typename F>
auto map_iterator_insert(M &m, const K &k, F &&f)
{
auto i = m.find(k);
if (i != m.end())
return i;
auto [j, inserted] = m.emplace(k, f());
return j;
}
} // namespace

32
tjp/core/algorithm/map_pair.hpp Executable file
View File

@@ -0,0 +1,32 @@
// 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 {
template<typename M, typename K>
auto map_pair(const M &m, K &&k)
{
typedef typename M::value_type *R;
auto i = m.find(std::forward<K>(k));
if (i != m.end())
return &*i;
return (R)nullptr;
}
template<typename M, typename K>
auto map_pair(M &m, K &&k)
{
typedef typename M::value_type const *R;
auto i = m.find(std::forward<K>(k));
if (i != m.end())
return &*i;
return (R)nullptr;
}
} // namespace

View File

@@ -0,0 +1,20 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "map_erase.hpp"
namespace tjp::core {
template<typename M, typename K, typename V>
auto map_set_or_erase_optional(M &m, K &&k, V &&v)
{
if (v)
m[k] = *v;
else
map_erase(m, k);
}
} // namespace

View File

@@ -0,0 +1,25 @@
// 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 <utility>
namespace tjp::core {
template<typename M, typename K>
auto map_value(M &&m, K &&k)
{
static_assert(std::is_lvalue_reference_v<M&&>, "requires an lvalue");
auto i = m.find(std::forward<K>(k));
return
(i != m.end()) ?
&i->second :
nullptr;
}
} // namespace

View File

@@ -0,0 +1,28 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Optional.hpp"
namespace tjp::core {
template<typename M, typename K>
auto map_value_erase(M &m, K &&k)
{
typedef typename M::mapped_type R;
auto i = m.find(std::forward<K>(k));
if (i != m.end())
{
auto result = Optional<R>(std::move(i->second));
m.erase(i);
return result;
}
return Optional<R>();
}
} // namespace

View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Optional.hpp"
namespace tjp::core {
template<typename M, typename K>
auto map_value_optional(M &m, K &&k)
{
typedef typename M::mapped_type R;
auto i = m.find(std::forward<K>(k));
if (i != m.end())
{
return Optional<R>(std::move(i->second));
}
return Optional<R>();
}
} // namespace

View File

@@ -0,0 +1,19 @@
// 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 {
template<typename M, typename K, typename V, typename R = typename M::mapped_type>
R map_value_or_default(const M &m, K &&k, V &&v)
{
auto i = m.find(std::forward<K>(k));
if (i != m.end())
return i->second;
return R(v);
}
} // namespace

View File

@@ -0,0 +1,21 @@
// 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 {
template<typename M, typename K, typename F>
auto &map_value_or_insert(M &m, const K &k, const F &f)
{
auto i = m.find(k);
if (i != m.end())
return i->second;
auto [j, inserted] = m.emplace(k, f());
return j->second;
}
} // namespace

View File

@@ -0,0 +1,16 @@
// 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 {
template<typename M, typename K, typename V>
auto map_value_or_insert_value(M &m, K &&k, V &&v)
{
auto [i, inserted] = m.emplace(std::forward<K>(k), std::forward<V>(v));
return &i->second;
}
} // namespace

Some files were not shown because too many files have changed in this diff Show More