213 lines
7.7 KiB
C++
213 lines
7.7 KiB
C++
/*
|
|
* 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 2019-2020 Danny Robson <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../algo/search.hpp"
|
|
#include "../std.hpp"
|
|
#include "../platform.hpp"
|
|
|
|
#include <string_view>
|
|
#include <algorithm>
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
namespace cruft::introspection::name {
|
|
template <typename T>
|
|
constexpr
|
|
std::string_view full (void)
|
|
{
|
|
std::string_view pretty_function (__PRETTY_FUNCTION__);
|
|
|
|
#ifdef __clang__
|
|
// PRETTY_FUNCTION = std::string_view cruft::type_name() [T = std::__1::vector<int, std::__1::allocator<int> >]
|
|
|
|
std::string_view const prefix = "[T = ";
|
|
#elif defined(__GNUC__)
|
|
// PRETTY_FUNCTION = "constexpr std::string_view cruft::type_name() [with T = std::__debug::vector<int>; std::string_view = std::basic_string_view<char>]"
|
|
|
|
std::string_view prefix = "[with T = ";
|
|
#else
|
|
#error "Unsupported compiler"
|
|
#endif
|
|
|
|
// Find the location where the type begins.
|
|
auto const type_begin = std::search (
|
|
pretty_function.begin (),
|
|
pretty_function.end (),
|
|
prefix.begin (),
|
|
prefix.end ()
|
|
) + prefix.size ();
|
|
|
|
// Find the point the type name ends. Both use ']', but gcc lists
|
|
// std::string_view in the function signature too and so requires the
|
|
// delimiting ';' as a suffix.
|
|
char const suffixes[] = ";]";
|
|
auto const type_end = std::find_first_of (
|
|
type_begin,
|
|
pretty_function.end (),
|
|
std::begin (suffixes),
|
|
std::end (suffixes)
|
|
);
|
|
|
|
// Find the start of the first template parameter so we can cut it out.
|
|
// If this isn't present we end up with a pointer to the end of the
|
|
// type string which is the end of the type anyway.
|
|
auto const template_start = std::find (type_begin, type_end, '<');
|
|
auto const template_end = cruft::search::balanced (template_start, type_end, '<', '>');
|
|
|
|
return std::string_view (
|
|
type_begin,
|
|
std::distance (type_begin, template_end)
|
|
);
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
constexpr
|
|
std::string_view bare (void)
|
|
{
|
|
|
|
auto const fullname = full<T> ();
|
|
|
|
constexpr char const namespace_symbol[] = "::";
|
|
auto const last_namespace_pos = std::search (
|
|
std::rbegin (fullname),
|
|
std::rend (fullname),
|
|
namespace_symbol + 0,
|
|
namespace_symbol + 2
|
|
);
|
|
|
|
auto const length = std::distance (std::rbegin (fullname), last_namespace_pos);
|
|
auto const offset = fullname.size () - length;
|
|
return std::string_view (fullname.data () + offset, length);
|
|
}
|
|
|
|
|
|
template <> constexpr std::string_view bare<i08> (void) { return "i08"; }
|
|
template <> constexpr std::string_view bare<i16> (void) { return "i16"; }
|
|
template <> constexpr std::string_view bare<i32> (void) { return "i32"; }
|
|
template <> constexpr std::string_view bare<i64> (void) { return "i64"; }
|
|
|
|
template <> constexpr std::string_view bare<u08> (void) { return "u08"; }
|
|
template <> constexpr std::string_view bare<u16> (void) { return "u16"; }
|
|
template <> constexpr std::string_view bare<u32> (void) { return "u32"; }
|
|
template <> constexpr std::string_view bare<u64> (void) { return "u64"; }
|
|
|
|
template <> constexpr std::string_view bare<f32> (void) { return "f32"; }
|
|
template <> constexpr std::string_view bare<f64> (void) { return "f64"; }
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
namespace detail {
|
|
template <std::size_t N>
|
|
constexpr std::size_t
|
|
rfind (char const (&str)[N], char target, int offset = N)
|
|
{
|
|
static_assert (N > 1);
|
|
|
|
for (std::size_t i = N - 1 - (N - offset); i; --i)
|
|
if (str[i] == target)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
template <typename T>
|
|
struct pointer_to_member_type { };
|
|
|
|
template <typename A, typename B>
|
|
struct pointer_to_member_type<A B::*> { using type = A; };
|
|
|
|
template <typename T>
|
|
struct pointer_to_member_class { };
|
|
|
|
template <typename A, typename B>
|
|
struct pointer_to_member_class<A B::*> { using type = B; };
|
|
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Returns a stringview containing the name of the member pointed to by
|
|
/// the pointer-tomember.
|
|
template <typename TypeT, typename KlassT, TypeT KlassT::*Ptr>
|
|
constexpr std::string_view
|
|
member (void)
|
|
{
|
|
#if defined(COMPILER_GCC)
|
|
// GCC: "constexpr std::string_view cruft::introspection::name::member() [with TypeT = int; KlassT = foo; TypeT KlassT::* Ptr = &foo::a; std::string_view = std::basic_string_view<char>]"
|
|
//
|
|
// We find the last semicolon, then count back to the colon.
|
|
|
|
constexpr std::size_t b = detail::rfind (__PRETTY_FUNCTION__, ';');
|
|
constexpr std::size_t a = detail::rfind (__PRETTY_FUNCTION__, ':', b) + 1;
|
|
|
|
constexpr std::string_view name = __PRETTY_FUNCTION__;
|
|
return std::string_view (name.data () + a, b - a);
|
|
#elif defined(COMPILER_CLANG)
|
|
// std::string_view cruft::introspection::name::member() [TypeT = int, KlassT = foo, Ptr = &foo::a]
|
|
//
|
|
// The strategy is to count back from the end of the string to find
|
|
// the ampersand and return everything between that and the final
|
|
// character (which is always a ']').
|
|
|
|
constexpr std::size_t a = detail::rfind (__PRETTY_FUNCTION__, ':') + 1;
|
|
constexpr std::size_t b = detail::rfind (__PRETTY_FUNCTION__, ']');
|
|
constexpr std::string_view name = __PRETTY_FUNCTION__;
|
|
return std::string_view (name.data () + a, b - a);
|
|
#else
|
|
#error "Unsupported compiler"
|
|
#endif
|
|
}
|
|
|
|
|
|
template <auto Ptr>
|
|
constexpr std::string_view
|
|
member (void)
|
|
{
|
|
return member<
|
|
typename pointer_to_member_type <decltype(Ptr)>::type,
|
|
typename pointer_to_member_class<decltype(Ptr)>::type,
|
|
Ptr
|
|
> ();
|
|
}
|
|
|
|
|
|
constexpr std::size_t
|
|
member_offset (auto ptr)
|
|
{
|
|
using klass_t = typename pointer_to_member_class<decltype (ptr)>::type;
|
|
klass_t instance {};
|
|
return std::uintptr_t (&(instance.*ptr)) - std::uintptr_t (&instance);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
template <typename T>
|
|
struct type_char;
|
|
|
|
template <> struct type_char<float > { static constexpr char value = 'f'; };
|
|
template <> struct type_char<double> { static constexpr char value = 'd'; };
|
|
|
|
template <> struct type_char< int8_t> { static constexpr char value = 'i'; };
|
|
template <> struct type_char< int16_t> { static constexpr char value = 'i'; };
|
|
template <> struct type_char< int32_t> { static constexpr char value = 'i'; };
|
|
template <> struct type_char< int64_t> { static constexpr char value = 'i'; };
|
|
|
|
template <> struct type_char< uint8_t> { static constexpr char value = 'u'; };
|
|
template <> struct type_char<uint16_t> { static constexpr char value = 'u'; };
|
|
template <> struct type_char<uint32_t> { static constexpr char value = 'u'; };
|
|
template <> struct type_char<uint64_t> { static constexpr char value = 'u'; };
|
|
|
|
template <typename T>
|
|
constexpr auto type_char_v = type_char<T>::value;
|
|
}
|