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

165
tjp/core/rtti/RTTI+custom.hpp Executable file
View File

@@ -0,0 +1,165 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "TypeName.hpp"
#include "../types/Definitions.h"
#include "../const_hash/Hash.hpp"
#include <type_traits>
#include <iostream>
namespace tjp::core::rtti {
using type_index_v = u32;
struct type_index {
type_index_v v;
const char *name() const { return "[name]"; }
} ;
inline
constexpr bool operator <(const type_index &lhs, const type_index &rhs)
{
return lhs.v < rhs.v;
}
inline
constexpr bool operator ==(const type_index &lhs, const type_index &rhs)
{
return lhs.v == rhs.v;
}
inline
constexpr bool operator !=(const type_index &lhs, const type_index &rhs)
{
return lhs.v != rhs.v;
}
#define ENABLE_RTTI_CLASS \
tjp::core::rtti::type_index _static_type_id_() const { return tjp::core::rtti::type_id(*this); }
#define ENABLE_RTTI_GET_BASE \
virtual tjp::core::rtti::type_index _type_() { return _static_type_id_(); }
#define ENABLE_RTTI_GET_OVERRIDE(BASE) \
tjp::core::rtti::type_index _type_() override { return _static_type_id_(); }
#define ENABLE_RTTI_IS_BASE \
virtual bool _is_(tjp::core::rtti::type_index v) { return _static_type_id_() == v; }
#define ENABLE_RTTI_IS_OVERRIDE(BASE) \
bool _is_(tjp::core::rtti::type_index v) override { \
return _static_type_id_() == v || BASE::_is_(v); \
} \
#define ENABLE_RTTI_BASE \
ENABLE_RTTI_CLASS \
ENABLE_RTTI_GET_BASE \
ENABLE_RTTI_IS_BASE \
#define ENABLE_RTTI(BASE) \
ENABLE_RTTI_CLASS \
ENABLE_RTTI_GET_OVERRIDE(BASE) \
ENABLE_RTTI_IS_OVERRIDE(BASE) \
#define RTTI_TYPE_FOR_STRING(x) tjp::core::hash_compile<type_index_v>(x)
template<typename T>
constexpr auto type_id_name()
{
return type_name<T>();
}
constexpr
type_index type_id_using(const std::string_view &s)
{
auto v = RTTI_TYPE_FOR_STRING(s);
return { v };
}
template<typename T>
constexpr type_index type_id()
{
constexpr auto name = type_id_name<T>();
constexpr auto v = RTTI_TYPE_FOR_STRING(name);
return {v};
}
template<typename T>
type_index type_id(const T &t)
{
return type_id<T>();
}
template <typename Container>
using pushback_t = decltype(std::declval<Container>()._is_(type_index{}));
template <typename Container, typename = std::void_t<>>
struct has_rtti_method : std::false_type{};
template <typename Container>
struct has_rtti_method<Container, std::void_t<pushback_t<Container>>>:
std::true_type{};
//template <class T, typename U = void>
//struct has_rtti_method: public std::false_type {};
//
//template <class T>
//struct has_rtti_method<T, std::enable_if<std::is_samedecltype(T::_static_type_id_)>> : public std::true_type {};
template<typename T, typename std::enable_if<!has_rtti_method<T>::value, T>::type* = nullptr>
constexpr bool is_type(T *t, const type_index type)
{
return type_id<T>() == type;
}
template<typename T, typename std::enable_if<has_rtti_method<T>::value, T>::type* = nullptr>
bool is_type(T *t, const type_index type)
{
if (type_id<T>() == type)
return true;
return t && t->_is_(type);
}
template<typename T, typename U>
bool is_type(U *u)
{
return is_type(u, type_id<T>());
}
template<typename T, typename U>
T *static_cast_ptr(U *u)
{
return static_cast<T *>(u);
}
template<typename T, typename U, typename std::enable_if<!has_rtti_method<U>::value, U>::type* = nullptr>
constexpr T *dynamic_cast_ptr(U *u)
{
if constexpr(type_id<T>() == type_id<U>())
return u;
return nullptr;
}
template<typename T, typename U, typename std::enable_if<has_rtti_method<U>::value, U>::type* = nullptr>
T *dynamic_cast_ptr(U *u)
{
if constexpr(type_id<T>() == type_id<U>())
return u;
if (is_type<T>(u))
return static_cast<T *>(u);
return nullptr;
}
} // namespace

48
tjp/core/rtti/RTTI+std.hpp Executable file
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
#pragma once
#include <typeindex>
namespace tjp::core {
namespace rtti {
#define ENABLE_RTTI_BASE
#define ENABLE_RTTI(BASE)
using type_index = std::type_index;
template<typename T>
type_index type_id(const T &t)
{
return typeid(T);
}
template<typename T>
type_index type_id()
{
return typeid(T);
}
template<typename T, typename U>
bool is_type(U *u)
{
return dynamic_cast<T *>(u) != nullptr;
}
template<typename T, typename U>
T *static_cast_ptr(U *u)
{
return static_cast<T *>(u);
}
template<typename T, typename U>
T *dynamic_cast_ptr(U *u)
{
return dynamic_cast<T *>(u);
}
} // namespace
} // namespace

162
tjp/core/rtti/RTTI.cpp Executable file
View File

@@ -0,0 +1,162 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "RTTI.hpp"
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core::rtti {
namespace {
struct A {
ENABLE_RTTI_BASE;
} ;
struct B : A {
ENABLE_RTTI(A);
} ;
struct C_different_base {
ENABLE_RTTI_BASE;
} ;
//struct D_no_inherit_shouldn_t_compile {
// ENABLE_RTTI(A);
//} ;
struct E : A {
ENABLE_RTTI(A);
} ;
struct B_A : B {
ENABLE_RTTI(B);
} ;
struct X0 {};
struct X1 {};
SCENARIO("core::rtti")
{
GIVEN("some structures")
{
A a_;
B b_;
C_different_base c_;
// D_no_inherit d_;
B_A b_a_;
auto *a = &a_;
unused(a);
auto *b = &b_;
unused(a);
auto *c = &c_;
unused(c);
// auto *d = &d_;
auto *b_a = &b_a_;
static_assert(has_rtti_method<int>::value == false);
static_assert(has_rtti_method<A>::value == true);
sLogTest("testing",
logVar(type_id<A>().v)
<< logVar(type_id<B>().v)
<< logVar(type_id<C_different_base>().v)
// << logVar(type_id<D>().v)
<< logVar(type_id<E>().v)
<< logVar(type_id<B_A>().v)
);
sLogTest("testing",
logVar(has_rtti_method<int>::value)
<< logVar(has_rtti_method<A>::value)
<< logVar(has_rtti_method<B>::value)
<< logVar(has_rtti_method<C_different_base>::value)
// << logVar(has_rtti_method<D>::value)
<< logVar(has_rtti_method<E>::value)
<< logVar(has_rtti_method<B_A>::value)
);
{
auto cast_a = dynamic_cast_ptr<A>(b);
auto cast_b = dynamic_cast_ptr<B>(cast_a);
REQUIRE(cast_b == b);
}
{
auto cast_a = dynamic_cast_ptr<A>(b);
auto cast_e = dynamic_cast_ptr<E>(cast_a);
REQUIRE(cast_e == nullptr);
}
{
auto cast_a = dynamic_cast_ptr<A>(b_a);
auto cast_b = dynamic_cast_ptr<B>(cast_a);
REQUIRE(cast_b == b_a);
auto cast_b_a = dynamic_cast_ptr<B_A>(cast_a);
REQUIRE(cast_b_a == b_a);
auto cast_b_a_2 = dynamic_cast_ptr<B_A>(cast_b);
REQUIRE(cast_b_a_2 == b_a);
}
}
GIVEN("some datatypes")
{
int i_;
char c_;
float f_;
X0 x0_;
X1 x1_;
auto *i = &i_;
auto *c = &c_;
unused(c);
auto *f = &f_;
auto *x0 = &x0_;
auto *x1 = &x1_;
unused(x1);
{
auto x = dynamic_cast_ptr<char>(i);
REQUIRE(x == nullptr);
auto y = dynamic_cast_ptr<int>(i);
REQUIRE(y == i);
}
{
auto x = dynamic_cast_ptr<char>(f);
REQUIRE(x == nullptr);
auto y = dynamic_cast_ptr<float>(f);
REQUIRE(y == f);
}
{
auto x = dynamic_cast_ptr<X1>(x0);
REQUIRE(x == nullptr);
auto y = dynamic_cast_ptr<X0>(x0);
REQUIRE(y == x0);
}
}
}
} // namespace
} // namespace

20
tjp/core/rtti/RTTI.hpp Executable file
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
#ifdef __GXX_RTTI
#include "RTTI+std.hpp"
#else
#include "RTTI+custom.hpp"
#endif
namespace tjp::core {
using rtti::static_cast_ptr;
using rtti::dynamic_cast_ptr;
using rtti::type_id;
using rtti::type_index;
} // namespace

139
tjp/core/rtti/TypeName+custom.hpp Executable file
View File

@@ -0,0 +1,139 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <cstddef>
#include <string_view>
#include "../const_expr/Str.hpp"
#include "../const_expr/count_char.hpp"
#include "../const_expr/remove_char.hpp"
#include "../const_expr/length.hpp"
namespace tjp::core::rtti {
// basis:
// https://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template/59522794#59522794
// https://stackoverflow.com/posts/59522794/revisions
namespace impl
{
using const_expr::Str;
using const_expr::StrView;
template <typename T>
constexpr const auto &RawTypeName_()
{
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
template <typename T>
constexpr const auto RawTypeName()
{
constexpr auto &s = RawTypeName_<T>();
constexpr auto n = const_expr::length(s);
return Str<n>(s);
}
struct RawTypeNameFormat
{
std::size_t leading_junk = 0, trailing_junk = 0;
};
// Returns `false` on failure.
inline constexpr bool GetRawTypeNameFormat(RawTypeNameFormat *format)
{
const auto &str = RawTypeName_<int>();
const auto length = const_expr::length(str);
for (std::size_t i = 0;; i++)
{
if (str[i] == 'i' && str[i+1] == 'n' && str[i+2] == 't')
{
if (format)
{
format->leading_junk = i;
format->trailing_junk = length-i-3; // `3` is the length of "int"
}
return true;
}
}
return false;
}
inline static constexpr RawTypeNameFormat format =
[]{
static_assert(GetRawTypeNameFormat(nullptr), "Unable to figure out how to generate type names on this compiler.");
RawTypeNameFormat format;
GetRawTypeNameFormat(&format);
return format;
}();
} // namespace
template <typename T>
[[nodiscard]] constexpr auto type_name_()
{
constexpr std::size_t length =
const_expr::length(impl::RawTypeName_<T>())
- impl::format.leading_junk
- impl::format.trailing_junk;
constexpr const auto &name = impl::RawTypeName_<T>();
return std::string_view {
&name[impl::format.leading_junk],
length
};
}
template <typename T>
[[nodiscard]] constexpr auto type_name_custom(const T *)
{
return type_name_<T>();
}
template <typename T>
[[nodiscard]] constexpr auto type_name_dispatch(const T *t)
{
return type_name_custom(t);
}
template <typename T>
[[nodiscard]] constexpr auto type_name()
{
constexpr auto name = type_name_dispatch((T *)nullptr);
// on some compilers, there is weirdness at the end of template names
constexpr auto numSpaces = const_expr::count_char(name, "> ");
constexpr int size = name.size() - numSpaces;
const_expr::Str<size> result;
const_expr::remove_second_of_char_2(name, result, "> ");
return result;
}
template <>
[[nodiscard]] constexpr auto type_name<void>()
{
return type_name_<void>();
}
template <typename T>
[[nodiscard]] constexpr auto type_unique_label_stringview()
{
return type_name_dispatch((T *)nullptr);
}
} // namespace

38
tjp/core/rtti/TypeName.hpp Executable file
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
#ifdef __GXX_RTTI
#include "TypeName+custom.hpp"
// #include "TypeName+std.hpp"
#else
#include "TypeName+custom.hpp"
#endif
namespace tjp::core {
using rtti::type_name;
using rtti::type_unique_label_stringview;
} // namespace
#define TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, replace_with) \
[[nodiscard]] constexpr auto type_name_custom(const type_to_replace *) \
{ \
return std::string_view(replace_with); \
} \
#define TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME(type_to_replace) \
TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, #type_to_replace)
#define TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME_WITH(type_to_replace, replace_with) \
namespace tjp::core::rtti { \
template<> \
TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, replace_with) \
} \
#define TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(type_to_replace) \
TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME_WITH(type_to_replace, #type_to_replace)

382
tjp/core/rtti/_tests/All.cxx Executable file
View File

@@ -0,0 +1,382 @@
// https://godbolt.org/
// to test compilers
#include <stddef.h>
#include <string_view>
#include <array>
namespace tjp::core::const_expr {
struct StrView {
char *v;
size_t len;
constexpr StrView(char *v_, size_t len_) :
v(v_), len(len_)
{}
constexpr StrView(const char *v_, size_t len_) :
v(const_cast<char *>(v_)), len(len_)
{}
constexpr StrView(const std::string_view &v_) :
v((char *)v_.data()), len(v_.size())
{}
constexpr auto *data() { return v; }
constexpr auto *begin() const { return v; }
constexpr auto *end() const { return begin() + size(); }
constexpr auto *begin() { return v; }
constexpr auto *end() { return begin() + size(); }
constexpr size_t size() { return len; }
constexpr const size_t size() const { return len; }
constexpr void set(const size_t i, const char c) { v[i] = c; }
constexpr char operator[](const size_t i) const { return v[i]; }
constexpr operator std::string_view() const
{
return std::string_view(v, len);
}
} ;
template<size_t N>
struct Str {
char v[N];
constexpr Str(const char *s) :
v{0}
{
for (auto i=0; i<N; ++i)
v[i] = s[i];
}
constexpr Str() : v{0}
{
}
constexpr auto *data() const { return v; }
constexpr auto *begin() const { return &v[0]; }
constexpr auto *end() const { return begin() + size(); }
constexpr auto *begin() { return &v[0]; }
constexpr auto *end() { return begin() + size(); }
constexpr size_t size() const { return N; }
constexpr void set(const size_t i, const char c) { v[i] = c; }
constexpr char operator[](const size_t i) const { return v[i]; }
constexpr operator std::string_view() const
{
return std::string_view(begin(), size());
}
constexpr operator StrView()
{
return StrView(begin(), size());
}
constexpr operator const StrView() const
{
return StrView((char *)begin(), size());
}
} ;
template<size_t N>
constexpr bool operator ==(const Str<N> &lhs, const char *rhs)
{
return (std::string_view)lhs == rhs;
}
} // namespace
#include <iostream>
namespace tjp::core::const_expr {
template<size_t N>
std::ostream &operator <<(std::ostream &o, const Str<N> &v)
{
return o << (std::string_view)(v);
}
inline
std::ostream &operator <<(std::ostream &o, const StrView &v)
{
return o << (std::string_view)(v);
}
} // namespace
namespace tjp::core::const_expr {
[[nodiscard]]
inline constexpr auto count_char(const StrView &s, const char v)
{
size_t num = 0;
for (auto &c : s)
{
if (c == v)
++num;
}
return num;
}
[[nodiscard]]
inline constexpr auto count_char(const StrView &s, const char v[2])
{
size_t num = 0;
for (auto i=0; i<s.size()-1; ++i)
{
if (s[i] == v[0] && s[i+1] == v[1])
++num;
}
return num;
}
} // namespace
namespace tjp::core::const_expr {
[[nodiscard]]
inline constexpr auto remove_char(const StrView &s, StrView result, const char v)
{
int i = 0;
for (auto &c : s)
{
if (c != v)
result.set(i++, c);
}
}
[[nodiscard]]
inline constexpr auto remove_char(const StrView &s, StrView result, const char v[2])
{
if (result.size() == 0)
return;
int r = 0;
result.set(r++, s[0]);
for (auto i=0; i<s.size()-1; ++i)
{
if (s[i] == v[0] && s[i+1] == v[1])
continue;
result.set(r++, s[i+1]);
}
}
} // namespace
namespace tjp::core::const_expr {
[[nodiscard]]
inline constexpr auto length(const char *s)
{
size_t size = 0;
while (*s++)
size++;
return size;
}
} // namespace
#include <string_view>
namespace tjp::core::rtti {
// https://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template/59522794#59522794
// https://stackoverflow.com/posts/59522794/revisions
namespace impl
{
using const_expr::Str;
using const_expr::StrView;
template <typename T>
constexpr const auto &RawTypeName_()
{
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
template <typename T>
constexpr const auto RawTypeName()
{
constexpr auto &s = RawTypeName_<T>();
constexpr auto n = const_expr::length(s);
return Str<n>(s);
}
struct RawTypeNameFormat
{
std::size_t leading_junk = 0, trailing_junk = 0;
};
// Returns `false` on failure.
inline constexpr bool GetRawTypeNameFormat(RawTypeNameFormat *format)
{
const auto &str = RawTypeName_<int>();
const auto length = const_expr::length(str);
for (std::size_t i = 0;; i++)
{
if (str[i] == 'i' && str[i+1] == 'n' && str[i+2] == 't')
{
if (format)
{
format->leading_junk = i;
format->trailing_junk = length-i-3; // `3` is the length of "int"
}
return true;
}
}
return false;
}
inline static constexpr RawTypeNameFormat format =
[]{
static_assert(GetRawTypeNameFormat(nullptr), "Unable to figure out how to generate type names on this compiler.");
RawTypeNameFormat format;
GetRawTypeNameFormat(&format);
return format;
}();
} // namespace
template <typename T>
[[nodiscard]] constexpr auto type_name_()
{
constexpr std::size_t length =
const_expr::length(impl::RawTypeName_<T>())
- impl::format.leading_junk
- impl::format.trailing_junk;
constexpr const auto &name = impl::RawTypeName_<T>();
return std::string_view {
&name[impl::format.leading_junk],
length
};
}
template <typename T>
[[nodiscard]] constexpr auto type_name_custom(const T *)
{
return type_name_<T>();
}
template <typename T>
[[nodiscard]] constexpr auto type_name_dispatch(const T *t)
{
return type_name_custom(t);
}
template <typename T>
[[nodiscard]] constexpr auto type_name()
{
constexpr auto name = type_name_dispatch((T *)nullptr);
constexpr auto numSpaces = const_expr::count_char(name, "> ");
constexpr int size = name.size() - numSpaces;
const_expr::Str<size> result;
const_expr::remove_char(name, result, "> ");
return result;
}
template <>
[[nodiscard]] constexpr auto type_name<void>()
{
return type_name_<void>();
}
} // namespace
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
namespace tjp::core::rtti {
[[nodiscard]] inline constexpr auto type_id_for(const std::string_view &s)
{
int type = 0;
for (auto &c : s)
type += (int)c;
return type;
}
template<size_t N>
[[nodiscard]] inline constexpr auto type_id_for(const std::array<char, N> &s)
{
int type = 0;
for (auto &c: s)
type += (int)c;
return type;
}
template<typename T>
[[nodiscard]] constexpr auto type_id()
{
constexpr auto name = type_name<T>();
return type_id_for(name);
}
} // namespace
#include <map>
#include <memory>
namespace tjp::core::rtti {
struct Y;
template<typename T>
struct X {};
using XY = X<Y>;
template<typename T>
struct XX {};
using XXY = XX<X<Y>>;
template<typename T>
struct XXX {};
using XXXY = XXX<XX<X<Y>>>;
using MXY = std::map<X<Y>, XXY>;
using SMX = std::shared_ptr<MXY>;
inline void run()
{
std::cout << "before" << std::endl;
std::cout << "[" << impl::RawTypeName<int>() << "]" << std::endl;
std::cout << "[" <<impl::RawTypeName<XXXY>() << "]" << std::endl;
std::cout << "[" <<type_name<int>() << "]" << std::endl;
std::cout << "[" <<type_name<XXXY>() << "]" << std::endl;
std::cout << "[" <<type_id<XXXY>() << "]" << std::endl;
std::cout << "[" <<type_name<MXY>() << "]" << std::endl;
std::cout << "[" <<type_name<SMX>() << "]" << std::endl;
std::cout << "after" << std::endl;
}
} // namespcae
int main(int argc, char *arv[])
{
tjp::core::rtti::run();
}

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/rtti/TypeName.hpp>
#include <tjp/core/rtti/RTTI.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <tjp/core/string/Str.hpp>
namespace tjp::core::rtti {
namespace {
struct A {
ENABLE_RTTI_BASE;
} ;
struct B : A {
ENABLE_RTTI(A);
} ;
struct C_different_base {
ENABLE_RTTI_BASE;
} ;
//struct D_no_inherit_shouldn_t_compile {
// ENABLE_RTTI(A);
//} ;
struct E : A {
ENABLE_RTTI(A);
} ;
struct B_A : B {
ENABLE_RTTI(B);
} ;
struct X0 {};
struct X1 {};
template<typename T>
struct Z {};
TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME(Z<X0>);
SCENARIO("core::rtti::type_name")
{
GIVEN("some structures")
{
sLogDebug("testing",
logVar(type_name<A>())
<< logVar(type_name<B>())
<< logVar(type_name<C_different_base>())
// << logVar(type_id<D>().v)
<< logVar(type_name<E>())
<< logVar(type_name<B_A>())
<< logVar(type_name<int>())
<< logVar(type_name<char>())
<< logVar(type_name<float>())
<< logVar(type_name<const char *>())
<< logVar(type_name<Z<X0>>())
<< logVar(type_name<Z<X1>>())
<< logVar(type_name<Str>())
);
static_assert(type_name<Str>() == "tjp::core::Str");
static_assert(type_name<Z<X0>>() == "Z<X0>");
static_assert(!(type_name<Z<X1>>() == "Z<X1>"));
}
}
} // namespace
} // namespace