/* * 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 */ #pragma once #include "../algo/search.hpp" #include "../std.hpp" #include "../platform.hpp" #include #include /////////////////////////////////////////////////////////////////////////////// namespace cruft::introspection::name { template 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 >] std::string_view const prefix = "[T = "; #elif defined(__GNUC__) // PRETTY_FUNCTION = "constexpr std::string_view cruft::type_name() [with T = std::__debug::vector; std::string_view = std::basic_string_view]" 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 constexpr std::string_view bare (void) { auto const fullname = full (); 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 (void) { return "i08"; } template <> constexpr std::string_view bare (void) { return "i16"; } template <> constexpr std::string_view bare (void) { return "i32"; } template <> constexpr std::string_view bare (void) { return "i64"; } template <> constexpr std::string_view bare (void) { return "u08"; } template <> constexpr std::string_view bare (void) { return "u16"; } template <> constexpr std::string_view bare (void) { return "u32"; } template <> constexpr std::string_view bare (void) { return "u64"; } template <> constexpr std::string_view bare (void) { return "f32"; } template <> constexpr std::string_view bare (void) { return "f64"; } /////////////////////////////////////////////////////////////////////////////// namespace detail { template 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 struct pointer_to_member_type { }; template struct pointer_to_member_type { using type = A; }; template struct pointer_to_member_class { }; template struct pointer_to_member_class { using type = B; }; ///------------------------------------------------------------------------ /// Returns a stringview containing the name of the member pointed to by /// the pointer-tomember. template 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]" // // 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 constexpr std::string_view member (void) { return member< typename pointer_to_member_type ::type, typename pointer_to_member_class::type, Ptr > (); } constexpr std::size_t member_offset (auto ptr) { using klass_t = typename pointer_to_member_class::type; klass_t instance {}; return std::uintptr_t (&(instance.*ptr)) - std::uintptr_t (&instance); } /////////////////////////////////////////////////////////////////////////// template struct type_char; template <> struct type_char { static constexpr char value = 'f'; }; template <> struct type_char { 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 { static constexpr char value = 'u'; }; template <> struct type_char { static constexpr char value = 'u'; }; template <> struct type_char { static constexpr char value = 'u'; }; template constexpr auto type_char_v = type_char::value; }