typeidx: ensure fundamental types have a constexpr index

This commit is contained in:
Danny Robson 2021-03-25 12:02:00 +10:00
parent c7b711550c
commit f67b370cd3

View File

@ -13,6 +13,7 @@
#include <atomic> #include <atomic>
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <string_view>
#include <cassert> #include <cassert>
@ -22,19 +23,107 @@ namespace cruft {
template <typename TagT> template <typename TagT>
int typeidx_next (void) int typeidx_next (void)
{ {
static std::atomic<int> counter; if constexpr (std::is_same_v<TagT, void>) {
return ++counter; // This must match the highest offset of the default set of names.
static std::atomic<int> counter = 17;
return ++counter;
} else {
static std::atomic<int> counter = 0;
return ++counter;
}
} }
template <typename TagT> template <typename TagT>
std::vector<std::string>& std::vector<std::string_view>&
name (void) name (void)
{ {
static std::vector<std::string> s_names (1, ""); if constexpr (std::is_same_v<TagT, void>) {
return s_names; // 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<std::string_view> 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<std::string_view> s_names (1, "");
return s_names;
}
} }
template <typename T, typename TagT = void>
struct queryidx {
static int get (void)
{
static auto id = detail::typeidx_next<TagT> ();
static bool s_done = false;
if (!s_done) {
auto &name = detail::name<TagT> ();
assert (name.size () == std::size_t (id));
name.resize (name.size () + 1);
name[id] = cruft::introspection::name::full<T> ();
s_done = true;
}
return id;
}
};
#define SPECIALISE(KLASS, IDX) \
template <> \
struct queryidx<KLASS, void> { \
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 /// Return a globally unique runtime ID for a given type (namespaced by a
/// tag type). /// tag type).
/// ///
@ -57,26 +146,15 @@ namespace cruft {
/// sets of IDs. The default Tag is void. /// sets of IDs. The default Tag is void.
/// \return The unique ID of the type /// \return The unique ID of the type
template <typename T, typename TagT = void> template <typename T, typename TagT = void>
int constexpr int
typeidx (void) typeidx (void)
{ {
static auto id = detail::typeidx_next<TagT> (); return detail::queryidx<T,TagT>::get ();
static bool s_done = false;
if (!s_done) {
auto &name = detail::name<TagT> ();
assert (name.size () == std::size_t (id));
name.resize (name.size () + 1);
name[id] = cruft::introspection::name::full<T> ();
s_done = true;
}
return id;
} }
template <typename TagT = void> template <typename TagT = void>
std::string const& std::string_view
typeidx_name (int idx) typeidx_name (int idx)
{ {
return detail::name<TagT> ()[idx]; return detail::name<TagT> ()[idx];