flatten 20260225
This commit is contained in:
165
tjp/core/rtti/RTTI+custom.hpp
Executable file
165
tjp/core/rtti/RTTI+custom.hpp
Executable 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
48
tjp/core/rtti/RTTI+std.hpp
Executable 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
162
tjp/core/rtti/RTTI.cpp
Executable 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
20
tjp/core/rtti/RTTI.hpp
Executable 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
139
tjp/core/rtti/TypeName+custom.hpp
Executable 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
38
tjp/core/rtti/TypeName.hpp
Executable 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
382
tjp/core/rtti/_tests/All.cxx
Executable 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();
|
||||
}
|
||||
77
tjp/core/rtti/_tests/TypeName.cpp
Executable file
77
tjp/core/rtti/_tests/TypeName.cpp
Executable 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
|
||||
Reference in New Issue
Block a user