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

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.DS_Store
*.pyc
xcuserdata
.bin
transfer-to-*
temp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6E97D10281EF664004C92E9"
BuildableName = "Core_Zero_Tests"
BlueprintName = "Core_Zero_Tests"
ReferencedContainer = "container:Core_Zero.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6E97D10281EF664004C92E9"
BuildableName = "Core_Zero_Tests"
BlueprintName = "Core_Zero_Tests"
ReferencedContainer = "container:Core_Zero.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-s"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-b"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::math::Float16&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::algorithm::on_destruct&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::split_once&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::algorithm::container_get_if&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::algorithm::small_copy&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::enumerate&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::no_last&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::no_first&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::zip&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::is_first&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::range&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::range_with&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::safe_next&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::iterators::transform_with&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::log::LogOf&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::ptr&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::const_hash&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::const_hash::expected&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::rtti::type_name&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::rtti&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::join&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::cmp_case&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::replace&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::trim&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::timer::Timer&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::string::str&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: vectorpool&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: safe iteration of lists&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::containers::InPlace&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: MultiContainer&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: allocator_pool::Stack&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: SizeAllocatorPool&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::allocator_pool::prune::Pruning&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: stackarray_v2&quot;"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F6E97D10281EF664004C92E9"
BuildableName = "Core_Zero_Tests"
BlueprintName = "Core_Zero_Tests"
ReferencedContainer = "container:Core_Zero.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

188
Examples.cpp Normal file
View File

@@ -0,0 +1,188 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/log/Log.h>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/containers/Map.hpp>
#include <tjp/core/algorithm/map_value.hpp>
#include <tjp/core/algorithm/map_value_erase.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/time/Time+chrono.hpp>
namespace my_base_namespace {
namespace ext = tjp::core;
using namespace ext;
}
// or
namespace my_base_namespace {
namespace ext = tjp::core;
using ext::Mutex;
}
namespace my_base_namespace::sub_name_space {
void do_something() {}
template<typename T>
void do_something_with(T &&) {}
// ----------------------------------------
// example for locks
// ----------------------------------------
void example_lock_tjp()
{
Mutex mutex;
auto lock = lock_of(mutex);
do_something();
auto should_send_signal = true;
if (should_send_signal)
{
auto unlock = unlock_of(mutex);
do_something();
}
}
// using std
void example_lock_cpp()
{
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
do_something();
auto should_send_signal = true;
if (should_send_signal)
{
try
{
mutex.unlock();
do_something();
mutex.lock();
}
catch (...)
{
mutex.lock();
}
}
}
// ----------------------------------------
// example for maps
// ----------------------------------------
void example_map_tjp()
{
Map<int, int> map;
if (auto value = map_value(map, 42))
do_something_with(*value);
if (auto value = map_value_erase(map, 42))
do_something_with(*value);
}
// using std
void example_map_cpp()
{
std::map<int, int> map;
auto i = map.find(42);
if (i != map.end())
{
do_something_with(*i);
}
auto j = map.find(42);
if (j != map.end())
{
auto v = std::move(j->second);
map.erase(j);
do_something_with(v);
}
}
// ----------------------------------------
// example for range
// ----------------------------------------
void example_range_cpp()
{
for (auto k=0; k<42; ++k)
do_something_with(k);
}
void example_range_tjp()
{
for (auto i: range(42))
do_something_with(i);
}
// ----------------------------------------
// time
// ----------------------------------------
void example_time_duration_cpp()
{
auto t1 = std::chrono::system_clock::now();
do_something();
auto t2 = std::chrono::system_clock::now();
auto duration = t2 - t1;
auto duration_serializable_number = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
do_something_with(duration_serializable_number);
auto duration_in_seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
do_something_with(duration_in_seconds);
auto two_second_after_t1 = t1 + std::chrono::seconds(2);
do_something_with(two_second_after_t1);
auto meters = 32.;
auto seconds = std::chrono::seconds(2);
auto meters_per_second = meters / std::chrono::duration<float>(seconds).count();
do_something_with(meters_per_second);
meters = std::chrono::duration<float>(seconds).count() * meters_per_second;
do_something_with(meters);
}
void example_time_duration_tjp()
{
auto t1 = time::now();
do_something();
auto t2 = time::now();
auto duration = t2 - t1;
auto duration_serializable_number = duration.v;
do_something_with(duration_serializable_number);
auto duration_in_seconds = duration / time::Seconds;
do_something_with(duration_in_seconds);
auto two_second_after_t1 = t1 + time::Seconds(2);
auto two_second_after_t1_another = t1 + 2 * time::Seconds;
do_something_with(two_second_after_t1);
do_something_with(two_second_after_t1_another);
auto meters = 32.;
auto seconds = 2 * time::Seconds;
auto meters_per_second = meters / seconds;
do_something_with(meters_per_second);
meters = seconds * meters_per_second;
do_something_with(meters);
}
} // namespace

26
LICENSE Executable file
View File

@@ -0,0 +1,26 @@
MIT NON-AI License
Copyright (c) 2025, Timothy Prepscius
Permission is hereby granted, free of charge, to any person obtaining a copy of the software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
In addition, the following restrictions apply:
1. The Software and any modifications made to it may not be used for the purpose of training or improving machine learning algorithms,
including but not limited to artificial intelligence, natural language processing, or data mining. This condition applies to any derivatives,
modifications, or updates based on the Software code. Any usage of the Software in an AI-training dataset is considered a breach of this License.
2. The Software may not be included in any dataset used for training or improving machine learning algorithms,
including but not limited to artificial intelligence, natural language processing, or data mining.
3. Any person or organization found to be in violation of these restrictions will be subject to legal action and may be held liable
for any damages resulting from such use.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

8
Makefile Normal file
View File

@@ -0,0 +1,8 @@
###################################
# License: Modified MIT (NON-AI)
# Copyright 2025 Timothy Prepscius
# See the LICENSE file in the root directory for license information.
###################################
ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..)
include $(ROOTDIR)/Core_Make/tjp/Make/Makefile

11
Makefile.def Executable file
View File

@@ -0,0 +1,11 @@
###################################
# License: Modified MIT (NON-AI)
# Copyright 2025 Timothy Prepscius
# See the LICENSE file in the root directory for license information.
###################################
timprepscius.core_zero.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
timprepscius.core_zero.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR)
timprepscius.core.include := $(timprepscius.core.include) $(timprepscius.core_zero.include)
timprepscius.core.link := $(timprepscius.core.link) $(timprepscius.core_zero.link)

51
Makefile.project Executable file
View File

@@ -0,0 +1,51 @@
###################################
# License: Modified MIT (NON-AI)
# Copyright 2025 Timothy Prepscius
# See the LICENSE file in the root directory for license information.
###################################
include $(MAKEDIR)/Makefile.base
PROJECTS := \
tjp/core/algorithm \
tjp/core/assert \
tjp/core/containers \
tjp/core/const_hash \
tjp/core/debug \
tjp/core/exception \
tjp/core/io \
tjp/core/iterators \
tjp/core/log \
tjp/core/ptr \
tjp/core/ptr/std \
tjp/core/ptr/using_maps \
tjp/core/ptr/using_info \
tjp/core/sfinae \
tjp/core/string \
tjp/core/system \
tjp/core/testing \
tjp/core/threads \
tjp/core/threads/std \
tjp/core/time \
tjp/core/timer \
tjp/core/type_traits \
tjp/core/types \
ifeq (Android,$(SYS_NAME))
PROJECTS += \
tjp/core/debug/android \
else
PROJECTS += \
tjp/core/debug/glib \
endif
SRC_PCH := tjp/core/Precompile.pch
INCPATH := $(timprepscius.libraries.cpp.include)
LIBFILE := libCore_Zero.a
COPYTO := $(LIBRARIES_PROJECT)
include $(MAKEDIR)/Makefile.lib

141
ReadMe.md Executable file
View File

@@ -0,0 +1,141 @@
# Core_Zero
Basic foundational classes
## Building
Most of Core_Zero is header-only.
To enable header-only use:
`#define TJP_CORE_HEADER_ONLY`
The entire Core_Zero project will be converted to header only compatible soon.
To build all of the project use these steps.
```
mkdir my_project
cd my_project
git clone http://github.com/timprepscius/Core_Libraries
git clone http://github.com/timprepscius/Core_Zero
git clone http://github.com/timprepscius/Core_Make
cd Core_Zero
make
cd tests
make
.bin/Core_Zero_Tests.exe
```
## How to use
### Locks
```
// ----------------------------------------
// example for locks
// ----------------------------------------
void example_lock_tjp()
{
Mutex mutex;
auto lock = lock_of(mutex);
do_something();
auto should_send_signal = true;
if (should_send_signal)
{
auto unlock = unlock_of(mutex);
do_something();
}
}
// using std
void example_lock_cpp()
{
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
do_something();
auto should_send_signal = true;
if (should_send_signal)
{
try
{
mutex.unlock();
do_something();
mutex.lock();
}
catch (...)
{
mutex.lock();
}
}
}
```
### Maps
```
// ----------------------------------------
// example for maps
// ----------------------------------------
void example_map_tjp()
{
Map<int, int> map;
if (auto value = map_value(map, 42))
do_something_with(*value);
if (auto value = map_value_erase(map, 42))
do_something_with(*value);
}
// using std
void example_map_cpp()
{
std::map<int, int> map;
auto i = map.find(42);
if (i != map.end())
{
do_something_with(*i);
}
auto j = map.find(42);
if (j != map.end())
{
auto v = std::move(j->second);
map.erase(j);
do_something_with(v);
}
}
```
### Range iteration
```
// ----------------------------------------
// example for range
// ----------------------------------------
void example_range_tjp()
{
for (auto i: range(42))
do_something_with(i);
}
// using std
void example_range_cpp()
{
for (auto k=0; k<42; ++k)
do_something_with(k);
}
```
### Other examples
Look at `Core_Zero/Examples.cpp` for more examples on how to use this library.

0
core Normal file
View File

1
tests/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../../Make/Makefile

36
tests/Makefile.project Executable file
View File

@@ -0,0 +1,36 @@
include $(MAKEDIR)/Makefile.base
PROJECTS := \
. \
../core/algorithm/_tests \
../core/const_hash/_tests \
../core/const_expr/_tests \
../core/containers/_tests \
../core/iterators/_tests \
../core/log/_tests \
../core/ptr/_tests \
../core/ptr/using_info/_tests \
../core/ptr/using_maps/_tests \
../core/rtti/_tests \
../core/testing/_tests \
INCPATH := \
$(timprepscius.libraries.cpp.include) \
$(timprepscius.core.include)
LDPATH := \
$(timprepscius.libraries.cpp.link)
LIBS := \
-lCore_Zero
EXEFILE := Core_Zero_Tests.exe
#COPYTO := $(ROOTDIR)/.bin
ifeq (Darwin,$(SYS_NAME))
LIBS += -lc++
endif
include $(MAKEDIR)/Makefile.bin

21
tests/Run.cpp Normal file
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
#define CATCH_CONFIG_RUNNER
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
using namespace tjp;
using namespace core;
int main( int argc, char* argv[] )
{
xLogInitialize();
xLogActivateStory("testing");
xLogActivateStory("debug");
int result = Catch::Session().run( argc, argv );
return result;
}

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

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