xo-reader2 stack: + TypeRegistry
This commit is contained in:
parent
d36f0b7733
commit
0023831e4c
17 changed files with 318 additions and 136 deletions
|
|
@ -169,7 +169,7 @@ namespace xo {
|
||||||
|
|
||||||
/* arbitrary alloc size */
|
/* arbitrary alloc size */
|
||||||
size_t req_z = 13;
|
size_t req_z = 13;
|
||||||
byte * mem = a1o.alloc(typeseq::anon(), req_z);
|
byte * mem = a1o.alloc(typeseq::sentinel(), req_z);
|
||||||
|
|
||||||
REQUIRE(arena.error_count_ == 0);
|
REQUIRE(arena.error_count_ == 0);
|
||||||
REQUIRE(mem != nullptr);
|
REQUIRE(mem != nullptr);
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.allocated() == 0);
|
REQUIRE(a1o.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = 1;
|
size_t z0 = 1;
|
||||||
byte * m0 = a1o.alloc(typeseq::anon(), 1);
|
byte * m0 = a1o.alloc(typeseq::sentinel(), 1);
|
||||||
|
|
||||||
REQUIRE(m0);
|
REQUIRE(m0);
|
||||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||||
|
|
@ -171,7 +171,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.committed() <= a1o.reserved());
|
REQUIRE(a1o.committed() <= a1o.reserved());
|
||||||
|
|
||||||
size_t z1 = 16;
|
size_t z1 = 16;
|
||||||
byte * m1 = a1o.alloc(typeseq::anon(), z1);
|
byte * m1 = a1o.alloc(typeseq::sentinel(), z1);
|
||||||
|
|
||||||
REQUIRE(m1);
|
REQUIRE(m1);
|
||||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||||
|
|
@ -209,7 +209,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.allocated() == 0);
|
REQUIRE(a1o.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = 1;
|
size_t z0 = 1;
|
||||||
byte * m0 = a1o.alloc(typeseq::anon(), 1);
|
byte * m0 = a1o.alloc(typeseq::sentinel(), 1);
|
||||||
|
|
||||||
REQUIRE(m0);
|
REQUIRE(m0);
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.allocated() == 0);
|
REQUIRE(a1o.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = 1;
|
size_t z0 = 1;
|
||||||
byte * m0 = a1o.alloc(typeseq::anon(), 1);
|
byte * m0 = a1o.alloc(typeseq::sentinel(), 1);
|
||||||
|
|
||||||
REQUIRE(m0);
|
REQUIRE(m0);
|
||||||
|
|
||||||
|
|
@ -306,7 +306,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.allocated() == 0);
|
REQUIRE(a1o.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = cfg.hugepage_z_ + 1;
|
size_t z0 = cfg.hugepage_z_ + 1;
|
||||||
byte * m0 = a1o.alloc(typeseq::anon(), z0);
|
byte * m0 = a1o.alloc(typeseq::sentinel(), z0);
|
||||||
|
|
||||||
REQUIRE(!m0);
|
REQUIRE(!m0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace utest {
|
||||||
|
|
||||||
bool ok_flag = true;
|
bool ok_flag = true;
|
||||||
|
|
||||||
std::byte * mem = mm.alloc(typeseq::anon(), z);
|
std::byte * mem = mm.alloc(typeseq::sentinel(), z);
|
||||||
|
|
||||||
log && log(xtag("i_alloc", i_alloc),
|
log && log(xtag("i_alloc", i_alloc),
|
||||||
xtag("si", si),
|
xtag("si", si),
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,10 @@ namespace xo {
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
|
|
||||||
MemorySizeInfo() = default;
|
MemorySizeInfo() = default;
|
||||||
MemorySizeInfo(std::string_view name, std::size_t u, std::size_t a, std::size_t c, std::size_t r)
|
MemorySizeInfo(std::string_view name,
|
||||||
: resource_name_{name}, used_{u}, allocated_{a}, committed_{c}, reserved_{r}
|
std::size_t u, std::size_t a, std::size_t c, std::size_t r)
|
||||||
|
: resource_name_{name},
|
||||||
|
used_{u}, allocated_{a}, committed_{c}, reserved_{r}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static MemorySizeInfo sentinel() { return MemorySizeInfo(); }
|
static MemorySizeInfo sentinel() { return MemorySizeInfo(); }
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace xo {
|
||||||
|
|
||||||
DArena::DArena(const ArenaConfig & cfg)
|
DArena::DArena(const ArenaConfig & cfg)
|
||||||
{
|
{
|
||||||
*this = std::move(map(cfg));
|
*this = map(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
DArena::DArena(const ArenaConfig & cfg,
|
DArena::DArena(const ArenaConfig & cfg,
|
||||||
|
|
@ -290,7 +290,7 @@ namespace xo {
|
||||||
(complete_flag
|
(complete_flag
|
||||||
? alloc_mode::sub_complete
|
? alloc_mode::sub_complete
|
||||||
: alloc_mode::sub_incomplete),
|
: alloc_mode::sub_incomplete),
|
||||||
typeseq::anon() /*typeseq: ignored*/,
|
typeseq::sentinel() /*typeseq: ignored*/,
|
||||||
0 /*age - ignored */);
|
0 /*age - ignored */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ namespace xo {
|
||||||
REQUIRE(arena.allocated() == 0);
|
REQUIRE(arena.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = 1;
|
size_t z0 = 1;
|
||||||
byte * m0 = arena.alloc(typeseq::anon(), 1);
|
byte * m0 = arena.alloc(typeseq::sentinel(), 1);
|
||||||
|
|
||||||
REQUIRE(m0);
|
REQUIRE(m0);
|
||||||
REQUIRE(arena.last_error().error_ == error::ok);
|
REQUIRE(arena.last_error().error_ == error::ok);
|
||||||
|
|
@ -159,7 +159,7 @@ namespace xo {
|
||||||
REQUIRE(arena.committed() <= arena.reserved());
|
REQUIRE(arena.committed() <= arena.reserved());
|
||||||
|
|
||||||
size_t z1 = 16;
|
size_t z1 = 16;
|
||||||
byte * m1 = arena.alloc(typeseq::anon(), z1);
|
byte * m1 = arena.alloc(typeseq::sentinel(), z1);
|
||||||
|
|
||||||
REQUIRE(m1);
|
REQUIRE(m1);
|
||||||
REQUIRE(arena.last_error().error_ == error::ok);
|
REQUIRE(arena.last_error().error_ == error::ok);
|
||||||
|
|
@ -195,7 +195,7 @@ namespace xo {
|
||||||
REQUIRE(arena.allocated() == 0);
|
REQUIRE(arena.allocated() == 0);
|
||||||
|
|
||||||
size_t z0 = 1;
|
size_t z0 = 1;
|
||||||
byte * m0 = arena.alloc(typeseq::anon(), 1);
|
byte * m0 = arena.alloc(typeseq::sentinel(), 1);
|
||||||
|
|
||||||
REQUIRE(m0);
|
REQUIRE(m0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "TypeRegistry.hpp"
|
||||||
#include "facet_implementation.hpp"
|
#include "facet_implementation.hpp"
|
||||||
#include "typeseq.hpp"
|
//#include "typeseq.hpp"
|
||||||
#include "obj.hpp"
|
#include "obj.hpp"
|
||||||
#include <xo/arena/DArenaHashMap.hpp>
|
#include <xo/arena/DArenaHashMap.hpp>
|
||||||
#include <xo/indentlog/scope.hpp>
|
#include <xo/indentlog/scope.hpp>
|
||||||
|
|
@ -74,6 +75,9 @@ namespace xo {
|
||||||
static void register_impl() {
|
static void register_impl() {
|
||||||
static FacetImplType<AFacet, DRepr> impl;
|
static FacetImplType<AFacet, DRepr> impl;
|
||||||
|
|
||||||
|
TypeRegistry::register_type<AFacet>();
|
||||||
|
TypeRegistry::register_type<DRepr>();
|
||||||
|
|
||||||
instance()._register_impl(typeseq::id<AFacet>(),
|
instance()._register_impl(typeseq::id<AFacet>(),
|
||||||
typeseq::id<DRepr>(),
|
typeseq::id<DRepr>(),
|
||||||
&impl);
|
&impl);
|
||||||
|
|
|
||||||
137
xo-facet/include/xo/facet/TypeRegistry.hpp
Normal file
137
xo-facet/include/xo/facet/TypeRegistry.hpp
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
/** @file TypeRegistry.hpp
|
||||||
|
*
|
||||||
|
* @brief Runtime facet implementation lookup
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Jan 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "typeseq.hpp"
|
||||||
|
#include <xo/arena/DArenaVector.hpp>
|
||||||
|
#include <xo/indentlog/scope.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace facet {
|
||||||
|
|
||||||
|
/** @class TypeRegistry
|
||||||
|
*
|
||||||
|
* @brief Runtime registry for types.
|
||||||
|
*
|
||||||
|
* Just assigns ids and remembers names.
|
||||||
|
* Not a full reflection implementation
|
||||||
|
**/
|
||||||
|
class TypeRegistry {
|
||||||
|
public:
|
||||||
|
using ReprType = xo::mm::DArenaVector<typerecd>;
|
||||||
|
using ArenaConfig = xo::mm::ArenaConfig;
|
||||||
|
using MemorySizeVisitor = xo::mm::MemorySizeVisitor;
|
||||||
|
using typeseq = xo::reflect::typeseq;
|
||||||
|
|
||||||
|
/** singleton instance.
|
||||||
|
* @p hint_max_capacity is a lower bound for registry capacity.
|
||||||
|
* Only honored the first time instance is called.
|
||||||
|
**/
|
||||||
|
static TypeRegistry & instance(uint32_t hint_max_capacity = 1024) {
|
||||||
|
static TypeRegistry s_instance(hint_max_capacity);
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Type-safe registration
|
||||||
|
*
|
||||||
|
* Registers the compile-time FacetImplementation<AFacet, DRepr>
|
||||||
|
* for runtime lookup.
|
||||||
|
*
|
||||||
|
* @tparam AFacet abstract facet type
|
||||||
|
* @tparam DRepr data representation type
|
||||||
|
**/
|
||||||
|
template <typename T>
|
||||||
|
static void register_type() {
|
||||||
|
typerecd r = typerecd::recd<T>();
|
||||||
|
|
||||||
|
instance()._register_type(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Number of registered (facet, repr) pairs **/
|
||||||
|
std::size_t size() const { return registry_.size(); }
|
||||||
|
|
||||||
|
std::string_view id2name(typeseq id) const noexcept {
|
||||||
|
return instance()._id2name(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** visit memory pools owned by facet registry **/
|
||||||
|
void visit_pools(const MemorySizeVisitor & visitor) {
|
||||||
|
registry_.visit_pools(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check if type is registered **/
|
||||||
|
bool contains(typeseq id) const
|
||||||
|
{
|
||||||
|
if ((0 <= id.seqno())
|
||||||
|
&& (id.seqno() < static_cast<int32_t>(registry_.size())))
|
||||||
|
{
|
||||||
|
return (registry_.at(id.seqno()).seqno() == id.seqno());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(std::ostream * p_out) const {
|
||||||
|
(*p_out) << std::endl;
|
||||||
|
(*p_out) << "<TypeRegistry" << std::endl;
|
||||||
|
for (const auto & item : registry_) {
|
||||||
|
(*p_out)
|
||||||
|
<< " [" << item.seqno() << "]"
|
||||||
|
<< " -> " << item.name() << std::endl;
|
||||||
|
}
|
||||||
|
(*p_out) << ">" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Register a facet implementation (type-erased)
|
||||||
|
*
|
||||||
|
* @param facet_id typeseq for abstract facet (e.g., APrintable)
|
||||||
|
* @param repr_id typeseq for data representation (e.g., DFloat)
|
||||||
|
* @param impl pointer to stateless implementation instance
|
||||||
|
**/
|
||||||
|
void _register_type(const typerecd & recd)
|
||||||
|
{
|
||||||
|
if ((recd.seqno() >= 0)
|
||||||
|
&& (static_cast<int32_t>(registry_.size()) <= recd.seqno()))
|
||||||
|
{
|
||||||
|
registry_.resize(recd.seqno() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
registry_.at(recd.seqno()) = recd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get typename from @p id.
|
||||||
|
**/
|
||||||
|
std::string_view _id2name(typeseq id) const
|
||||||
|
{
|
||||||
|
if ((0 <= id.seqno())
|
||||||
|
&& (static_cast<std::size_t>(id.seqno()) < registry_.size()))
|
||||||
|
{
|
||||||
|
return registry_.at(id.seqno()).name();
|
||||||
|
}
|
||||||
|
|
||||||
|
return typerecd::sentinel().name();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TypeRegistry(uint32_t hint_max_capacity)
|
||||||
|
: registry_(ReprType::map(ArenaConfig()
|
||||||
|
.with_name("types")
|
||||||
|
.with_size(hint_max_capacity
|
||||||
|
* sizeof(typerecd))))
|
||||||
|
{}
|
||||||
|
|
||||||
|
/** runtime lookup table (AFacet,DRepr) -> impl **/
|
||||||
|
ReprType registry_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*namespace facet*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end TypeRegistry.hpp */
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace facet {
|
namespace facet {
|
||||||
// Re-export from xo::arena namespace
|
// Re-export from xo::arena namespace
|
||||||
using xo::reflect::typeseq_impl;
|
using xo::reflect::typerecd;
|
||||||
using xo::reflect::typeseq;
|
using xo::reflect::typeseq;
|
||||||
}
|
}
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ namespace xo {
|
||||||
DX1Collector::add_gc_root_poly(obj<AGCObject> * p_root) noexcept
|
DX1Collector::add_gc_root_poly(obj<AGCObject> * p_root) noexcept
|
||||||
{
|
{
|
||||||
std::byte * mem
|
std::byte * mem
|
||||||
= roots_.alloc(typeseq::anon(),
|
= roots_.alloc(typeseq::sentinel(),
|
||||||
sizeof(obj<AGCObject>*));
|
sizeof(obj<AGCObject>*));
|
||||||
assert(mem);
|
assert(mem);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ namespace xo {
|
||||||
REQUIRE(a1o.allocated() == 0);
|
REQUIRE(a1o.allocated() == 0);
|
||||||
|
|
||||||
size_t req_z = 13;
|
size_t req_z = 13;
|
||||||
byte * mem = gc.alloc(typeseq::anon(), req_z);
|
byte * mem = gc.alloc(typeseq::sentinel(), req_z);
|
||||||
|
|
||||||
REQUIRE(mem != nullptr);
|
REQUIRE(mem != nullptr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace utest {
|
||||||
|
|
||||||
bool ok_flag = true;
|
bool ok_flag = true;
|
||||||
|
|
||||||
std::byte * mem = mm.alloc(typeseq::anon(), z);
|
std::byte * mem = mm.alloc(typeseq::sentinel(), z);
|
||||||
|
|
||||||
log && log(xtag("i_alloc", i_alloc),
|
log && log(xtag("i_alloc", i_alloc),
|
||||||
xtag("si", si),
|
xtag("si", si),
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace xo {
|
||||||
|
|
||||||
bool log_memory_layout(scope * p_log) {
|
bool log_memory_layout(scope * p_log) {
|
||||||
auto visitor = [p_log](const MemorySizeInfo & info) {
|
auto visitor = [p_log](const MemorySizeInfo & info) {
|
||||||
*p_log && (*p_log)(xtag("resource", info.resource_name_),
|
*p_log && (*p_log)(xtag("name", info.resource_name_),
|
||||||
xtag("used", info.used_),
|
xtag("used", info.used_),
|
||||||
xtag("alloc", info.allocated_),
|
xtag("alloc", info.allocated_),
|
||||||
xtag("commit", info.committed_),
|
xtag("commit", info.committed_),
|
||||||
|
|
|
||||||
|
|
@ -2,91 +2,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <xo/reflectutil/type_name.hpp>
|
||||||
#include <string_view>
|
|
||||||
#include <array> // std::array
|
|
||||||
#include <utility> // std::index_sequence
|
|
||||||
|
|
||||||
namespace xo {
|
|
||||||
namespace reflect {
|
|
||||||
|
|
||||||
template <std::size_t...Idxs>
|
|
||||||
constexpr auto
|
|
||||||
substring_as_array(std::string_view str,
|
|
||||||
std::index_sequence<Idxs...> indexes)
|
|
||||||
{
|
|
||||||
//return std::array<char, indexes.size()+1>{str[Idxs]..., '\n'};
|
|
||||||
return std::array<char, indexes.size()>{str[Idxs]...};
|
|
||||||
} /*substring_as_array*/
|
|
||||||
|
|
||||||
template <typename T> constexpr auto type_name_array() {
|
|
||||||
#if defined(__clang__)
|
|
||||||
constexpr auto prefix = std::string_view{"[T = "};
|
|
||||||
constexpr auto suffix = std::string_view{"]"};
|
|
||||||
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
constexpr auto prefix = std::string_view{"with T = "};
|
|
||||||
constexpr auto suffix = std::string_view{"]"};
|
|
||||||
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
constexpr auto prefix = std::string_view{"type_name_array<"};
|
|
||||||
constexpr auto suffix = std::string_view{">(void)"};
|
|
||||||
constexpr auto function = std::string_view{__FUNCSIG__};
|
|
||||||
#else
|
|
||||||
# error type_name_array: Unsupported compiler
|
|
||||||
#endif
|
|
||||||
|
|
||||||
constexpr auto start = function.find(prefix) + prefix.size();
|
|
||||||
constexpr auto end = function.rfind(suffix);
|
|
||||||
|
|
||||||
//static_assert(start < end);
|
|
||||||
|
|
||||||
constexpr auto name = function.substr(start, (end - start));
|
|
||||||
|
|
||||||
constexpr auto ixseq = std::make_index_sequence<name.size()>{};
|
|
||||||
|
|
||||||
return substring_as_array(name, ixseq);
|
|
||||||
} /*type_name_array*/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct type_name_holder {
|
|
||||||
static inline constexpr auto value = type_name_array<T>();
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr auto type_name() -> std::string_view
|
|
||||||
{
|
|
||||||
constexpr auto& value = type_name_holder<T>::value;
|
|
||||||
return std::string_view{value.data(), value.size()};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NOT_IN_USE
|
|
||||||
template <std::string_view const&... Strs>
|
|
||||||
struct join
|
|
||||||
{
|
|
||||||
// Join all strings into a single std::array of chars
|
|
||||||
static constexpr auto impl() noexcept
|
|
||||||
{
|
|
||||||
constexpr std::size_t len = (Strs.size() + ... + 0);
|
|
||||||
std::array<char, len + 1> arr{};
|
|
||||||
auto append = [i = 0, &arr](auto const& s) mutable {
|
|
||||||
for (auto c : s) arr[i++] = c;
|
|
||||||
};
|
|
||||||
(append(Strs), ...);
|
|
||||||
arr[len] = 0;
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
// Give the joined string static storage
|
|
||||||
static constexpr auto arr = impl();
|
|
||||||
// View as a std::string_view
|
|
||||||
static constexpr std::string_view value {arr.data(), arr.size() - 1};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper to get the value out
|
|
||||||
template <std::string_view const&... Strs>
|
|
||||||
static constexpr auto join_v = join<Strs...>::value;
|
|
||||||
#endif
|
|
||||||
} /*namespace reflect*/
|
|
||||||
} /*namespace xo*/
|
|
||||||
|
|
||||||
/* end demangle.hpp */
|
/* end demangle.hpp */
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,5 @@ xo_install_include_tree3(include/xo/cxxutil)
|
||||||
# NOTE:
|
# NOTE:
|
||||||
# dependency set here must be kept consistent with refcnt/cmake/refcntConfig.cmake.in
|
# dependency set here must be kept consistent with refcnt/cmake/refcntConfig.cmake.in
|
||||||
#
|
#
|
||||||
|
xo_dependency(${SELF_LIB} xo_reflectutil)
|
||||||
xo_dependency(${SELF_LIB} indentlog)
|
xo_dependency(${SELF_LIB} indentlog)
|
||||||
|
|
|
||||||
94
xo-reflectutil/include/xo/reflectutil/type_name.hpp
Normal file
94
xo-reflectutil/include/xo/reflectutil/type_name.hpp
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* @file type_name.hpp */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <array> // std::array
|
||||||
|
#include <utility> // std::index_sequence
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace reflect {
|
||||||
|
|
||||||
|
template <std::size_t...Idxs>
|
||||||
|
constexpr auto
|
||||||
|
substring_as_array(std::string_view str,
|
||||||
|
std::index_sequence<Idxs...> indexes)
|
||||||
|
{
|
||||||
|
//return std::array<char, indexes.size()+1>{str[Idxs]..., '\n'};
|
||||||
|
return std::array<char, indexes.size()>{str[Idxs]...};
|
||||||
|
} /*substring_as_array*/
|
||||||
|
|
||||||
|
template <typename T> constexpr auto type_name_array() {
|
||||||
|
#if defined(__clang__)
|
||||||
|
constexpr auto prefix = std::string_view{"[T = "};
|
||||||
|
constexpr auto suffix = std::string_view{"]"};
|
||||||
|
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
constexpr auto prefix = std::string_view{"with T = "};
|
||||||
|
constexpr auto suffix = std::string_view{"]"};
|
||||||
|
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
constexpr auto prefix = std::string_view{"type_name_array<"};
|
||||||
|
constexpr auto suffix = std::string_view{">(void)"};
|
||||||
|
constexpr auto function = std::string_view{__FUNCSIG__};
|
||||||
|
#else
|
||||||
|
# error type_name_array: Unsupported compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr auto start = function.find(prefix) + prefix.size();
|
||||||
|
constexpr auto end = function.rfind(suffix);
|
||||||
|
|
||||||
|
//static_assert(start < end);
|
||||||
|
|
||||||
|
constexpr auto name = function.substr(start, (end - start));
|
||||||
|
|
||||||
|
constexpr auto ixseq = std::make_index_sequence<name.size()>{};
|
||||||
|
|
||||||
|
return substring_as_array(name, ixseq);
|
||||||
|
} /*type_name_array*/
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_name_holder {
|
||||||
|
static inline constexpr auto value = type_name_array<T>();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** report name of type T as a string_view;
|
||||||
|
* using constexpr deps so runs at **/
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto type_name() -> std::string_view
|
||||||
|
{
|
||||||
|
constexpr auto& value = type_name_holder<T>::value;
|
||||||
|
return std::string_view{value.data(), value.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOT_IN_USE
|
||||||
|
template <std::string_view const&... Strs>
|
||||||
|
struct join
|
||||||
|
{
|
||||||
|
// Join all strings into a single std::array of chars
|
||||||
|
static constexpr auto impl() noexcept
|
||||||
|
{
|
||||||
|
constexpr std::size_t len = (Strs.size() + ... + 0);
|
||||||
|
std::array<char, len + 1> arr{};
|
||||||
|
auto append = [i = 0, &arr](auto const& s) mutable {
|
||||||
|
for (auto c : s) arr[i++] = c;
|
||||||
|
};
|
||||||
|
(append(Strs), ...);
|
||||||
|
arr[len] = 0;
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
// Give the joined string static storage
|
||||||
|
static constexpr auto arr = impl();
|
||||||
|
// View as a std::string_view
|
||||||
|
static constexpr std::string_view value {arr.data(), arr.size() - 1};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to get the value out
|
||||||
|
template <std::string_view const&... Strs>
|
||||||
|
static constexpr auto join_v = join<Strs...>::value;
|
||||||
|
#endif
|
||||||
|
} /*namespace reflect*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end type_name.hpp */
|
||||||
|
|
@ -5,22 +5,20 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "type_name.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace reflect {
|
namespace reflect {
|
||||||
/**
|
// template <typename Tag = class typerecd_tag>
|
||||||
* Tag here so we can preserve header-only implementation
|
struct typerecd {
|
||||||
* and still have static variable
|
/** sentinel value **/
|
||||||
*/
|
typerecd() = default;
|
||||||
template<typename Tag = class typeseq_tag>
|
|
||||||
struct typeseq_impl {
|
|
||||||
/** create sentinel value **/
|
|
||||||
typeseq_impl() = default;
|
|
||||||
|
|
||||||
/** typeseq with specific unique id **/
|
/** type-record with specific, unique id **/
|
||||||
explicit typeseq_impl(int32_t s) : seqno_{s} {}
|
explicit typerecd(int32_t s,
|
||||||
|
std::string_view n) : seqno_{s}, name_{n} {}
|
||||||
|
|
||||||
/** Can't have this be constexpr.
|
/** Can't have this be constexpr.
|
||||||
* We need ids in shared libraries to be generated
|
* We need ids in shared libraries to be generated
|
||||||
|
|
@ -35,57 +33,88 @@ namespace xo {
|
||||||
* when using clang.
|
* when using clang.
|
||||||
**/
|
**/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static typeseq_impl<Tag> id() {
|
static typerecd recd() {
|
||||||
static bool armed = true;
|
// reminder: {armed, id} are distint for each T
|
||||||
|
static bool s_armed = true;
|
||||||
static int32_t id = 0;
|
static int32_t id = 0;
|
||||||
|
|
||||||
if (armed) {
|
if (s_armed) {
|
||||||
armed = false;
|
s_armed = false;
|
||||||
id = ++s_next_id;
|
id = require_next_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeseq_impl(id);
|
return typerecd(id, xo::reflect::type_name<T>());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t require_next_id() {
|
||||||
|
static int32_t s_next_id = 0;
|
||||||
|
return s_next_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t seqno() const { return seqno_; }
|
||||||
|
std::string_view name() const { return name_; }
|
||||||
|
|
||||||
|
/** sentinel typerecd instance **/
|
||||||
|
static typerecd sentinel() {
|
||||||
|
return typerecd(-1, "_%sentinel%_");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t seqno_ = 0;
|
||||||
|
std::string_view name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//template <typename Tag>
|
||||||
|
//int32_t typerecd_impl<Tag>::s_next_id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag here so we can preserve header-only implementation
|
||||||
|
* and still have static variable
|
||||||
|
*/
|
||||||
|
struct typeseq {
|
||||||
|
/** create sentinel value **/
|
||||||
|
typeseq() = default;
|
||||||
|
|
||||||
|
/** typeseq with specific unique id **/
|
||||||
|
explicit typeseq(int32_t s) : seqno_{s} {}
|
||||||
|
|
||||||
/** 'anonymous' sentinel type.
|
/** 'anonymous' sentinel type.
|
||||||
* Niche uses for this, e.g. untyped allocator
|
* Niche uses for this, e.g. untyped allocator
|
||||||
**/
|
**/
|
||||||
static typeseq_impl<Tag> anon() {
|
static typeseq sentinel() {
|
||||||
return typeseq_impl(-1);
|
return typeseq(typerecd::sentinel().seqno());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static typeseq id() {
|
||||||
|
return typeseq(xo::reflect::typerecd::recd<T>().seqno());
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t seqno() const { return seqno_; }
|
int32_t seqno() const { return seqno_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int32_t s_next_id;
|
|
||||||
|
|
||||||
int32_t seqno_ = 0;
|
int32_t seqno_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Tag>
|
//template <typename Tag>
|
||||||
int32_t typeseq_impl<Tag>::s_next_id = 0;
|
//int32_t typeseq_impl<Tag>::s_next_id = 0;
|
||||||
|
|
||||||
template <typename Tag>
|
|
||||||
inline bool
|
inline bool
|
||||||
operator==(const typeseq_impl<Tag> & lhs, const typeseq_impl<Tag> & rhs) {
|
operator==(const typeseq & lhs, const typeseq & rhs) {
|
||||||
return lhs.seqno() == rhs.seqno();
|
return lhs.seqno() == rhs.seqno();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Tag>
|
|
||||||
inline bool
|
inline bool
|
||||||
operator!=(const typeseq_impl<Tag> & lhs, const typeseq_impl<Tag> & rhs) {
|
operator!=(const typeseq & lhs, const typeseq & rhs) {
|
||||||
return lhs.seqno() != rhs.seqno();
|
return lhs.seqno() != rhs.seqno();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Tag>
|
|
||||||
inline std::ostream &
|
inline std::ostream &
|
||||||
operator<<(std::ostream & s, const typeseq_impl<Tag> & x) {
|
operator<<(std::ostream & s, const typeseq & x) {
|
||||||
s << x.seqno();
|
s << x.seqno();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
using typeseq = typeseq_impl<>;
|
|
||||||
} /*namespace reflect*/
|
} /*namespace reflect*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue