flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:39:24 -05:00
commit fa54be052a
315 changed files with 49791 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Extensible+Enumerated.h"
#ifdef _DEBUG
void onExtensibleCacheNew_(void *);
void onExtensibleCache_(void *, size_t);
void onExtensibleCacheDelete_(void *, size_t);
void onExtensibleCacheClear_(void *, size_t);
inline void onExtensibleCacheNew(void *t) { onExtensibleCacheNew_(t); }
inline void onExtensibleCache(void *t, size_t v) { onExtensibleCache_(t, v); }
inline void onExtensibleCacheDelete(void *t, size_t v) { onExtensibleCacheDelete_(t, v); }
inline void onExtensibleCacheClear(void *t, size_t v) { onExtensibleCacheDelete_(t, v); }
#else
inline void onExtensibleCacheNew(void *) {}
inline void onExtensibleCache(void *, size_t) {}
inline void onExtensibleCacheDelete(void *, size_t) {}
inline void onExtensibleCacheClear(void *, size_t) {}
#endif
struct ExtensibleCacheViaArray
{
[[no_unique_address]]
TestMutex mutex;
typedef ExtensionInterface *ExtensionInterfacePtr;
constexpr static size_t REDIRECT_TYPE_BITSIZE = 8;
constexpr static size_t REDIRECTS_PER_BYTE = 8 / REDIRECT_TYPE_BITSIZE;
// leave one left over for the size variable
constexpr static size_t MAX_TYPE = 48 - REDIRECTS_PER_BYTE;
constexpr static size_t REDIRECT_CACHE_BYTE_SIZE = MAX_TYPE / REDIRECTS_PER_BYTE;
constexpr static size_t
MAX_CACHE = (1 << REDIRECT_TYPE_BITSIZE) - 1
- 1; // 0xF is NULL_REDIRECT
constexpr static u8 CACHE_MASK = (1 << REDIRECT_TYPE_BITSIZE) - 1;
constexpr static size_t NULL_REDIRECT = (1 << REDIRECT_TYPE_BITSIZE) - 1;
// using Cache = InPlaceArray<ExtensionInterfacePtr, MAX_CACHE>;
using Cache = StackArray<ExtensionInterfacePtr, 2>;
// using Cache = Vector<ExtensionInterfacePtr>;
Cache cache;
using Redirects = u8[REDIRECT_CACHE_BYTE_SIZE];
Redirects redirect;
ExtensibleCacheViaArray()
{
onExtensibleCacheNew(this);
memset(redirect, CACHE_MASK, REDIRECT_CACHE_BYTE_SIZE);
}
~ExtensibleCacheViaArray()
{
debug_assert(cache.empty());
}
void clear()
{
onExtensibleCacheDelete(this, cache.size());
memset(redirect, 0xFF, REDIRECT_CACHE_BYTE_SIZE);
for (auto p : cache)
delete p;
cache.clear();
}
inline
size_t getRedirect(size_t index)
{
debug_assert(index < MAX_TYPE);
if constexpr(REDIRECTS_PER_BYTE == 1)
{
return redirect[index] ;
}
else
{
auto redirectByte = index / REDIRECTS_PER_BYTE;
auto redirectNibble = index % REDIRECTS_PER_BYTE;
auto redirectShift = redirectNibble * REDIRECT_TYPE_BITSIZE;
auto byte = redirect[redirectByte] >> redirectShift;
return byte & CACHE_MASK;
}
}
inline
void setRedirect(size_t index, u8 value)
{
debug_assert(index < MAX_TYPE);
if constexpr(REDIRECTS_PER_BYTE == 1)
{
redirect[index] = value;
}
else
{
auto redirectByte = index / REDIRECTS_PER_BYTE;
auto redirectNibble = index % REDIRECTS_PER_BYTE;
auto redirectShift = redirectNibble * REDIRECT_TYPE_BITSIZE;
u8 writeBits = 0xF << redirectShift;
u8 keepBits = ~writeBits;
auto &byte = redirect[redirectByte];
byte = (byte & keepBits) | (value << redirectShift);
}
}
template<typename T>
T *find()
{
auto lock = lock_of(mutex);
(void)lock;
auto index = T::getExtensionIndex();
debug_assert(index < MAX_TYPE);
auto redirect = getRedirect(index);
if (redirect == NULL_REDIRECT)
return nullptr;
debug_assert(redirect < MAX_CACHE);
return static_cast<T *>(cache[redirect]);
}
template<typename T>
void insert(T *t)
{
auto lock = lock_of(mutex);
(void)lock;
auto index = T::getExtensionIndex();
debug_assert(index < MAX_TYPE);
auto redirect = getRedirect(index);
if (redirect != NULL_REDIRECT)
{
debug_assert(cache[redirect] == nullptr);
cache[redirect] = t;
return;
}
redirect = cache.size();
cache.push_back(t);
onExtensibleCache(this, cache.size());
debug_assert(redirect < MAX_CACHE);
setRedirect(index, redirect);
debug_assert(redirect < MAX_CACHE);
}
template<typename T>
void erase(T *t)
{
auto lock = lock_of(mutex);
(void)lock;
auto index = T::getExtensionIndex();
debug_assert(index < MAX_TYPE);
auto redirect = getRedirect(index);
if (redirect == NULL_REDIRECT)
return ;
debug_assert(redirect < MAX_CACHE);
cache[redirect] = nullptr;
}
} ;
using ExtensibleCache = ExtensibleCacheViaArray;
template<typename T>
using Extension = ExtensionEnumerated<T>;

View File

@@ -0,0 +1,72 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Extensible+CacheViaMap.h"
#include "Extensible+Enumerated.h"
struct ExtensibleCacheViaArrayAndMap
{
typedef ExtensionInterface *ExtensionInterfacePtr;
constexpr static size_t MAX_CACHE=64;
ExtensionInterfacePtr cache[MAX_CACHE];
ExtensibleCacheViaMap map;
ExtensibleCacheViaArrayAndMap()
{
memset(cache, 0, sizeof(ExtensionInterfacePtr) * MAX_CACHE);
}
~ExtensibleCacheViaArrayAndMap()
{
clear();
}
void clear()
{
auto *begin = &cache[0];
auto *end = begin + MAX_CACHE;
for (auto *p=begin; p!=end; ++p)
{
if (*p)
{
delete *p;
*p = nullptr;
}
}
map.clear();
}
template<typename T>
T *find()
{
auto index = T::getExtensionIndex();
if (index < MAX_CACHE)
return static_cast<T *>(cache[index]);
return map.find<T>();
}
template<typename T>
void insert(T *t)
{
auto index = T::getExtensionIndex();
if (index < MAX_CACHE)
{
cache[index] = t;
}
else
{
debug_assert(false);
map.insert(t);
}
}
} ;
using ExtensibleCache = ExtensibleCacheViaArrayAndMap;
template<typename T>
using Extension = ExtensionEnumerated<T>;

View File

@@ -0,0 +1,51 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Extensible+TypeInfo.h"
struct ExtensibleCacheViaMap
{
typedef ExtensionInterface *ExtensionInterfacePtr;
std::map<std::type_index, ExtensionInterfacePtr> extensions;
~ExtensibleCacheViaMap()
{
clear();
}
void clear()
{
for (auto &kv : extensions)
delete kv.second;
extensions.clear();
}
template<typename T>
T *find()
{
const auto key = type_id<T>();
auto i = extensions.find(key);
if (i == extensions.end())
return nullptr;
return static_cast<T *>(i->second);
}
template<typename T>
void insert(T *t)
{
const auto key = type_id<T>();
debug_assert(extensions.find(key) == extensions.end());
extensions.emplace(key, t);
}
} ;
//using ExtensibleCache = ExtensibleCacheViaMap;
//
//template<typename T>
//using Extension = ExtensionTypeInfo<T>;

View File

@@ -0,0 +1,27 @@
// TJP COPYRIGHT HEADER
#pragma once
template<typename T>
struct ExtensionEnumerated : ExtensionInterface
{
static size_t extension_index;
static size_t getExtensionIndex();
} ;
size_t getNextExtensionIndex();
template<typename T>
size_t ExtensionEnumerated<T>::extension_index = -1;
template<typename T>
size_t ExtensionEnumerated<T>::getExtensionIndex()
{
if (extension_index != -1)
return extension_index;
extension_index = getNextExtensionIndex();
return extension_index;
}

View File

@@ -0,0 +1,7 @@
// TJP COPYRIGHT HEADER
template<typename T>
struct ExtensionTypeInfo : ExtensionInterface
{
} ;

View File

@@ -0,0 +1,67 @@
// TJP COPYRIGHT HEADER
#include "Extensible.h"
#include <atomic>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
std::atomic<size_t> nextExtensionIndex = 0;
size_t getNextExtensionIndex()
{
sLogDebug("core::extensible", logVar(nextExtensionIndex));
return nextExtensionIndex++;
}
constexpr size_t MAX_CACHE_STATISTICS = 64;
static std::array<size_t, MAX_CACHE_STATISTICS+1> numPerSizeCurrent = {0};
static std::array<size_t, MAX_CACHE_STATISTICS+1> numPerSizeTotals = {0};
void onExtensibleCache_(void *t, size_t size)
{
if (size < MAX_CACHE_STATISTICS)
{
if (size > 0)
{
numPerSizeCurrent[size-1]--;
numPerSizeTotals[size-1]--;
}
numPerSizeCurrent[size]++;
numPerSizeTotals[size]++;
}
sLogDebug("core::extensible", "C " << logVar(numPerSizeCurrent));
sLogDebug("core::extensible", "T " << logVar(numPerSizeTotals));
}
void onExtensibleCacheNew_(void *t)
{
onExtensibleCache_(t, 0);
}
void onExtensibleCacheClear_(void *t, size_t size)
{
if (size < MAX_CACHE_STATISTICS)
{
numPerSizeCurrent[size]--;
numPerSizeTotals[size]--;
numPerSizeCurrent[0]++;
numPerSizeTotals[0]++;
}
}
void onExtensibleCacheDelete_(void *t, size_t size)
{
numPerSizeCurrent[size]--;
sLogDebug("core::extensible", "C " << logVar(numPerSizeCurrent));
sLogDebug("core::extensible", "T " << logVar(numPerSizeTotals));
}
} // namespace

View File

@@ -0,0 +1,269 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <map>
#include <string.h>
#include <tjp/core/exception/Exception.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/algorithm/remove_const_of_var.hpp>
#include <tjp/core/types/Types.h>
#include <tjp/core/debug/Debug.h>
#include <tjp/core/containers/InPlaceArray.hpp>
#include <tjp/core/containers/StackArray.hpp>
#include <tjp/core/threads/SpinMutex.hpp>
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/threads/TestMutex.hpp>
#include "ExtensibleWith.h"
namespace tjp::core {
struct ExtensionInterface
{
ExtensionInterface (const ExtensionInterface &) = delete;
ExtensionInterface () {}
virtual ~ExtensionInterface () {}
virtual void initializeExtension() {}
} ;
template<typename T>
void initializeExtension(T *t)
{
t->initializeExtension();
}
//#include "Extensible+CacheViaArrayAndMap.h"
#include "Extensible+CacheViaArray.h"
// -----------------
struct ExtensibleBaseDefault
{
virtual ~ExtensibleBaseDefault () {};
} ;
template<typename B=ExtensibleBaseDefault>
struct Extensor : B
{
typedef B Super;
mutable ExtensibleCache extensions;
Extensor () { }
template<typename ...T>
Extensor(T &&...t) :
B(std::forward<T>(t)...) {}
virtual ~Extensor ()
{
extensions.clear();
}
template<typename U, typename T, typename std::enable_if<std::is_constructible<T, U*>::value>::type* = nullptr>
T &getExtensionTU (U *self) const
{
if (auto extension = extensions.find<T>())
return *extension;
T *t = new T(
static_cast<U *>(self)
);
extensions.insert(t);
initializeExtension(t);
return *t;
}
template<typename U, typename T, typename std::enable_if<!std::is_constructible<T, U*>::value>::type* = nullptr>
T &getExtensionTU (U *self) const
{
if (auto extension = extensions.find<T>())
return *extension;
throw tjp::core::Exception("Extension not available");
}
template<typename U, typename T, typename std::enable_if<std::is_constructible<T, U*>::value>::type* = nullptr>
T &getExtensionU () const
{
if (auto extension = extensions.find<T>())
return *extension;
T *t = new T(
static_cast<U *>(remove_const_of_var(this))
);
extensions.insert(t);
initializeExtension(t);
return *t;
}
template<typename U, typename T, typename std::enable_if<!std::is_constructible<T, U*>::value>::type* = nullptr>
T &getExtensionU () const
{
if (auto extension = extensions.find<T>())
return *extension;
throw tjp::core::Exception("Extension not available");
}
template<typename U, typename T, typename std::enable_if<std::is_constructible<T, U*>::value>::type* = nullptr>
bool hasExtensionU () const
{
return true;
}
template<typename U, typename T, typename std::enable_if<!std::is_constructible<T, U*>::value>::type* = nullptr>
bool hasExtensionU () const
{
return extensions.find<T>();
}
template<typename U, typename T, typename TI, typename ...V>
T &makeExtensionTU (const U *self, V &&...v) const
{
if (auto extension = extensions.find<T>())
return *extension;
T *t = new TI(
static_cast<U *>(remove_const_of_var(self)),
v...
);
extensions.insert(t);
initializeExtension(t);
return *t;
}
template<typename U, typename T, typename TI, typename ...V>
T &makeExtensionU (V &&...v) const
{
if (auto extension = extensions.find<T>())
return *extension;
T *t = new TI(
static_cast<U *>(remove_const_of_var(this)),
v...
);
extensions.insert(t);
initializeExtension(t);
return *t;
}
template<typename U, typename T>
T withExtensionU () const
{
return T(
ExtendingWith {},
static_cast<U *>(remove_const_of_var(this))
);
}
template<typename T>
void eraseExtension ()
{
if (auto extension = extensions.find<T>())
{
extensions.erase(extension);
delete extension;
}
}
};
template<typename P, typename B=ExtensibleBaseDefault>
struct Extensible : Extensor<B>
{
typedef Extensor<B> Extensor_;
typedef Extensible<P,B> Extensible_;
Extensible () {}
template<typename ...T>
Extensible(T &&...t) :
Extensor_(std::forward<T>(t)...) {}
template<typename T>
bool hasExtension () const
{
return this->template hasExtensionU<P, T>();
}
template<typename T>
T &getExtension () const
{
return this->template getExtensionU<P, T>();
}
template<typename T, typename TI, typename ...V>
T &makeExtension (V &&...v) const
{
return this->template makeExtensionU<P, T, TI>(v...);
}
template<typename T, typename ...V>
T &makeExtension (V &&...v) const
{
return this->template makeExtensionU<P, T, T>(v...);
}
template<typename T>
T withExtension () const
{
return this->template withExtensionU<P, T>();
}
} ;
template<typename B, typename U>
struct Extensibled : B
{
typedef B Super;
typedef Extensibled<B, U> Extensible_;
template<typename ...T>
Extensibled(T &&...t) :
B(std::forward<T>(t)...) {}
Extensibled() {}
template<typename T>
T &getExtension () const
{
return this->template getExtensionU<U, T>();
}
template<typename T>
bool hasExtension () const
{
return this->template hasExtensionU<U, T>();
}
template<typename T, typename TI, typename ... V>
T &makeExtension (V &&...v) const
{
return this->template makeExtensionU<U, T, TI>(v...);
}
template<typename T, typename ... V>
T &makeExtension (V &&...v) const
{
return this->template makeExtensionU<U, T, T>(v...);
}
template<typename T>
T withExtension () const
{
return this->template withExtensionU<U, T>();
}
} ;
} // namespace

View File

@@ -0,0 +1,33 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/algorithm/remove_const_of_var.hpp>
namespace tjp::core {
template<typename T>
struct WithExtension {};
struct ExtendingWith {};
template<typename P>
struct ExtensibleWith
{
template<typename U, typename T>
T withExtensionU () const
{
return T(
ExtendingWith {},
static_cast<U *>(remove_const_of_var(this))
);
}
template<typename T>
T withExtension () const
{
return withExtensionU<P, T>();
}
} ;
} // namespace

View File

@@ -0,0 +1,130 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/extensible/Extensible.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
struct A : Extensible<A>
{
int num = 0;
} ;
struct B : Extensibled<A, B>
{
} ;
struct C : Extensibled<B, C>
{
} ;
struct A_Ext : Extension<A_Ext>
{
A_Ext (A *a) { a->num++; }
char val() const { return 'A'; }
} ;
struct B_Ext : Extension<B_Ext>
{
B_Ext (B *b) { b->num++; }
char val() const { return 'B'; }
} ;
struct C_Ext : Extension<C_Ext>
{
C_Ext (C *c) { c->num++; }
char val() const { return 'C'; }
} ;
SCENARIO("extensible")
{
xLogActivateStory("core::extensible");
GIVEN("sizeof")
{
sLogTest("testing", logVar(sizeof(Extensible<A>)) << logVar(sizeof(ExtensibleCache)));
sLogTest("testing", logVar(sizeof(ExtensibleCache::Cache)) << logVar(sizeof(ExtensibleCache::Redirects)));
}
GIVEN("a get extension")
{
A a;
B b;
C c;
auto val = a.getExtension<A_Ext>().val() ;
REQUIRE(val == 'A');
REQUIRE(A_Ext::extension_index == 0);
REQUIRE(b.getExtension<B_Ext>().val() == 'B');
REQUIRE(B_Ext::extension_index == 1);
// REQUIRE(c.getExtension<C_Ext>().val() == 'C');
val = c.getExtension<C_Ext>().val();
REQUIRE(val == 'C');
REQUIRE(C_Ext::extension_index == 2);
REQUIRE(a.num == 1);
REQUIRE(b.num == 1);
REQUIRE(c.num == 1);
val = c.getExtension<A_Ext>().val() ;
REQUIRE(val == 'A');
val = c.getExtension<B_Ext>().val() ;
REQUIRE(val == 'B');
val = c.getExtension<C_Ext>().val() ;
REQUIRE(val == 'C');
val = c.getExtension<A_Ext>().val() ;
REQUIRE(val == 'A');
val = c.getExtension<B_Ext>().val() ;
REQUIRE(val == 'B');
val = c.getExtension<C_Ext>().val() ;
REQUIRE(val == 'C');
REQUIRE(c.num == 3);
}
GIVEN("a make extension")
{
A a;
B b;
C c;
auto val = a.makeExtension<A_Ext>().val() ;
REQUIRE(val == 'A');
REQUIRE(b.makeExtension<B_Ext>().val() == 'B');
REQUIRE(c.makeExtension<C_Ext>().val() == 'C');
val = a.getExtension<A_Ext>().val() ;
REQUIRE(val == 'A');
REQUIRE(a.num == 1);
REQUIRE(b.num == 1);
REQUIRE(c.num == 1);
}
}
} // namespace
} // namespace