Files
Simple-Protocol-Lib/test/type_name.hpp
Persson-dev 073872df94
All checks were successful
Linux arm64 / Build (push) Successful in 15s
byte swapping
2025-06-26 14:43:27 +02:00

155 lines
5.3 KiB
C++

// Copyright (c) 2018 Will Wray https://keybase.io/willwray
//
// Distributed under the Boost Software License, Version 1.0.
// (http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <cstring>
#include <string>
#include <string_view>
#include <typeinfo>
#include <type_traits>
#if __has_include(<cxxabi.h>)
# include <cxxabi.h>
# include <cstdlib>
# include <memory>
#endif
constexpr bool CXXABI
{
#if __has_include(<cxxabi.h>)
true
#endif
};
/*
"type_name_rt.hpp": get type names at runtime (hence 'rt')
^^^^^^^^^^^^^^^^
This header defines, in global scope (i.e. not namespace'd):
(1) A function template type_name_str<T>() for extracting a type's name.
(2) A variable template type_name_rt<T> initialized to the type's name.
(also an incomplete class template IdT<T>, an implementation detail.)
The template type parameter T is mapped to a readable name for the type.
The work is done at runtime by what is the most standard current method;
runtime type information (RTTI) and, on CXXABI, a demangle call
(for compile-time alternatives see type_name_pt or type_name_ct).
(1) type_name_str<T>()
Returns a std::string copy of the demangled typeid name.
On each call it does all the work, and cleans it all up
(i.e. it frees any demangle allocation once copied from).
(2) type_name_rt<T>
A std::string_view global constant (a view into the
demangle buffer, on CXXABI, which is not ever free'd).
All work is done in static initialization, before main()
Failure is signalled by an empty return value; ""
(indicates a demangle failure as typeid is assumed fail-safe).
Requirements:
C++17 for string_view, constexpr-if, CTAD (unique_ptr) and __has_include
RTTI, the compiler's runtime type information, must be enabled
Dependencies: <string>,<string_view>,<type_traits> for std::conditional
<typeinfo> (RTTI)
for typeid(T).name(), an implementation-defined name.
<cxxabi.h> (on CXXABI platforms only - GCC, Clang, etc.)
for abi::__cxa_demangle(name,...)
to map typeid(T).name to a human readable name for T.
<cstdlib> for std::free, <memory> for std::unique_ptr
E.g.
int i;
std::cout << type_name_rt<decltype(i)> << "\n^^^ tada!";
--- stdout ---
int
^^^ tada!
*/
// IdT<T> wraps T as template param so typeid can't decay ref or cv quals.
// An implementation detail; must be a 3-character id, any 3 chars will do.
template <typename T> struct IdT {};
namespace impl
{
// demangle<bool Free=false>( const char* name)
//
// (1) On non-CXXABI returns name, regardless of the template parameter.
// i.e. the function does nothing but return its parameter, a char*.
//
// (2) On CXXABI the demangle ABI is called and the result is returned
// with return type depending on the boolean template argument:
// (a) char* by default (Free=false). Any demangle malloc is not free'd.
// (b) unique_ptr<char> (Free=true) to RAII-free any malloc'd chars.
//
// The input name should be a valid mangled name like typeid(T).name()
// Null return value implies demangle fail (no malloc, free is harmless).
//
template <bool Free = false>
auto
demangle(char const* name) noexcept(!CXXABI)
{
if constexpr (!CXXABI) {
return name; // NOP: assume already demangled if not on CXXABI
} else {
auto dmg = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
if constexpr (Free)
return std::unique_ptr<char, decltype(std::free)*>( dmg, std::free);
else
return dmg;
}
}
// prefix_len (constant): prefix length of demangled typeid(IdT<T>)
// for different compilers (remove 4 chars "int>" from the length)
size_t IdT_prefix_len()
{
static size_t const len = std::strlen(demangle<>(typeid(IdT<int>).name()))
- std::strlen("int>");
return len;
}
template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <typename T>
inline constexpr bool is_cvref_v = !std::is_same_v<T,remove_cvref_t<T>>;
// type_name_rt<T>() Returns string, frees any malloc from ABI demangle
// type_name_rt<T,false>() Returns string_view, does not free demangle malloc
//
template <typename T, bool Free = true, typename = void>
auto
type_name_rt() noexcept(!CXXABI) -> std::conditional_t<Free, std::string,
std::string_view>
{
if constexpr (!is_cvref_v<T>)
{
if (auto dmg = demangle<Free>(typeid(T).name()))
{
return { &*dmg };
}
}
else // wrap all cvref types for now - maybe only do functions and arrays
{
if (auto dmg = demangle<Free>(typeid(IdT<T>).name()))
{
size_t const p = IdT_prefix_len();
return { &*dmg + p, std::strlen(&*dmg) - p - 1 };
}
}
return "";
}
} // namespace impl
// type_name_str<T>() Returns a std::string copy of the demangled typeid name.
//
template <typename T>
std::string
const type_name_str() { return impl::type_name_rt<T>(); }
// type_name_rt<T> Global constant; "The Demangle that Never Dangles"
//
template <typename T>
inline
std::string_view
const type_name_rt = impl::type_name_rt<T, false>();