diff --git a/include/xo/reflectutil/type_name.hpp b/include/xo/reflectutil/type_name.hpp new file mode 100644 index 0000000..bdce1b0 --- /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 d2f888c..336f011 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*/