From f67b370cd34a0299674acf584427921e5ffad30d Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 25 Mar 2021 12:02:00 +1000 Subject: [PATCH] typeidx: ensure fundamental types have a constexpr index --- typeidx.hpp | 116 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 19 deletions(-) diff --git a/typeidx.hpp b/typeidx.hpp index 72be89fb..83105722 100644 --- a/typeidx.hpp +++ b/typeidx.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -22,19 +23,107 @@ namespace cruft { template int typeidx_next (void) { - static std::atomic counter; - return ++counter; + if constexpr (std::is_same_v) { + // This must match the highest offset of the default set of names. + static std::atomic counter = 17; + return ++counter; + } else { + static std::atomic counter = 0; + return ++counter; + } } template - std::vector& + std::vector& name (void) { - static std::vector s_names (1, ""); - return s_names; + if constexpr (std::is_same_v) { + // This list is a propulated form of the specialisations for + // index queries that appears a little below. The order of this + // list _must_ be _exactly_ the same in both locations so that + // the indexes match. + static std::vector s_names ({ + "", + "void", + "nullptr_t", + "bool", + "char", + "signed char", + "unsigned char", + "signed short", + "unsigned short", + "signed int", + "unsigned int", + "signed long", + "unsigned long", + "signed long long", + "unsigned long long", + "float", + "double", + "long double", + }); + return s_names; + } else { + static std::vector s_names (1, ""); + return s_names; + } } + + + template + struct queryidx { + static int get (void) + { + static auto id = detail::typeidx_next (); + + static bool s_done = false; + if (!s_done) { + auto &name = detail::name (); + assert (name.size () == std::size_t (id)); + name.resize (name.size () + 1); + name[id] = cruft::introspection::name::full (); + s_done = true; + } + + return id; + } + }; + + #define SPECIALISE(KLASS, IDX) \ + template <> \ + struct queryidx { \ + static consteval int get (void) { \ + return IDX; \ + } \ + }; + + SPECIALISE(void, 1) + SPECIALISE(std::nullptr_t, 2) + + SPECIALISE(bool, 3) + + SPECIALISE(char, 4) + SPECIALISE(signed char, 5) + SPECIALISE(unsigned char, 6) + + SPECIALISE(signed short, 7) + SPECIALISE(unsigned short, 8) + SPECIALISE(signed int, 9) + SPECIALISE(unsigned int, 10) + SPECIALISE(signed long, 11) + SPECIALISE(unsigned long, 12) + SPECIALISE(signed long long, 13) + SPECIALISE(unsigned long long, 14) + + SPECIALISE(float, 15) + SPECIALISE(double, 16) + SPECIALISE(long double, 17) + + + #undef SPECIALISE } + /// Return a globally unique runtime ID for a given type (namespaced by a /// tag type). /// @@ -57,26 +146,15 @@ namespace cruft { /// sets of IDs. The default Tag is void. /// \return The unique ID of the type template - int + constexpr int typeidx (void) { - static auto id = detail::typeidx_next (); - - static bool s_done = false; - if (!s_done) { - auto &name = detail::name (); - assert (name.size () == std::size_t (id)); - name.resize (name.size () + 1); - name[id] = cruft::introspection::name::full (); - s_done = true; - } - - return id; + return detail::queryidx::get (); } template - std::string const& + std::string_view typeidx_name (int idx) { return detail::name ()[idx];