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

13
tjp/core/containers/Align.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#ifdef __GNUC__
#define ALIGN( X, __Declaration__ ) __Declaration__ __attribute__((aligned(X)))
#endif
#ifdef _MSC_VER
#define ALIGN( __Declaration__ ) __pragma( align(push, 4) ) __Declaration__ __pragma( pack(pop))
#endif

View File

@@ -0,0 +1,36 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Array.hpp"
#include "../assert/debug_assert.h"
namespace std {
template<typename IO, typename T, size_t Size>
void io_r(IO &io, std::array<T, Size> &t)
{
auto size = io.array_begin();
debug_assert(size == Size);
for (auto &v: t)
io.on_vector_value(v);
io.array_end();
}
//template<typename IO, typename T, size_t Size>
//void io_w(IO &io, std::array<T, Size> &t)
//{
// io.array_begin(t.size());
// debug_assert(size == Size);
//
// for (auto &v: t)
// io.on_vector_value(v);
//
// io.array_end();
//}
} // namespace

14
tjp/core/containers/Array.h 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
#include <array>
namespace tjp::core {
template<typename T, int N>
using Array = std::array<T, N>;
} // namespace

7
tjp/core/containers/Array.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Array.h"

34
tjp/core/containers/ByF.hpp Executable file
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
#pragma once
namespace tjp::core {
template<typename T, typename F>
struct ByF {
typedef bool is_transparent;
[[no_unique_address]]
F f;
bool operator() (const T &lhs, const T &rhs) const
{
return f(lhs) < f(rhs);
}
template<typename R>
bool operator() (const T &lhs, const R &rhs) const
{
return f(lhs) < f(rhs);
}
template<typename R>
bool operator() (const R &lhs, const T &rhs) const
{
return f(lhs) < f(rhs);
}
} ;
}

31
tjp/core/containers/ById.hpp Executable file
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
namespace tjp::core {
template<typename T>
struct ById {
typedef bool is_transparent;
bool operator() (const T &lhs, const T &rhs) const
{
return lhs.id < rhs.id;
}
template<typename R>
bool operator() (const T &lhs, const R &rhs) const
{
return lhs.id < rhs;
}
template<typename R>
bool operator() (const R &lhs, const T &rhs) const
{
return lhs < rhs.id;
}
} ;
}

31
tjp/core/containers/ByPtr.hpp Executable file
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 "../ptr/Ptr.h"
namespace tjp::core {
template<typename T>
struct ByPtr {
typedef bool is_transparent;
bool operator() (const StrongPtr<T> &lhs, const StrongPtr<T> &rhs) const
{
return ptr_of(lhs) < ptr_of(rhs);
}
bool operator() (const StrongPtr<T> &lhs, const T *rhs) const
{
return ptr_of(lhs) < rhs;
}
bool operator() (const T *lhs, const StrongPtr<T> &rhs) const
{
return lhs < ptr_of(rhs);
}
} ;
}

42
tjp/core/containers/ByPtrId.hpp Executable file
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
#pragma once
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/assert/debug_assert.h>
namespace tjp::core {
template<typename T>
struct ByPtrId {
typedef bool is_transparent;
bool operator() (const T *lhs, const T *rhs) const
{
debug_assert(lhs);
debug_assert(rhs);
return lhs->id < rhs->id;
}
template<typename R>
bool operator() (const T *lhs, const R &rhs) const
{
debug_assert(lhs);
debug_assert(rhs);
return lhs->id < rhs;
}
template<typename R>
bool operator() (const R &lhs, const T *rhs) const
{
debug_assert(lhs);
debug_assert(rhs);
return lhs < rhs->id;
}
} ;
}

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
#pragma once
#include <tjp/core/ptr/Ptr.hpp>
namespace tjp::core {
template<typename T>
struct ByStrongPtrId {
typedef bool is_transparent;
bool operator() (const StrongPtr<T> &lhs, const StrongPtr<T> &rhs) const
{
return lhs->id < rhs->id;
}
template<typename R>
bool operator() (const StrongPtr<T> &lhs, const R &rhs) const
{
return lhs->id < rhs;
}
template<typename R>
bool operator() (const R &lhs, const StrongPtr<T> &rhs) const
{
return lhs < rhs->id;
}
} ;
}

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 {
namespace core {
/**
* std list and vector and set are too slow for some reason, need fast allocation, with
*/
template<typename T, int N=32>
struct FilledArray;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,66 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "FilledArray.h"
#include "StackArray.hpp"
#include "../debug/Debug.h"
#include "../assert/debug_assert.h"
#include <memory>
#include <cstring> // memcpy
#include "../threads/TestCollision.h"
namespace tjp {
namespace core {
template<typename T, int N>
struct FilledArray : StackArray<T, N>
{
using Super = StackArray<T, N>;
using iterator = typename Super::iterator;
using const_iterator = typename Super::const_iterator;
void insert(const T &element)
{
this->push_back(element);
}
void erase (typename Super::iterator i)
{
if (i == this->end())
return;
auto &back = this->back();
if (i != &back)
*i = std::move(back);
this->pop_back();
}
void erase (const T &element)
{
erase(find(element));
}
iterator find (const T &element)
{
// now iterator all except for what used to be the end element
for (auto i=this->begin(); i!=this->end(); ++i)
{
if (*i == element)
{
// the end element was the last element
return i;
}
}
return this->end();
}
} ;
} // namespace utilities
} // 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 "../threads/Lock.h"
namespace tjp {
namespace core {
/**
* std list and vector and set are too slow for some reason, need fast allocation, with
*/
template<typename T, int N=32, typename M = Mutex>
class FilledArrayThreadSafe;
} // namespace utilities
} // 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
#pragma once
#include "FilledArrayThreadSafe.h"
#include "FilledArray.hpp"
namespace tjp {
namespace core {
/**
* std list and vector and set are too slow for some reason, need fast allocation, with
*/
template<typename T, int N, typename M>
struct FilledArrayThreadSafe : FilledArray<T,N>
{
typedef FilledArray<T,N> Super;
typedef M Mutex;
Mutex m;
template<typename ... U>
FilledArrayThreadSafe(U&& ...u) :
Super(std::forward<U>(u)...)
{
}
} ;
} // namespace utilities
} // namespace

14
tjp/core/containers/Function.h 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
#include <functional>
namespace tjp::core {
template<typename V>
using Function = std::function<V>;
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Function.h"

View File

@@ -0,0 +1,64 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../assert/debug_assert.h"
#include "../assert/handle_assert.hpp"
#include "../algorithm/mem_copy.hpp"
#include <cstring> // for memcpy
namespace tjp::core {
template<typename T, size_t N>
auto rbegin(InPlaceArray<T, N> &t)
{
return t.rbegin();
}
template<typename T, size_t N>
auto rend(InPlaceArray<T, N> &t)
{
return t.rend();
}
template<typename T, size_t N>
auto rbegin(const InPlaceArray<T, N> &t)
{
return t.rbegin();
}
template<typename T, size_t N>
auto rend(const InPlaceArray<T, N> &t)
{
return t.rend();
}
template<typename T, size_t N>
auto begin(InPlaceArray<T, N> &t)
{
return t.begin();
}
template<typename T, size_t N>
auto end(InPlaceArray<T, N> &t)
{
return t.end();
}
template<typename T, size_t N>
auto begin(const InPlaceArray<T, N> &t)
{
return t.begin();
}
template<typename T, size_t N>
auto end(const InPlaceArray<T, N> &t)
{
return t.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 <stddef.h>
namespace tjp {
namespace core {
template<typename T, size_t N=32>
class InPlaceArray;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,137 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "InPlaceArray.h"
#include "Array.h"
#include <cstddef>
#include <memory>
#include <array>
#include "../types/Types.h"
namespace tjp {
namespace core {
template<typename T, size_t N>
class InPlaceArray
{
public:
static constexpr size_t MaxLength = N;
private:
using Array = std::array<T, N>;
using Block = char;
using Size = u32;
union Static {
Block block;
Array array;
Static() : block(0) {}
~Static () {}
} ;
Static v;
Size length = 0;
typedef std::allocator<T> Allocator;
Allocator allocator;
public:
using value_type = typename Array::value_type;
using iterator = typename Array::iterator;
using const_iterator = typename Array::const_iterator;
using pointer = typename Array::pointer;
using reference = typename Array::reference;
using const_reference = typename Array::const_reference;
inline auto data() { return v.array.data(); }
inline auto data() const { return v.array.data(); }
inline auto begin() { return v.array.begin(); }
inline auto end () { return v.array.begin() + length; }
inline auto begin() const { return v.array.begin(); }
inline auto end () const { return v.array.begin() + length; }
inline auto rbegin() { return v.array.rbegin() + (v.array.size() - length); }
inline auto rend () { return v.array.rend(); }
inline auto rbegin() const { return v.array.rbegin() + (v.array.size() - length); }
inline auto rend () const { return v.array.rend(); }
inline const_reference front () const { return v.array.front(); }
inline const_reference back () const { return *(v.array.data() + (length - 1)); }
inline reference front () { return v.array.front(); }
inline reference back () { return *(v.array.data() + (length - 1)); }
private:
template<typename ... Args>
void construct(T *t, Args&& ...args)
{
std::allocator_traits<Allocator>::construct(allocator, t, std::forward<Args>(args)...);
}
void destruct(T *t)
{
std::allocator_traits<Allocator>::destroy(allocator, t);
}
protected:
void shorten_block(size_t length_);
void shorten_items(size_t length_);
void shorten(size_t length_);
void append_block(const T *begin, const T *end);
void append_items(const T *begin, const T *end);
void emplace_items(T *begin, T *end);
public:
InPlaceArray ();
InPlaceArray(size_t length_, T t=T());
// InPlaceArray(InPlaceArray &&rhs);
// template<size_t N2>
InPlaceArray(const InPlaceArray<T, N> &rhs);
InPlaceArray(const std::initializer_list<T> &rhs);
InPlaceArray(const T *begin, const T *end);
InPlaceArray(const T *begin, size_t size);
// template<size_t N2>
InPlaceArray &operator =(const InPlaceArray<T, N> &rhs);
InPlaceArray &operator =(const Array &rhs);
~InPlaceArray ();
void resize(size_t length_, T t=T());
void append(const T *begin, const T *end);
void emplace(T *begin, T *end);
void push_back_();
void push_back (const T &element);
void push_back (T &&element);
void pop_back ();
template<typename ... Args>
T &emplace_back (Args&& ...args);
const T &at(size_t i) const;
T &at(size_t i);
const T &operator[] (size_t i) const;
T &operator[] (size_t i);
size_t size () const;
void clear ();
bool empty () const;
} ;
} // namespace utilities
} // namespace
#include "InPlaceArray.inl"
#include "InPlaceArray+iterator.inl"

View File

@@ -0,0 +1,333 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../assert/debug_assert.h"
#include "../assert/handle_assert.hpp"
#include "../algorithm/mem_copy.hpp"
#include "../exception/OutOfBounds.hpp"
#include <cstring> // for memcpy
namespace tjp {
namespace core {
template<typename T, size_t N>
InPlaceArray<T, N>::InPlaceArray (size_t size, T t)
{
resize(size, t);
}
template<typename T, size_t N>
InPlaceArray<T, N>::InPlaceArray ()
{
}
template<typename T, size_t N>
//template<size_t N2>
InPlaceArray<T, N>::InPlaceArray(const InPlaceArray<T, N> &rhs)
{
append(rhs.begin(), rhs.end());
}
template<typename T, size_t N>
//template<size_t N2>
InPlaceArray<T, N>::InPlaceArray(const T *begin, const T *end)
{
append(begin, end);
}
template<typename T, size_t N>
//template<size_t N2>
InPlaceArray<T, N>::InPlaceArray(const T *data, size_t size)
{
append(data, data + size);
}
//template<typename T, size_t N>
//InPlaceArray<T, N>::InPlaceArray(InPlaceArray<T, N> &&rhs)
//{
// append(rhs.begin(), rhs.end());
//}
template<typename T, size_t N>
//template<size_t N2>
InPlaceArray<T,N> &InPlaceArray<T, N>::operator =(const InPlaceArray<T, N> &rhs)
{
if (this == &rhs)
return *this;
clear();
append(rhs.begin(), rhs.end());
return *this;
}
template<typename T, size_t N>
//template<size_t N2>
InPlaceArray<T,N> &InPlaceArray<T, N>::operator =(const Array &rhs)
{
if (&v.array != &rhs)
v.array = rhs;
length = N;
return *this;
}
template<typename T, size_t N>
InPlaceArray<T, N>::InPlaceArray(const std::initializer_list<T> &rhs)
{
for (auto &element: rhs)
push_back(element);
}
template<typename T, size_t N>
void InPlaceArray<T, N>::append_block(const T *begin_, const T *end_)
{
auto size = (end_ - begin_);
handle_assert(length + size <= N) {
throw exceptions::OutOfBounds();
}
mem_copy((char *)end(), (char *)begin_, size * sizeof(T));
length += size;
}
template<typename T, size_t N>
void InPlaceArray<T, N>::append_items(const T *begin_, const T *end_)
{
for (auto i = begin_; i!=end_; ++i)
push_back(*i);
}
template<typename T, size_t N>
void InPlaceArray<T, N>::emplace_items(T *begin_, T *end_)
{
for (auto i = begin_; i!=end_; ++i)
emplace_back(std::move(*i));
}
template<typename T, size_t N>
void InPlaceArray<T, N>::append(const T *begin, const T *end)
{
if constexpr (std::is_trivially_copyable<T>::value)
return append_block(begin, end);
else
return append_items(begin, end);
}
template<typename T, size_t N>
void InPlaceArray<T, N>::emplace(T *begin, T *end)
{
if constexpr (std::is_trivially_copyable<T>::value)
return append_block(begin, end);
else
return emplace_items(begin, end);
}
template<typename T, size_t N>
InPlaceArray<T, N>::~InPlaceArray ()
{
clear();
}
template<typename T, size_t N>
void InPlaceArray<T, N>::shorten_items(size_t length_)
{
while (length > length_)
pop_back();
}
template<typename T, size_t N>
void InPlaceArray<T, N>::shorten_block(size_t length_)
{
if (length > length_)
length = (Size)length_;
}
template<typename T, size_t N>
void InPlaceArray<T, N>::shorten(size_t length_)
{
if constexpr (std::is_trivially_destructible<T>::value)
return shorten_block(length_);
else
return shorten_items(length_);
}
template<typename T, size_t N>
void InPlaceArray<T, N>::resize(size_t length_, T t)
{
shorten(length_);
handle_assert(length_ <= N) {
throw exceptions::OutOfBounds();
}
if constexpr (std::is_trivially_copyable<T>::value)
{
if (length < length_)
{
auto *data_ = data();
auto *begin = data_ + length;
auto *end = data_ + length_;
std::fill(begin, end, t);
length = (Size)length_;
}
}
else
{
while (length < length_)
push_back(t);
}
}
template<typename T, size_t N>
void InPlaceArray<T, N>::push_back (const T &element)
{
handle_assert(length < N) {
throw exceptions::OutOfBounds();
}
++length;
if constexpr (std::is_trivially_copyable<T>::value)
{
back() = element;
}
else
{
construct(&back(), element);
}
}
template<typename T, size_t N>
void InPlaceArray<T, N>::push_back (T &&element)
{
handle_assert(length < N) {
throw exceptions::OutOfBounds();
}
++length;
construct(&back(), std::move(element));
}
template<typename T, size_t N>
void InPlaceArray<T, N>::pop_back ()
{
debug_assert (length > 0);
// decrease length
if (length > 0)
{
--length;
destruct(&v.array[length]);
}
}
template<typename T, size_t N>
template<typename ... Args>
T &InPlaceArray<T, N>::emplace_back (Args&& ...element)
{
handle_assert(length < N) {
throw exceptions::OutOfBounds();
}
++length;
auto &t = back();
construct(&t, std::forward<Args>(element)...);
return t;
}
template<typename T, size_t N>
const T &InPlaceArray<T, N>::at(size_t i) const
{
return v.array[i];
}
template<typename T, size_t N>
T &InPlaceArray<T, N>::at(size_t i)
{
return v.array[i];
}
template<typename T, size_t N>
const T &InPlaceArray<T, N>::operator[] (size_t i) const
{
return at(i);
}
template<typename T, size_t N>
T &InPlaceArray<T, N>::operator[] (size_t i)
{
return at(i);
}
template<typename T, size_t N>
size_t InPlaceArray<T, N>::size () const
{
return length;
}
template<typename T, size_t N>
void InPlaceArray<T, N>::clear ()
{
shorten(0);
}
template<typename T, size_t N>
bool InPlaceArray<T, N>::empty () const
{
return length == 0;
}
template<typename T, size_t N>
bool operator <(const InPlaceArray<T, N> &lhs, const InPlaceArray<T, N> &rhs)
{
auto max = std::min(lhs.size(), rhs.size());
for (auto i=0; i<max; ++i)
{
auto &l = lhs.at(i);
auto &r = rhs.at(i);
if (l != r)
return l < r;
}
return lhs.size() < rhs.size();
}
template<typename T, size_t N>
bool operator ==(const InPlaceArray<T, N> &lhs, const InPlaceArray<T, N> &rhs)
{
if (lhs.size() != rhs.size())
return false;
for (auto i=0; i<lhs.size(); ++i)
{
auto &l = lhs.at(i);
auto &r = rhs.at(i);
if (l != r)
return false;
}
return true;
}
template<typename T, size_t N>
bool operator !=(const InPlaceArray<T, N> &lhs, const InPlaceArray<T, N> &rhs)
{
return !(lhs == rhs);
}
} // namespace utilities
} // namespace

14
tjp/core/containers/List.h 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
#include <list>
namespace tjp::core {
template<typename V>
using List = std::list<V>;
} // namespace

7
tjp/core/containers/List.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "List.h"

14
tjp/core/containers/Map.h 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
#include <map>
namespace tjp::core {
template<typename K, typename V, typename L=std::less<K>, typename A=std::allocator<std::pair<const K, V>>>
using Map = std::map<K, V, L, A>;
} // namespace

7
tjp/core/containers/Map.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Map.h"

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 "Vector.h"
namespace tjp::core {
namespace memory_array {
template<typename T>
struct MemoryArrayIterator;
template<typename T>
struct MemoryArray;
} // namespace
using namespace memory_array;
} // namespace

View File

@@ -0,0 +1,170 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "MemoryArray.h"
#include "Vector.h"
#include "../assert/debug_assert.h"
namespace tjp::core {
namespace memory_array {
template<typename T>
struct MemoryArrayIterator
{
char *ptr_;
size_t stride_;
size_t offset_;
void operator ++()
{
ptr_ += stride_;
}
T &operator *()
{
return *(T *)(ptr_ + offset_);
}
bool operator !=(const MemoryArrayIterator<T> &rhs)
{
return ptr_ != rhs.ptr_;
}
} ;
template<typename T>
struct MemoryArray
{
char *begin_;
size_t size_;
size_t stride_;
size_t offset_;
typedef T value_type;
MemoryArray(char *begin, size_t size, size_t stride, size_t offset) :
begin_(begin),
size_(size),
stride_(stride),
offset_(offset)
{}
MemoryArray(const Vector<T> &v) :
begin_((char *)(v.data())),
size_(v.size()),
stride_(sizeof(T)),
offset_(0)
{}
T &at(size_t index) const
{
char *ptr = (begin_ + stride_*index) + offset_;
return *(T *)ptr;
}
auto &operator[](size_t index) const
{
return at(index);
}
auto begin () const
{
return MemoryArrayIterator<T> { begin_, stride_, offset_ };
}
auto end () const
{
return MemoryArrayIterator<T> { (begin_ + stride_*size_), stride_, offset_ };
}
auto &front () const
{
return at(0);
}
auto &back () const
{
return at(size()-1);
}
auto size() const
{
return size_;
}
bool empty() const
{
return size_ == 0;
}
template<typename U>
auto recast() const
{
return MemoryArray<U> { begin_, size_, stride_, offset_ };
}
} ;
template<typename R>
MemoryArray<R> memoryArray()
{
return MemoryArray<R> { nullptr, 0, 0, 0 };
}
template<typename R>
MemoryArray<R> memoryArray(void *begin, size_t size, size_t stride, size_t offset)
{
return MemoryArray<R> { (char *)begin, size, stride, offset };
}
// ----------------------------------
template<typename R, typename T>
MemoryArray<R> memoryArray(const T *begin, size_t size)
{
static_assert(sizeof(R) <= sizeof(T));
return memoryArray<R>((void *)begin, size, sizeof(T), 0);
}
template<typename R, typename T>
MemoryArray<R> memoryArray(const T *begin, size_t size, size_t offset)
{
static_assert(sizeof(R) <= sizeof(T));
return memoryArray<R>((void *)begin, size, sizeof(T), offset * sizeof(T));
}
template<typename T>
MemoryArray<T> memoryArray(const T *begin, size_t size)
{
return memoryArray<T, T>(begin, size);
}
template<typename T>
MemoryArray<T> memoryArray(const T *begin, size_t size, size_t offset)
{
return memoryArray<T, T>(begin, size, offset);
}
// ----------------------------------
template<typename R, typename T>
MemoryArray<R> memoryArray(const Vector<T> &data)
{
return memoryArray<R, T>(data.data(), data.size());
}
template<typename T>
MemoryArray<T> memoryArray(const Vector<T> &data)
{
return memoryArray<T, T>(data);
}
} // namespace
using namespace memory_array;
} // namespace

View File

@@ -0,0 +1,13 @@
// 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::containers {
template<typename T>
struct MemorySegment;
} // namespace

View File

@@ -0,0 +1,75 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "MemorySegment.h"
#include <stddef.h>
namespace tjp::core::containers {
template<typename T>
struct MemorySegment
{
using value_type = T;
using size_type = size_t;
T *data_ = nullptr;
size_t size_ = 0;
using iterator = T *;
using const_iterator = T *;
iterator begin() { return data_; }
iterator end() { return data_ + size_; }
const_iterator begin() const { return data_; }
const_iterator end() const { return data_ + size_; }
T *data() { return data_; }
const T *data() const { return data_; }
size_t size() const { return size_; }
T &operator[](size_t i)
{
return data_[i];
}
const T &operator[](size_t i) const
{
return data_[i];
}
};
template<typename T>
inline
MemorySegment<T> memory_segment(T *t, size_t size)
{
return MemorySegment<T> { t, size };
}
template<typename C, typename T>
inline
MemorySegment<C> memory_segment(T *t, size_t size)
{
return MemorySegment<C> { (C *)t, size * sizeof(T) / sizeof(C) };
}
template<typename C, typename T>
inline
MemorySegment<C> memory_segment_vector(const T &t)
{
return { (C *)t.data(), t.size() * sizeof(typename T::value_type) / sizeof(C) };
}
template<typename C, typename T>
inline
MemorySegment<C> memory_segment_value(const T &t)
{
return MemorySegment<C> { (C *)&t, sizeof(T) / sizeof(C) };
}
} // namespace

View File

@@ -0,0 +1,232 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StackArray.hpp"
#include "../exception/OutOfBounds.hpp"
#include "../algorithm/vector_erase_if_value.hpp"
namespace tjp::core {
template<typename T>
using MultiContainer_ = StackArray<T *>;
template<typename T, typename I, typename J>
struct MultiIterator
{
using Self = MultiIterator<T,I,J>;
using value_type = typename T::value_type;
using reference = typename T::reference;
I end;
I i;
J j;
bool ended;
MultiIterator()
{
}
MultiIterator(I &&end_, I &&i_, J &&j_, bool ended_) :
end(end_),
i(i_),
j(j_),
ended(ended_)
{
validate();
}
auto &deref ()
{
return *j;
}
auto &operator *() { return deref(); }
auto &operator ->() { return deref(); }
void validate()
{
while (!ended && j == (*i)->end())
{
++i;
if (i == end)
ended = true;
else
j = (*i)->begin();
}
}
void next()
{
if (ended)
return;
++j;
validate();
}
auto &operator++(int)
{
next();
return *this;
}
auto operator++()
{
auto v = *this;
next();
return v;
}
bool operator ==(const Self &rhs) const
{
return
(ended && rhs.ended) ||
(i == rhs.i && j == rhs.j);
}
bool operator !=(const Self &rhs) const
{
return !(*this == rhs);
}
} ;
template<typename T, typename C=MultiContainer_<T>>
struct MultiContainer {
C c;
using Self = MultiContainer<T, C>;
using iterator = MultiIterator<T,typename C::iterator,typename T::iterator>;
using const_iterator = MultiIterator<T,typename C::const_iterator,typename T::const_iterator>;
using value_type = typename T::value_type;
using reference = typename T::reference;
MultiContainer()
{}
template<typename ... Args>
MultiContainer(Args ... args)
{
(add(args),...);
}
template<typename CI, typename TI, typename U>
static auto begin(U &self)
{
auto &c = self.c;
CI end = c.end();
CI i = c.begin();
TI j;
auto ended = c.empty();
if (!ended)
{
j = (*i)->begin();
}
return MultiIterator<T,CI,TI>(
std::move(end),
std::move(i),
std::move(j),
ended
);
}
template<typename CI, typename TI, typename U>
static auto end(U &self)
{
auto &c = self.c;
CI end = c.end();
CI i = c.end();
TI j;
return MultiIterator<T,CI,TI>(
std::move(end),
std::move(i),
std::move(j),
true
);
}
auto begin()
{
return begin<typename C::iterator, typename T::iterator>(*this);
}
auto end()
{
return end<typename C::iterator, typename T::iterator>(*this);
}
auto begin() const
{
return begin<typename C::const_iterator, typename T::const_iterator>(*this);
}
auto end() const
{
return end<typename C::const_iterator, typename T::const_iterator>(*this);
}
void add(T *t)
{
c.push_back(t);
}
void remove(T *t)
{
auto i = std::find(c.begin(), c.end(), t);
if (i != c.end())
{
std::swap(*i, c.back());
c.pop_back();
}
}
auto container_size() const
{
return c.size();
}
auto size() const
{
size_t size_ = 0;
for (auto *v : c)
size_ += v->size();
return size_;
}
auto empty() const
{
return size() == 0;
}
auto &at(size_t i) const
{
for (auto *v : c)
{
size_t size_ = v->size();
if (i < size_)
return v->at(i);
i -= size_;
}
debug_assert(false);
throw exceptions::OutOfBounds();
}
auto &operator[](size_t i)
{
return at(i);
}
} ;
} // 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 "Optional.hpp"
namespace std {
template<typename T>
auto logOf(const std::optional<T> &v)
{
return tjp::core::logOfRef(v ? &*v : nullptr);
}
}

14
tjp/core/containers/Optional.h 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
#include <optional>
namespace tjp::core {
template<typename T>
using Optional = std::optional<T>;
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Optional.h"

13
tjp/core/containers/Pack.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif
#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop))
#endif

14
tjp/core/containers/Pair.h 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
#include <utility>
namespace tjp::core {
template<typename A, typename B>
using Pair = std::pair<A, B>;
} // namespace

7
tjp/core/containers/Pair.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Pair.h"

14
tjp/core/containers/PtrOnly.h 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
#include <optional>
namespace tjp::core {
template<typename T>
struct PtrOnly;
} // namespace

59
tjp/core/containers/PtrOnly.hpp Executable file
View File

@@ -0,0 +1,59 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "PtrOrValue.h"
namespace tjp::core {
template<typename T>
struct PtrOnly {
const T *p = nullptr;
const T *get() const {
return p;
}
PtrOnly(const T *p_) :
p(p_)
{}
PtrOnly(const PtrOnly &rhs) :
p(rhs.p)
{}
PtrOnly(PtrOnly &&rhs) :
p(std::move(rhs.p))
{}
auto *operator ->() const
{
return get();
}
const T &operator *() const
{
return *get();
}
operator const T&() const
{
return *get();
}
} ;
template<typename T>
PtrOnly<T> makePtrOnly(const T *t)
{
return PtrOnly<T>(t);
}
template<typename T>
PtrOnly<T> makePtrOnly(const T &t)
{
return PtrOnly<T>(t);
}
} // namespace

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
#include <optional>
namespace tjp::core {
template<typename T>
struct PtrOrValue;
} // namespace

View File

@@ -0,0 +1,70 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "PtrOrValue.h"
namespace tjp::core {
template<typename T>
struct PtrOrValue {
Optional<T> v;
const T *p = nullptr;
const T *get() const {
return v ?
&*v :
p;
}
PtrOrValue(const T &v_) :
v(v_) {}
PtrOrValue(T &&v_) :
v(std::move(v_)) {}
PtrOrValue(const T *p_) :
p(p_)
{}
PtrOrValue(const PtrOrValue &rhs) :
v(rhs.v),
p(rhs.p)
{}
PtrOrValue(PtrOrValue &&rhs) :
v(std::move(rhs.v)),
p(std::move(rhs.p))
{}
auto *operator ->() const
{
return get();
}
const T &operator *() const
{
return *get();
}
operator const T&() const
{
return *get();
}
} ;
template<typename T>
PtrOrValue<T> makePtrOrValue(const T *t)
{
return PtrOrValue<T>(t);
}
template<typename T>
PtrOrValue<T> makePtrOrValue(const T &t)
{
return PtrOrValue<T>(t);
}
} // namespace

16
tjp/core/containers/Queue.h 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
#include <queue>
namespace tjp {
namespace core {
template<typename T>
using Queue = std::queue<T>;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,80 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "List.h"
#include "../threads/Lock.h"
namespace tjp {
namespace core {
// this container is used in asio queue operations -
// where the front is always popped and read from the same thread
// this needs to be worked on, maybe a with_front(F &&f)
template<typename T, typename MutexType = Mutex>
class QueueThreadSafe
{
public:
List<T> queue;
mutable MutexType mutex;
public:
T &front()
{
auto lk = lock_of(mutex);
return queue.front();
}
size_t push_back(const T &t)
{
auto lk = lock_of(mutex);
queue.push_back(t);
return queue.size();
}
size_t push_back(T &&t)
{
auto lk = lock_of(mutex);
queue.emplace_back(std::move(t));
return queue.size();
}
template<typename ... Args>
size_t emplace_back(Args&& ...args)
{
auto lk = lock_of(mutex);
queue.emplace_back(std::forward<Args>(args)...);
return queue.size();
}
size_t pop_front()
{
auto lk = lock_of(mutex);
debug_assert(!queue.empty());
queue.pop_front();
return queue.size();
}
size_t size() const
{
auto lk = lock_of(mutex);
return queue.size();
}
bool empty() const
{
auto lk = lock_of(mutex);
return queue.empty();
}
template<typename F>
auto with(F &&f) {
auto lk = lock_of(mutex);
return f(queue);
}
} ;
} // namespace utilities
} // namespace

17
tjp/core/containers/Reversed.h 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
namespace tjp {
namespace core {
template<typename T>
T reversed (T &&t);
template<typename T>
struct Reversed;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,67 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Reversed.h"
#include <utility>
#include <cstddef>
namespace tjp {
namespace core {
template<typename T>
T reversed (T &&t)
{
T c(std::move(t));
for (auto i=0; i<c.size()/2; ++i)
std::swap(c[i], c[c.size()-(i+1)]);
return c;
}
template<typename T>
struct Reversed : T
{
typedef T Super;
typedef T Unreversed;
template<typename ...U>
Reversed(U&& ...u) : Super(u...)
{}
typedef typename Super::reverse_iterator iterator;
typedef typename Super::iterator reverse_iterator;
typedef typename Super::const_reverse_iterator const_iterator;
typedef typename Super::const_iterator const_reverse_iterator;
auto begin() { return Super::rbegin(); }
auto begin() const { return Super::rbegin(); }
auto end() { return Super::rend(); }
auto end() const { return Super::rend(); }
auto rbegin() { return Super::begin(); }
auto rbegin() const { return Super::begin(); }
auto rend() { return Super::end(); }
auto rend() const { return Super::end(); }
auto &back() { return Super::front(); }
auto &back() const { return Super::front(); }
auto &front() { return Super::back(); }
auto &front() const { return Super::back(); }
auto &operator[](size_t i)
{
return Super::operator[](Super::size()-1-i);
}
auto &operator[] (size_t i) const
{
return Super::operator[](Super::size()-1-i);
}
} ;
} // namespace utilities
} // 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 "SafeIteration.h"
namespace tjp::core {
template<typename IO, typename T>
void io_(IO &io, SafeIteration<T> &t)
{
io.any((T &)t);
}
} // 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 "Vector.h"
#include "FilledArray.h"
namespace tjp {
namespace core {
struct SafeIterationException;
template<class container, class iterator_type, class reference_type, class microsoftfix>
class SafeIterator;
template<typename T>
using SafeIteratorMutable =
SafeIterator<T, typename T::iterator, typename T::reference, char>;
template<typename T>
using SafeIteratorConst =
SafeIterator<T, typename T::const_iterator, typename T::const_reference, int>;
template<typename T, typename CM=FilledArray<SafeIteratorMutable<T> *, 1>>
class SafeIteration;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "SafeIteration_v_all_mutable.hpp"

View File

@@ -0,0 +1,369 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "SafeIteration.h"
#include "FilledArrayThreadSafe.hpp"
#include "../exception/Exception.hpp"
#include "../assert/debug_assert.h"
#include "../algorithm/vector_erase_if_value.hpp"
#include "../threads/Lock.hpp"
#include "../threads/TestMutex.hpp"
#ifdef SAFE_ITERATION_LOG
#include "../log/Log.h"
#include "../log/LogOf.h"
#define xLogDebugSafeIteration(x) xLogDebug(x)
#else
#define xLogDebugSafeIteration(x)
#endif
namespace tjp {
namespace core {
/**
* the only exception the safe iteration templates throw
*/
DECLARE_EXCEPTION (SafeIterationException);
/**
* provides an iterator template which is tightly bound to a safe iteration class
*/
template<class container, class iterator_type, class reference_type, class microsoftfix>
class SafeIterator : public iterator_type
{
friend class SafeIteration<container>;
protected:
const SafeIteration<container> *parent;
bool valid;
protected:
void invalidate ()
{
xLogDebugSafeIteration(logOfThis(this));
valid = false;
iterator_type::operator ++();
}
void invalidate (iterator_type i)
{
xLogDebugSafeIteration(logOfThis(this));
iterator_type::operator =(i);
valid = false;
}
public:
SafeIterator () :
parent (nullptr)
{
xLogDebugSafeIteration(logOfThis(this));
valid = false;
}
SafeIterator (const SafeIteration<container> *parent_, const iterator_type &i) :
iterator_type(i),
parent (parent_)
{
xLogDebugSafeIteration(logOfThis(this));
valid = true;
parent->addSafeIterator (this);
}
SafeIterator(const SafeIterator &rhs) :
iterator_type(rhs)
{
xLogDebugSafeIteration(logOfThis(this));
valid = rhs.valid;
parent = rhs.parent;
parent->addSafeIterator (this);
}
SafeIterator &operator=(const SafeIterator &rhs)
{
xLogDebugSafeIteration(logOfThis(this));
if (this == &rhs)
return *this;
if (parent)
parent->removeSafeIterator(this);
iterator_type::operator=(rhs);
parent = rhs.parent;
valid = rhs.valid;
if (parent)
parent->addSafeIterator(this);
return *this;
}
~SafeIterator ()
{
xLogDebugSafeIteration(logOfThis(this));
if (parent)
parent->removeSafeIterator (this);
}
reference_type operator *() const
{
validate ();
return (reference_type)iterator_type::operator *();
}
SafeIterator<container, iterator_type, reference_type, microsoftfix> &operator ++()
{
xLogDebugSafeIteration(logOfThis(this));
if (valid)
{
iterator_type::operator ++();
}
else
{
valid = true;
};
return *this;
}
SafeIterator<container, iterator_type, reference_type, microsoftfix> &operator --()
{
xLogDebugSafeIteration(logOfThis(this));
iterator_type::operator --();
if (!valid)
{
valid = true;
}
return *this;
}
bool isValid () const
{
return valid;
}
void validate () const
{
if (!valid)
throw SafeIterationException ("invalid iterator dereferenced");
}
} ;
template<typename T>
void safe_iterator_insert(Vector<T *> &v, T *t)
{
v.push_back(t);
}
template<typename T>
void safe_iterator_erase(Vector<T *> &v, T *t)
{
v.erase(
std::remove(
v.begin(), v.end(),
t
),
v.end()
);
}
template<typename T, int N>
void safe_iterator_insert(FilledArray<T *, N> &v, T *t)
{
v.insert(t);
}
template<typename T, int N>
void safe_iterator_erase(FilledArray<T *, N> &v, T *t)
{
v.erase(t);
}
template<typename T, typename CM>
class SafeIteration : public T
{
public:
// static constexpr int FilledArrayInitialSize = 4;
public:
using container_type = T;
using T_iterator = typename T::iterator;
using T_const_iterator = T_iterator ;
using T_reference = typename T::reference;
using T_const_reference = T_reference ;
using safe_iterator = SafeIteratorMutable<T>;
using safe_const_iterator = safe_iterator;
using iterator = safe_iterator;
using const_iterator = safe_const_iterator;
using iterators_container = CM;
//FilledArray<safe_iterator *, FilledArrayInitialSize>;
protected:
mutable iterators_container iterators;
void ensureAllIterators (T_const_reference k)
{
ensureAllIterators (this->find(k));
}
template<class Z>
void ensureIteratorSet (const T_iterator &I, Z &set)
{
for (typename Z::iterator i=set.begin(); i!=set.end(); ++i)
{
if ( (*(*i))!=T::end() )
{
if ( (*(*i)) == I )
{
(*i)->invalidate ();
}
}
}
}
void ensureAllIterators (const T_iterator &I)
{
ensureIteratorSet (I, iterators);
}
template<class Z>
void clearIteratorSet (Z &set)
{
for (typename Z::iterator i=set.begin(); i!=set.end(); ++i)
{
if ( (*(*i))!= T::end() )
{
(*i)->invalidate (T::end());
}
}
}
void clearAllIterators ()
{
clearIteratorSet (iterators);
}
public:
template<typename ... Args>
SafeIteration (Args && ...args) :
T(std::forward<Args>(args)...)
{
xLogDebugSafeIteration(logOfThis(this));
}
SafeIteration (const SafeIteration &copy)
{
xLogDebugSafeIteration(logOfThis(this));
T::operator =(copy);
}
~SafeIteration ()
{
debug_assert(iterators.empty());
}
SafeIteration &operator =(const SafeIteration &copy)
{
xLogDebugSafeIteration(logOfThis(this));
T::operator =(copy);
clearAllIterators();
return *this;
}
inline void erase (const T_const_reference &k)
{
xLogDebugSafeIteration(logOfThis(this));
ensureAllIterators(k);
T::erase(k);
}
inline void erase (const T_iterator &i)
{
xLogDebugSafeIteration(logOfThis(this));
T_iterator I(i);
ensureAllIterators(i);
T::erase(I);
}
inline void clear ()
{
T::clear();
clearAllIterators();
}
auto begin ()
{
xLogDebugSafeIteration(logOfThis(this));
return safe_iterator(this, T::begin());
}
auto begin () const
{
auto this_ = remove_const_of_var(this);
return this_->begin();
}
auto end ()
{
xLogDebugSafeIteration(logOfThis(this));
return safe_iterator(this, T::end());
}
auto end () const
{
auto this_ = remove_const_of_var(this);
return this_->end();
}
template<typename ...U>
void remove(U &&... u)
{
// use erase not remove
debug_assert(false);
}
public:
inline void addSafeIterator (safe_iterator *i) const
{
safe_iterator_insert(iterators, i);
}
inline void removeSafeIterator (safe_iterator *i) const
{
safe_iterator_erase(iterators, i);
}
} ;
} // namespace utilities
} // namespace

View File

@@ -0,0 +1,364 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "SafeIteration.h"
#include "FilledArrayThreadSafe.hpp"
#include "../exception/Exception.hpp"
#include "../assert/debug_assert.h"
#include "../threads/Lock.hpp"
#include "../threads/TestMutex.hpp"
#ifdef SAFE_ITERATION_LOG
#include "../log/Log.h"
#include "../log/LogOf.h"
#define xLogDebugSafeIteration(x) xLogDebug(x)
#else
#define xLogDebugSafeIteration(x)
#endif
namespace tjp {
namespace core {
/**
* the only exception the safe iteration templates throw
*/
DECLARE_EXCEPTION (SafeIterationException);
template<class T> class SafeIteration;
/**
* provides an iterator template which is tightly bound to a safe iteration class
*/
template<class container, class iterator_type, class reference_type, class microsoftfix>
class SafeIterator : public iterator_type
{
friend class SafeIteration<container>;
protected:
const SafeIteration<container> *parent;
bool valid;
protected:
void invalidate ()
{
xLogDebugSafeIteration(logOfThis(this));
valid = false;
iterator_type::operator ++();
}
void invalidate (iterator_type i)
{
xLogDebugSafeIteration(logOfThis(this));
iterator_type::operator =(i);
valid = false;
}
public:
SafeIterator () :
parent (nullptr)
{
xLogDebugSafeIteration(logOfThis(this));
valid = false;
}
SafeIterator (const SafeIteration<container> *parent_, const iterator_type &i) :
iterator_type(i),
parent (parent_)
{
xLogDebugSafeIteration(logOfThis(this));
valid = true;
parent->addSafeIterator (this);
}
SafeIterator(const SafeIterator &rhs) :
iterator_type(rhs)
{
xLogDebugSafeIteration(logOfThis(this));
valid = rhs.valid;
parent = rhs.parent;
parent->addSafeIterator (this);
}
SafeIterator &operator=(const SafeIterator &rhs)
{
xLogDebugSafeIteration(logOfThis(this));
if (this == &rhs)
return *this;
if (parent)
parent->removeSafeIterator(this);
iterator_type::operator=(rhs);
parent = rhs.parent;
valid = rhs.valid;
if (parent)
parent->addSafeIterator(this);
return *this;
}
~SafeIterator ()
{
xLogDebugSafeIteration(logOfThis(this));
if (parent)
parent->removeSafeIterator (this);
}
reference_type operator *() const
{
validate ();
return (reference_type)iterator_type::operator *();
}
SafeIterator<container, iterator_type, reference_type, microsoftfix> &operator ++()
{
xLogDebugSafeIteration(logOfThis(this));
if (valid)
{
iterator_type::operator ++();
}
else
{
valid = true;
};
return *this;
}
SafeIterator<container, iterator_type, reference_type, microsoftfix> &operator --()
{
xLogDebugSafeIteration(logOfThis(this));
iterator_type::operator --();
if (!valid)
{
valid = true;
}
return *this;
}
bool isValid () const
{
return valid;
}
void validate () const
{
if (!valid)
throw SafeIterationException ("invalid iterator dereferenced");
}
} ;
template<typename T>
class SafeIteration : public T
{
public:
static constexpr int FilledArrayInitialSize = 4;
public:
typedef T container_type;
typedef typename T::iterator T_iterator;
typedef typename T::const_iterator T_const_iterator;
typedef typename T::reference T_reference;
typedef typename T::const_reference T_const_reference;
typedef SafeIterator<T, T_iterator, T_reference, char> safe_iterator;
typedef SafeIterator<T, T_const_iterator, T_const_reference, int> safe_const_iterator;
typedef safe_iterator iterator;
typedef safe_const_iterator const_iterator;
using iterators_container = FilledArray<safe_iterator *, FilledArrayInitialSize>;
using const_iterators_container = FilledArray<safe_const_iterator *, FilledArrayInitialSize>;
protected:
mutable iterators_container iterators;
mutable const_iterators_container const_iterators;
void ensureAllIterators (T_const_reference k)
{
ensureAllIterators (this->find(k));
}
template<class Z>
void ensureIteratorSet (const T_iterator &I, Z &set)
{
for (typename Z::iterator i=set.begin(); i!=set.end(); ++i)
{
if ( (*(*i))!=T::end() )
{
if ( (*(*i)) == I )
{
(*i)->invalidate ();
}
}
}
}
void ensureAllIterators (const T_iterator &I)
{
ensureIteratorSet (I, iterators);
ensureIteratorSet (I, const_iterators);
}
template<class Z>
void clearIteratorSet (Z &set)
{
for (typename Z::iterator i=set.begin(); i!=set.end(); ++i)
{
if ( (*(*i))!= T::end() )
{
(*i)->invalidate (T::end());
}
}
}
void clearAllIterators ()
{
clearIteratorSet (iterators);
clearIteratorSet (const_iterators);
}
public:
template<typename ... Args>
SafeIteration (Args && ...args) :
T(std::forward<Args>(args)...)
{
xLogDebugSafeIteration(logOfThis(this));
}
SafeIteration (const SafeIteration &copy)
{
xLogDebugSafeIteration(logOfThis(this));
T::operator =(copy);
}
~SafeIteration ()
{
debug_assert(iterators.empty() && const_iterators.empty());
}
SafeIteration &operator =(const SafeIteration &copy)
{
xLogDebugSafeIteration(logOfThis(this));
T::operator =(copy);
clearAllIterators();
return *this;
}
// SafeIteration &operator =(SafeIteration &&copy)
// {
// xLogDebugSafeIteration(logOfThis(this));
//
// T::operator =(copy);
// clearAllIterators();
//
// return *this;
// }
inline void erase (const T_const_reference &k)
{
xLogDebugSafeIteration(logOfThis(this));
ensureAllIterators(k);
T::erase(k);
}
inline void erase (const T_iterator &i)
{
xLogDebugSafeIteration(logOfThis(this));
T_iterator I(i);
ensureAllIterators(i);
T::erase(I);
}
inline void clear ()
{
T::clear();
clearAllIterators();
}
iterator begin ()
{
xLogDebugSafeIteration(logOfThis(this));
return safe_iterator(this, T::begin());
}
const_iterator begin () const
{
xLogDebugSafeIteration(logOfThis(this));
return const_iterator(this, T::begin());
}
iterator end ()
{
xLogDebugSafeIteration(logOfThis(this));
return safe_iterator(this, T::end());
}
const_iterator end () const
{
xLogDebugSafeIteration(logOfThis(this));
return const_iterator(this, T::end());
}
template<typename ...U>
void remove(U &&... u)
{
// use erase not remove
debug_assert(false);
}
public:
inline void addSafeIterator (safe_iterator *i) const
{
iterators.insert (i);
}
inline void addSafeIterator (safe_const_iterator *i) const
{
const_iterators.insert (i);
}
inline void removeSafeIterator (safe_iterator *i) const
{
iterators.erase (i);
}
inline void removeSafeIterator (safe_const_iterator *i) const
{
const_iterators.erase (i);
}
} ;
} // namespace utilities
} // namespace

17
tjp/core/containers/Set.h 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 <set>
namespace tjp::core {
template<typename V>
using Set = std::set<V>;
template<typename V, typename S>
using SetSortBy = std::set<V, S>;
} // namespace

7
tjp/core/containers/Set.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Set.h"

View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StackArray_v2+IO.hpp"
namespace tjp::core {
using namespace stackarray_v2;
} // 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
#pragma once
#include "StackArray.hpp"
#include "StackArray_v2+hash.hpp"
namespace std {
template<typename T, size_t N>
struct hash<tjp::core::stackarray_v2::StackArray<T, N>> {
using A = tjp::core::stackarray_v2::StackArray<T, N>;
size_t operator()(const A &a) const {
size_t value = 0;
hash<typename A::value_type> hasher;
for (auto &v: a)
{
constexpr auto bitsToShift = 8;
// this is dumb, but we want to protect against x,x always going to zero
value = (
(value << bitsToShift) |
(value >> ((sizeof(value) * 8) - bitsToShift))
);
value = value ^ hasher(v);
}
return value;
}
};
}

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
#include "StackArray_v2.h"
namespace tjp::core {
using namespace stackarray_v2;
} // namespace

View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StackArray_v2.hpp"
namespace tjp::core {
using namespace stackarray_v2;
} // namespace

View File

@@ -0,0 +1,51 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StackArray_v2.hpp"
#include <iostream>
#include "../iterators/is_first.hpp"
#include "../string/trim.h"
#include "../string/split.hpp"
#include "../string/from_string.inl"
namespace tjp::core::stackarray_v2 {
template<typename T, size_t N>
std::ostream &operator<<(std::ostream &out, const StackArray<T, N> &a)
{
std::ostringstream s;
s << "{";
core::is_first first;
for (auto &id : a)
{
if (!first.check())
s << ",";
s << id;
}
s << "}";
out << s.str();
return out;
}
template<typename T, size_t N>
std::istream &operator>>(std::istream &in, StackArray<T, N> &a)
{
std::string s;
in >> s;
s = core::trim_copy(s, " {}");
auto parts = core::split(s, ',');
a.clear();
for (auto &part : parts)
a.push_back(core::from_string<T>(part));
return in;
}
} // namespace

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
#include "StackArray_v2.hpp"
namespace tjp::core::stackarray_v2 {
} // 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 "../types/Types.h"
namespace tjp::core::stackarray_v2 {
/**
* std list and vector and set are too slow for some reason, need fast allocation, with
*/
template<typename T, size_t N=32>
class StackArray;
} // namespace

View File

@@ -0,0 +1,120 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StackArray_v2.h"
#include "InPlaceArray.hpp"
#include "Vector.h"
#include "../debug/Debug.h"
#include "../algorithm/cmp.hpp"
#include <iterator>
#include <variant>
namespace tjp::core::stackarray_v2 {
// this makes random accesses faster, but at a memory pointer
//#define STACK_ARRAY_USE_PTR
template<typename T, size_t N>
class StackArray
{
public:
using Self = StackArray<T, N>;
static constexpr size_t Reserved = N;
using Fixed = InPlaceArray<T, N>;
using Variable = Vector<T>;
using Ptr = T *;
private:
std::variant<Fixed, Variable> v = Fixed();
Fixed &fixed();
const Fixed &fixed() const;
Variable &variable();
const Variable &variable() const;
#ifdef STACK_ARRAY_USE_PTR
Ptr array;
#endif
public:
typedef T value_type;
typedef T *iterator;
typedef const T *const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
inline T *data();
inline const T *data() const;
inline iterator begin();
inline const_iterator begin() const;
inline iterator end ();
inline const_iterator end () const;
inline reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
inline const_reverse_iterator rbegin() const { return std::make_reverse_iterator(end()); }
inline reverse_iterator rend () { return std::make_reverse_iterator(begin()); }
inline const_reverse_iterator rend () const { return std::make_reverse_iterator(begin()); }
inline T &front () { return *begin(); }
inline T &back () { return *(end() - 1); }
inline const T &front () const { return *begin(); }
inline const T &back () const { return *(end() - 1); }
void size_to(size_t newSize);
void changed();
public:
StackArray ();
StackArray (size_t _allocsize);
StackArray(const std::initializer_list<T> &rhs);
StackArray(const T *begin, const T *end);
template<size_t N2>
StackArray(const StackArray<T,N2> &rhs);
template<size_t N2>
StackArray &operator =(const StackArray<T,N2> &rhs);
~StackArray ();
void append(const T *begin, const T *end);
void emplace(const T *begin, const T *end);
void resize(size_t length_, T t=T());
void push_back (const T &element);
void push_back (T &&element);
void pop_back ();
template<typename ... Args>
T &emplace_back (Args&& ...element);
iterator find (const T &element);
const T &at(size_t i) const;
T &at(size_t i);
const T &operator[] (size_t i) const;
T &operator[] (size_t i);
size_t size () const;
void clear ();
bool empty () const;
bool on_stack () const;
} ;
} // namespace
#include "StackArray_v2.inl"

View File

@@ -0,0 +1,411 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "../assert/debug_assert.h"
#include "../algorithm/cmp.hpp"
#include "../log/Log.h"
#include "../log/LogOf.h"
namespace tjp::core::stackarray_v2 {
template<typename T, size_t N>
typename StackArray<T, N>::Fixed &StackArray<T, N>::fixed ()
{
return std::get<Fixed>(v);
}
template<typename T, size_t N>
typename StackArray<T, N>::Variable &StackArray<T, N>::variable ()
{
return std::get<Variable>(v);
}
template<typename T, size_t N>
const typename StackArray<T, N>::Fixed &StackArray<T, N>::fixed () const
{
return std::get<Fixed>(v);
}
template<typename T, size_t N>
const typename StackArray<T, N>::Variable &StackArray<T, N>::variable () const
{
return std::get<Variable>(v);
}
template<typename T, size_t N>
StackArray<T, N>::StackArray ()
#ifdef STACK_ARRAY_USE_PTR
: array(fixed().data())
#endif
{
}
template<typename T, size_t N>
template<size_t N2>
StackArray<T, N>::StackArray(const StackArray<T, N2> &rhs) :
Self()
{
append(rhs.begin(), rhs.end());
}
template<typename T, size_t N>
StackArray<T, N>::StackArray(const T *begin_, const T *end_) :
Self()
{
append(begin_, end_);
}
template<typename T, size_t N>
template<size_t N2>
StackArray<T,N> &StackArray<T, N>::operator =(const StackArray<T,N2> &rhs)
{
if (this == &rhs)
return *this;
clear();
append(rhs.begin(), rhs.end());
return *this;
}
template<typename T, size_t N>
StackArray<T, N>::StackArray(const std::initializer_list<T> &rhs) :
Self()
{
for (auto &element: rhs)
push_back(element);
}
template<typename T, size_t N>
StackArray<T, N>::StackArray (size_t size) :
Self()
{
resize(size);
}
template<typename T, size_t N>
StackArray<T, N>::~StackArray ()
{
}
template<typename T, size_t N>
T * StackArray<T, N>::data()
{
#ifdef STACK_ARRAY_USE_PTR
return array;
#else
return
on_stack() ?
fixed().data() :
variable().data();
#endif
}
template<typename T, size_t N>
const T * StackArray<T, N>::data() const
{
#ifdef STACK_ARRAY_USE_PTR
return array;
#else
return
on_stack() ?
fixed().data() :
variable().data();
#endif
}
template<typename T, size_t N>
typename StackArray<T, N>::iterator StackArray<T, N>::begin()
{
return data();
}
template<typename T, size_t N>
typename StackArray<T, N>::const_iterator StackArray<T, N>::begin() const
{
return data();
}
template<typename T, size_t N>
typename StackArray<T, N>::iterator StackArray<T, N>::end ()
{
return data() + size();
}
template<typename T, size_t N>
typename StackArray<T, N>::const_iterator StackArray<T, N>::end () const
{
return data() + size();
}
template<typename T, size_t N>
void StackArray<T, N>::append(const T *begin, const T *end)
{
size_to(size() + (end - begin));
if (on_stack())
fixed().append(begin, end);
else
variable().insert(variable().end(), begin, end);
changed();
}
template<typename T, size_t N>
void StackArray<T, N>::emplace(const T *begin, const T *end)
{
size_to(size() + (end - begin));
if (on_stack())
fixed().emplace(begin, end);
else
variable().emplace(variable().end(), begin, end);
changed();
}
template<typename T, size_t N>
void StackArray<T, N>::resize(size_t length_, T t)
{
size_to(length_);
if (on_stack())
fixed().resize(length_, t);
else
variable().resize(length_, t);
changed();
}
template<typename T, size_t N>
void StackArray<T, N>::size_to(size_t newSize)
{
if (!on_stack())
return;
// why not reserve before each push_back:
/**
https://en.cppreference.com/w/cpp/container/vector/reserve
Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing the capacity to grow linearly rather than exponentially) and result in increased computational complexity and decreased performance. For example, a function that receives an arbitrary vector by reference and appends elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage characteristics.
**/
if (newSize > N)
{
sLogDebug("core::StackArray::transfer", logVar(newSize) << logVar(N));
Variable variable_;
variable_.reserve(newSize);
auto &fixed_ = fixed();
for (auto &i: fixed_)
variable_.emplace_back(std::move(i));
v = std::move(variable_);
#ifdef STACK_ARRAY_USE_PTR
array = variable().data();
#endif
}
}
template<typename T, size_t N>
void StackArray<T, N>::changed()
{
#ifdef STACK_ARRAY_USE_PTR
if (!on_stack())
array = variable().data();
#endif
}
template<typename T, size_t N>
void StackArray<T, N>::push_back (const T &element)
{
size_to(size()+1);
if (on_stack())
fixed().push_back(element);
else
variable().push_back(element);
changed();
}
template<typename T, size_t N>
void StackArray<T, N>::push_back (T &&element)
{
size_to(size()+1);
if (on_stack())
fixed().push_back(std::move(element));
else
variable().push_back(std::move(element));
changed();
}
template<typename T, size_t N>
template<typename ... Args>
T &StackArray<T, N>::emplace_back (Args&& ...element)
{
size_to(size()+1);
T *r = nullptr;
if (on_stack())
{
auto &i = fixed().emplace_back(std::forward<Args>(element)...);
r = &i;
}
else
{
auto &i = variable().emplace_back(std::forward<Args>(element)...);
r = &i;
}
changed();
return *r;
}
template<typename T, size_t N>
void StackArray<T, N>::pop_back ()
{
if (on_stack())
fixed().pop_back();
else
variable().pop_back();
changed();
}
template<typename T, size_t N>
typename StackArray<T, N>::iterator StackArray<T, N>::find (const T &element)
{
// now iterator all except for what used to be the end element
for (iterator i=begin(); i!=end(); ++i)
{
if (*i == element)
{
// the end element was the last element
return i;
}
}
return end();
}
template<typename T, size_t N>
const T &StackArray<T, N>::at(size_t i) const
{
return data()[i];
}
template<typename T, size_t N>
T &StackArray<T, N>::at(size_t i)
{
return data()[i];
}
template<typename T, size_t N>
const T &StackArray<T, N>::operator[] (size_t i) const
{
return at(i);
}
template<typename T, size_t N>
T &StackArray<T, N>::operator[] (size_t i)
{
return at(i);
}
template<typename T, size_t N>
size_t StackArray<T, N>::size () const
{
return
on_stack() ?
fixed().size() :
variable().size();
}
template<typename T, size_t N>
void StackArray<T, N>::clear ()
{
resize(0);
}
template<typename T, size_t N>
bool StackArray<T, N>::empty () const
{
return size() == 0;
}
template<typename T, size_t N>
bool StackArray<T, N>::on_stack () const
{
return v.index() == 0;
}
template<typename T, size_t N>
int cmp(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
auto lhs_size = lhs.size();
auto rhs_size = rhs.size();
auto max = std::min(lhs_size, rhs_size);
auto *l = lhs.data();
auto *r = rhs.data();
for (auto i=0; i<max; ++i, ++l, ++r)
{
auto v = core::cmp(*l, *r);
if (v != 0)
return v;
}
return core::cmp(lhs_size, rhs_size);
}
template<typename T, size_t N>
bool operator <(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) < 0;
}
template<typename T, size_t N>
bool operator <=(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) <= 0;
}
template<typename T, size_t N>
bool operator >(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) > 0;
}
template<typename T, size_t N>
bool operator >=(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) >= 0;
}
template<typename T, size_t N>
bool operator ==(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) == 0;
}
template<typename T, size_t N>
bool operator !=(const StackArray<T, N> &lhs, const StackArray<T, N> &rhs)
{
return cmp(lhs, rhs) != 0;
}
} // 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
namespace tjp {
namespace core {
struct TransparentLess {
using is_transparent = void;
template <typename T, typename U>
constexpr bool operator()(const T& lhs, const U& rhs) const {
return lhs < rhs;
}
};
} // namespace
} // namespace

14
tjp/core/containers/Tuple.h 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
#include <tuple>
namespace tjp::core {
template<typename ... T>
using Tuple = std::tuple<T...>;
} // namespace

7
tjp/core/containers/Tuple.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Tuple.h"

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
#include <unordered_map>
namespace tjp::core {
template<typename K, typename V>
using UnorderedMap = std::unordered_map<K, V>;
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "UnorderedMap.h"

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
#include <unordered_set>
namespace tjp::core {
template<typename V, typename H>
using UnorderedSet = std::unordered_set<V, H>;
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "UnorderedSet.h"

14
tjp/core/containers/Vector.h 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
#include <vector>
namespace tjp::core {
template<typename V>
using Vector = std::vector<V>;
} // namespace

7
tjp/core/containers/Vector.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Vector.h"

View File

@@ -0,0 +1,187 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/containers/InPlaceArray.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/containers/List.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core::containers {
namespace {
struct E {
int i;
} ;
struct Constructable {
static int constructed;
static int copy_constructed;
static int move_constructed;
static int destructed;
static void clear() {
constructed =
copy_constructed =
move_constructed =
destructed = 0;
}
int i;
Constructable(const Constructable &c)
{
i = c.i+1;
copy_constructed++;
}
Constructable(Constructable &&c)
{
std::swap(i, c.i);
move_constructed++;
}
Constructable ()
{
i = 0;
constructed++;
}
~Constructable()
{
destructed++;
}
} ;
int Constructable::constructed = 0;
int Constructable::copy_constructed = 0;
int Constructable::move_constructed = 0;
int Constructable::destructed = 0;
SCENARIO("core::containers::InPlace" )
{
GIVEN("sizes")
{
using IPA = InPlaceArray<char, 32>;
sLogTest("debug",
logVar(sizeof(IPA))
);
}
GIVEN("a list with X elements")
{
InPlaceArray<E, 20> a;
WHEN("add less than N itesm")
{
for (auto i : range(0, 10))
a.push_back(E{i});
REQUIRE(a.size() == 10);
THEN("arrays elements match")
{
int i=0;
for (auto &v : a)
{
REQUIRE(v.i == i);
i++;
}
}
WHEN("remove some itesm")
{
for (auto _ : range(0, 5))
{
unused(_);
a.pop_back();
}
REQUIRE(a.size() == 5);
THEN("arrays elements match")
{
int i=0;
for (auto &v : a)
{
REQUIRE(v.i == i);
i++;
}
}
WHEN("things are copied")
{
THEN("arrays a elements match")
{
int i=0;
for (auto &v : a)
{
REQUIRE(v.i == i);
i++;
}
}
auto b = a;
REQUIRE(b.size() == 5);
THEN("arrays elements match")
{
int i=0;
for (auto &v : b)
{
REQUIRE(v.i == i);
i++;
}
}
}
}
}
}
GIVEN("a list with X unconstructed constructables")
{
{
Constructable::clear();
InPlaceArray<Constructable, 20> a;
REQUIRE(Constructable::constructed == 0);
REQUIRE(Constructable::destructed == 0);
Constructable c;
a.push_back(std::move(c));
}
REQUIRE(Constructable::constructed == 1);
REQUIRE(Constructable::move_constructed == 1);
REQUIRE(Constructable::destructed == 2);
{
Constructable::clear();
InPlaceArray<Constructable, 20> a;
REQUIRE(Constructable::constructed == 0);
REQUIRE(Constructable::destructed == 0);
Constructable c;
a.push_back(c);
}
REQUIRE(Constructable::constructed == 1);
REQUIRE(Constructable::copy_constructed == 1);
REQUIRE(Constructable::destructed == 2);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,108 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/containers/MultiContainer.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/containers/Vector.hpp>
namespace tjp::core::containers {
namespace {
SCENARIO("core::containers::MultiContainer")
{
GIVEN("a multicontainer")
{
using V = Vector<int>;
MultiContainer<V> c;
V v1, v2, v3;
c.add(&v1);
c.add(&v2);
c.add(&v3);
REQUIRE(c.size() == 0);
auto m = 0;
for (auto &_: c)
{
unused(_);
m++;
}
REQUIRE(m == 0);
auto v1s = 1;
auto v2s = 7;
auto v3s = 15;
v1.resize(v1s);
v2.resize(v2s);
v3.resize(v3s);
auto s = v1s + v2s + v3s;
REQUIRE(c.size() == s);
m = 0;
for (auto &_: c)
{
unused(_);
m++;
}
REQUIRE(m == s);
}
GIVEN("a multicontainer of multicontainer")
{
using V = Vector<int>;
using M = MultiContainer<V>;
using MM = MultiContainer<M>;
M cx0, cx1;
V v1, v2, v3;
cx0.add(&v1);
cx0.add(&v2);
cx1.add(&v3);
MM c(&cx0, &cx1);
auto size = c.size();
REQUIRE(size == 0);
auto m = 0;
for (auto &_: c)
{
unused(_);
m++;
}
REQUIRE(m == 0);
auto v1s = 1;
auto v2s = 7;
auto v3s = 15;
v1.resize(v1s);
v2.resize(v2s);
v3.resize(v3s);
auto s = v1s + v2s + v3s;
REQUIRE(c.size() == s);
m = 0;
for (auto &_: c)
{
unused(_);
m++;
}
REQUIRE(m == s);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,114 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/containers/SafeIteration.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/containers/List.h>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core::containers {
namespace {
SCENARIO("core::containers::SafeIteration")
{
GIVEN("sizes")
{
using LI = List<int>;
using SLI = SafeIteration<List<int>>;
using FA = FilledArray<void *, 4>;
sLogTest("debug",
logVar(sizeof(SLI))
<< logVar(sizeof(SLI::container_type))
<< logVar(sizeof(SLI::iterators_container))
);
}
GIVEN("a list with X elements")
{
SafeIteration<List<int>> l;
l.push_back(0);
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);
WHEN("iterate but my item+1")
{
List<int> r;
for (auto i : l)
{
r.push_back(i);
if (i == 3)
{
l.erase(std::find(l.begin(), l.end(), i+1));
}
}
REQUIRE(r == List<int> { 0, 1, 2, 3, 5 });
}
WHEN("iterate but my item")
{
List<int> r;
for (auto i : l)
{
r.push_back(i);
if (i == 3)
{
l.erase(std::find(l.begin(), l.end(), i));
}
}
REQUIRE(r == List<int> { 0, 1, 2, 3, 4, 5 });
}
WHEN("iterate but remove from front to back")
{
List<int> r;
for (auto i : l)
{
r.push_back(i);
if (i == 3)
{
while (!l.empty())
l.erase(std::find(l.begin(), l.end(), l.front()));
}
}
REQUIRE(r == List<int> { 0, 1, 2, 3 });
}
WHEN("iterate but remove from back to front")
{
List<int> r;
for (auto i : l)
{
r.push_back(i);
if (i == 3)
{
while (!l.empty())
l.erase(std::find(l.begin(), l.end(), l.back()));
}
}
REQUIRE(r == List<int> { 0, 1, 2, 3 });
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,91 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/containers/StackArray_v2.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/iterators/range.hpp>
#include <list>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core::stackarray_v2 {
namespace {
struct E {
int i;
} ;
SCENARIO("core::containers::stackarray_v2" )
{
GIVEN("sizes")
{
using SA32 = StackArray<char,32>;
sLogTest("debug",
logVar(sizeof(SA32))
<< logVar(sizeof(SA32::Fixed))
<< logVar(sizeof(SA32::Variable))
<< logVar(sizeof(SA32::Ptr))
);
}
GIVEN("a list with X elements")
{
StackArray<E> a;
WHEN("add less than N items")
{
for (auto i : range(0, 10))
a.push_back(E{i});
THEN("array is static")
{
REQUIRE(a.on_stack());
}
THEN("arrays elements match")
{
int i=0;
for (auto &v : a)
{
REQUIRE(v.i == i);
i++;
}
}
}
WHEN("add more than N items")
{
for (auto i : range(0, 32))
a.push_back(E{i});
for (auto i : range(32, 128))
a.push_back(E{i});
THEN("array is not static")
{
REQUIRE(!a.on_stack());
}
THEN("arrays elements match")
{
int i=0;
for (auto &v : a)
{
REQUIRE(v.i == i);
i++;
}
}
THEN("item is popped")
{
a.pop_back();
}
}
}
}
} // namespace
} // namespace