/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2017-2019 Danny Robson */ #pragma once #include "introspection/name.hpp" #include #include #include #include #include namespace cruft { namespace detail { template int typeidx_next (void) { 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& name (void) { 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). /// /// This is intended to be used as a lightweight type check for variants /// and such without requiring RTTI. /// /// The identifier is constructed at runtime and is not guaranteed to be /// stable across executions (particularly in the case of threads and /// other non-determinism). However it _is_ threadsafe to call this. /// /// The value 0 will never be returned from this function and can be used /// to indicate an 'unknown' state. /// /// The range of identifiers is _probably_ contiguous. This should not /// be relied upon for correctness, but may be used for performance /// concerns. /// /// \tparam T The type to register-and-retrieve the ID for /// \tparam TagT A namespacing type; different tags will have different /// sets of IDs. The default Tag is void. /// \return The unique ID of the type template constexpr int typeidx (void) { return detail::queryidx::get (); } template std::string_view typeidx_name (int idx) { return detail::name ()[idx]; } /// Returns the typeidx of the contained value within a variant. /// /// May throw std::bad_variant_access if the variant is /// valueless_by_exception. template int value_typeidx (std::variant const &val) { return std::visit ( [] (ValueT const &) { return typeidx (); }, val ); } }