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 <variant>
#include <vector>
#include <string_view>
#include <cassert>
@ -22,19 +23,107 @@ namespace cruft {
template <typename TagT>
int typeidx_next (void)
{
static std::atomic<int> counter;
return ++counter;
if constexpr (std::is_same_v<TagT, void>) {
// 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>
std::vector<std::string>&
std::vector<std::string_view>&
name (void)
{
static std::vector<std::string> s_names (1, "");
return s_names;
if constexpr (std::is_same_v<TagT, void>) {
// 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
/// tag type).
///
@ -57,26 +146,15 @@ namespace cruft {
/// sets of IDs. The default Tag is void.
/// \return The unique ID of the type
template <typename T, typename TagT = void>
int
constexpr int
typeidx (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;
return detail::queryidx<T,TagT>::get ();
}
template <typename TagT = void>
std::string const&
std::string_view
typeidx_name (int idx)
{
return detail::name<TagT> ()[idx];