From eee54530ff9676c419148b9e6b9746ee5cf8d515 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 3 Dec 2025 00:14:09 -0500 Subject: [PATCH 1/6] fix unit tests to build on osx / clang16 --- include/xo/reflectutil/reflect_struct_info.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/xo/reflectutil/reflect_struct_info.hpp b/include/xo/reflectutil/reflect_struct_info.hpp index 98313088..60c52392 100644 --- a/include/xo/reflectutil/reflect_struct_info.hpp +++ b/include/xo/reflectutil/reflect_struct_info.hpp @@ -6,6 +6,7 @@ #pragma once #include +#include namespace xo { namespace reflect { From 412697bbb875fcbb7d4f5bffa1d7f74a283b28cf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:49:33 -0500 Subject: [PATCH 2/6] refactor: move xo::facet::typeseq to xo-reflectutil/ prep for adding xo-arena/ --- CMakeLists.txt | 2 +- cmake/xo_reflectutilConfig.cmake.in | 7 +-- include/xo/reflectutil/typeseq.hpp | 88 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 include/xo/reflectutil/typeseq.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a231f5dc..4f3f6dee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets # ---------------------------------------------------------------- # dependencies -xo_headeronly_dependency(${SELF_LIB} xo_flatstring) +#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) #xo_headeronly_dependency(${SELF_LIB} randomgen) # etc.. diff --git a/cmake/xo_reflectutilConfig.cmake.in b/cmake/xo_reflectutilConfig.cmake.in index b7a5a0a2..26df0fc7 100644 --- a/cmake/xo_reflectutilConfig.cmake.in +++ b/cmake/xo_reflectutilConfig.cmake.in @@ -6,12 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in xo-reactor/src/reactor/CMakeLists.txt # -find_dependency(xo_flatstring) -#find_dependency(subsys) -#find_dependency(Eigen3) -#find_dependency(webutil) -#find_dependency(printjson) -#find_dependency(callback) +#find_dependency(xo_flatstring) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp new file mode 100644 index 00000000..dd0b869a --- /dev/null +++ b/include/xo/reflectutil/typeseq.hpp @@ -0,0 +1,88 @@ +/** @file typeseq.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace reflect { + /** + * Tag here so we can preserve header-only implementation + * and still have static variable + */ + template + struct typeseq_impl { + explicit typeseq_impl(int32_t s) : seqno_{s} {} + + /** Can't have this be constexpr. + * We need ids in shared libraries to be generated + * at load time to avoid false positives + * + * Return unique id number for each type. + * Numbers are sequentially allocated, so can use + * as vector indices + * + * Conversely note that built-in typeinfo may + * return false negatives across library boundaries + * when using clang. + **/ + template + static typeseq_impl id() { + static bool armed = true; + static int32_t id = 0; + + if (armed) { + armed = false; + id = ++s_next_id; + } + + return typeseq_impl(id); + + } + + /** 'anonymous' sentinel type. + * Niche uses for this, e.g. untyped allocator + **/ + static typeseq_impl anon() { + return typeseq_impl(-1); + } + + int32_t seqno() const { return seqno_; } + + private: + static int32_t s_next_id; + + int32_t seqno_; + }; + + template + int32_t typeseq_impl::s_next_id = 0; + + template + inline bool + operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() == rhs.seqno(); + } + + template + inline bool + operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() != rhs.seqno(); + } + + template + inline std::ostream & + operator<<(std::ostream & s, const typeseq_impl & x) { + s << x.seqno(); + return s; + } + + using typeseq = typeseq_impl<>; + } /*namespace reflect*/ +} /*namespace xo*/ + +/* end typeseq.hpp */ From d895083b584efaaee53e271ad5e7b6af1337b8b6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 11:55:50 -0500 Subject: [PATCH 3/6] xo-interpreter2 stack: cleanup memory reporting --- include/xo/reflectutil/typeseq.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index dd0b869a..d2f888cd 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -16,6 +16,10 @@ namespace xo { */ template struct typeseq_impl { + /** create sentinel value **/ + typeseq_impl() = default; + + /** typeseq with specific unique id **/ explicit typeseq_impl(int32_t s) : seqno_{s} {} /** Can't have this be constexpr. @@ -56,7 +60,7 @@ namespace xo { private: static int32_t s_next_id; - int32_t seqno_; + int32_t seqno_ = 0; }; template From fc9ca649dd8e266adf1c91969ecc25eb65125848 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 22:57:15 -0500 Subject: [PATCH 4/6] xo-reader2 stack: + TypeRegistry --- include/xo/reflectutil/type_name.hpp | 94 ++++++++++++++++++++++++++++ include/xo/reflectutil/typeseq.hpp | 89 +++++++++++++++++--------- 2 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 include/xo/reflectutil/type_name.hpp diff --git a/include/xo/reflectutil/type_name.hpp b/include/xo/reflectutil/type_name.hpp new file mode 100644 index 00000000..bdce1b0a --- /dev/null +++ b/include/xo/reflectutil/type_name.hpp @@ -0,0 +1,94 @@ +/* @file type_name.hpp */ + +#pragma once + +//#include +#include +#include // std::array +#include // std::index_sequence + +namespace xo { + namespace reflect { + + template + constexpr auto + substring_as_array(std::string_view str, + std::index_sequence indexes) + { + //return std::array{str[Idxs]..., '\n'}; + return std::array{str[Idxs]...}; + } /*substring_as_array*/ + + template 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{}; + + return substring_as_array(name, ixseq); + } /*type_name_array*/ + + template + struct type_name_holder { + static inline constexpr auto value = type_name_array(); + }; + + /** report name of type T as a string_view; + * using constexpr deps so runs at **/ + template + constexpr auto type_name() -> std::string_view + { + constexpr auto& value = type_name_holder::value; + return std::string_view{value.data(), value.size()}; + } + +#ifdef NOT_IN_USE + template + 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 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 + static constexpr auto join_v = join::value; +#endif + } /*namespace reflect*/ +} /*namespace xo*/ + +/* end type_name.hpp */ diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index d2f888cd..336f011c 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -5,22 +5,20 @@ #pragma once +#include "type_name.hpp" #include #include namespace xo { namespace reflect { - /** - * Tag here so we can preserve header-only implementation - * and still have static variable - */ - template - struct typeseq_impl { - /** create sentinel value **/ - typeseq_impl() = default; +// template + struct typerecd { + /** sentinel value **/ + typerecd() = default; - /** typeseq with specific unique id **/ - explicit typeseq_impl(int32_t s) : seqno_{s} {} + /** type-record with specific, unique id **/ + explicit typerecd(int32_t s, + std::string_view n) : seqno_{s}, name_{n} {} /** Can't have this be constexpr. * We need ids in shared libraries to be generated @@ -35,57 +33,88 @@ namespace xo { * when using clang. **/ template - static typeseq_impl id() { - static bool armed = true; + static typerecd recd() { + // reminder: {armed, id} are distint for each T + static bool s_armed = true; static int32_t id = 0; - if (armed) { - armed = false; - id = ++s_next_id; + if (s_armed) { + s_armed = false; + id = require_next_id(); } - return typeseq_impl(id); + return typerecd(id, xo::reflect::type_name()); } + 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 + //int32_t typerecd_impl::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. * Niche uses for this, e.g. untyped allocator **/ - static typeseq_impl anon() { - return typeseq_impl(-1); + static typeseq sentinel() { + return typeseq(typerecd::sentinel().seqno()); + } + + template + static typeseq id() { + return typeseq(xo::reflect::typerecd::recd().seqno()); } int32_t seqno() const { return seqno_; } private: - static int32_t s_next_id; - int32_t seqno_ = 0; }; - template - int32_t typeseq_impl::s_next_id = 0; + //template + //int32_t typeseq_impl::s_next_id = 0; - template inline bool - operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + operator==(const typeseq & lhs, const typeseq & rhs) { return lhs.seqno() == rhs.seqno(); } - template inline bool - operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + operator!=(const typeseq & lhs, const typeseq & rhs) { return lhs.seqno() != rhs.seqno(); } - template inline std::ostream & - operator<<(std::ostream & s, const typeseq_impl & x) { + operator<<(std::ostream & s, const typeseq & x) { s << x.seqno(); return s; } - - using typeseq = typeseq_impl<>; } /*namespace reflect*/ } /*namespace xo*/ From f655dbb86a2fac08bada154aed1902b8af2c926c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 00:48:00 -0500 Subject: [PATCH 5/6] xo-expression2 stack: expand MemorySizeInfo w/ per-type detail --- include/xo/reflectutil/typeseq.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/xo/reflectutil/typeseq.hpp b/include/xo/reflectutil/typeseq.hpp index 336f011c..d337cd5b 100644 --- a/include/xo/reflectutil/typeseq.hpp +++ b/include/xo/reflectutil/typeseq.hpp @@ -61,7 +61,7 @@ namespace xo { } private: - int32_t seqno_ = 0; + int32_t seqno_ = -1; std::string_view name_; }; @@ -91,10 +91,11 @@ namespace xo { return typeseq(xo::reflect::typerecd::recd().seqno()); } + bool is_sentinel() const { return seqno_ == -1; } int32_t seqno() const { return seqno_; } private: - int32_t seqno_ = 0; + int32_t seqno_ = -1; }; //template From dffaf7fa163d4781ffa116f42fa4bf9705fd049b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 27 Feb 2026 19:38:53 +1100 Subject: [PATCH 6/6] xo-cmake: setup to make share target available via cmake install --- cmake/xo_reflectutilConfig.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo_reflectutilConfig.cmake.in b/cmake/xo_reflectutilConfig.cmake.in index 26df0fc7..b57e2bb5 100644 --- a/cmake/xo_reflectutilConfig.cmake.in +++ b/cmake/xo_reflectutilConfig.cmake.in @@ -9,4 +9,5 @@ include(CMakeFindDependencyMacro) #find_dependency(xo_flatstring) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") check_required_components("@PROJECT_NAME@")