| // -*- C++ -*- |
| //===-------------------------- typeinfo ----------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef __LIBCPP_TYPEINFO |
| #define __LIBCPP_TYPEINFO |
| |
| /* |
| |
| typeinfo synopsis |
| |
| namespace std { |
| |
| class type_info |
| { |
| public: |
| virtual ~type_info(); |
| |
| bool operator==(const type_info& rhs) const noexcept; |
| bool operator!=(const type_info& rhs) const noexcept; |
| |
| bool before(const type_info& rhs) const noexcept; |
| size_t hash_code() const noexcept; |
| const char* name() const noexcept; |
| |
| type_info(const type_info& rhs) = delete; |
| type_info& operator=(const type_info& rhs) = delete; |
| }; |
| |
| class bad_cast |
| : public exception |
| { |
| public: |
| bad_cast() noexcept; |
| bad_cast(const bad_cast&) noexcept; |
| bad_cast& operator=(const bad_cast&) noexcept; |
| virtual const char* what() const noexcept; |
| }; |
| |
| class bad_typeid |
| : public exception |
| { |
| public: |
| bad_typeid() noexcept; |
| bad_typeid(const bad_typeid&) noexcept; |
| bad_typeid& operator=(const bad_typeid&) noexcept; |
| virtual const char* what() const noexcept; |
| }; |
| |
| } // std |
| |
| */ |
| |
| #include <__config> |
| #include <exception> |
| #include <cstddef> |
| #include <cstdint> |
| #ifdef _LIBCPP_NO_EXCEPTIONS |
| #include <cstdlib> |
| #endif |
| |
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| #pragma GCC system_header |
| #endif |
| |
| #if defined(_LIBCPP_ABI_VCRUNTIME) |
| #include <vcruntime_typeinfo.h> |
| #else |
| |
| namespace std // purposefully not using versioning namespace |
| { |
| |
| |
| #if defined(_LIBCPP_ABI_MICROSOFT) |
| |
| class _LIBCPP_EXCEPTION_ABI type_info |
| { |
| type_info& operator=(const type_info&); |
| type_info(const type_info&); |
| |
| mutable struct { |
| const char *__undecorated_name; |
| const char __decorated_name[1]; |
| } __data; |
| |
| int __compare(const type_info &__rhs) const _NOEXCEPT; |
| |
| public: |
| _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE |
| virtual ~type_info(); |
| |
| const char *name() const _NOEXCEPT; |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool before(const type_info& __arg) const _NOEXCEPT { |
| return __compare(__arg) < 0; |
| } |
| |
| size_t hash_code() const _NOEXCEPT; |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool operator==(const type_info& __arg) const _NOEXCEPT { |
| return __compare(__arg) == 0; |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool operator!=(const type_info& __arg) const _NOEXCEPT |
| { return !operator==(__arg); } |
| }; |
| |
| #else // !defined(_LIBCPP_ABI_MICROSOFT) |
| |
| // ========================================================================== // |
| // Implementations |
| // ========================================================================== // |
| // ------------------------------------------------------------------------- // |
| // Unique |
| // ------------------------------------------------------------------------- // |
| // This implementation of type_info assumes a unique copy of the RTTI for a |
| // given type inside a program. This is a valid assumption when abiding to |
| // Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components). |
| // Under this assumption, we can always compare the addresses of the type names |
| // to implement equality-comparison of type_infos instead of having to perform |
| // a deep string comparison. |
| // -------------------------------------------------------------------------- // |
| // NonUnique |
| // -------------------------------------------------------------------------- // |
| // This implementation of type_info does not assume there is always a unique |
| // copy of the RTTI for a given type inside a program. For various reasons |
| // the linker may have failed to merge every copy of a types RTTI |
| // (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two |
| // type_infos are equal if their addresses are equal or if a deep string |
| // comparison is equal. |
| // -------------------------------------------------------------------------- // |
| // NonUniqueARMRTTIBit |
| // -------------------------------------------------------------------------- // |
| // This implementation of type_info does not assume always a unique copy of |
| // the RTTI for a given type inside a program. It packs the pointer to the |
| // type name into a uintptr_t and reserves the high bit of that pointer (which |
| // is assumed to be free for use under the ABI in use) to represent whether |
| // that specific copy of the RTTI can be assumed unique inside the program. |
| // To implement equality-comparison of type_infos, we check whether BOTH |
| // type_infos are guaranteed unique, and if so, we simply compare the addresses |
| // of their type names instead of doing a deep string comparison, which is |
| // faster. If at least one of the type_infos can't guarantee uniqueness, we |
| // have no choice but to fall back to a deep string comparison. |
| // |
| // This implementation is specific to ARM64 on Apple platforms. |
| // |
| // Note that the compiler is the one setting (or unsetting) the high bit of |
| // the pointer when it constructs the type_info, depending on whether it can |
| // guarantee uniqueness for that specific type_info. |
| |
| struct __type_info_implementations { |
| struct __string_impl_base { |
| typedef const char* __type_name_t; |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { |
| return __v; |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { |
| return __v; |
| } |
| }; |
| |
| struct __unique_impl : __string_impl_base { |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static size_t __hash(__type_name_t __v) _NOEXCEPT { |
| return reinterpret_cast<size_t>(__v); |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| return __lhs == __rhs; |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| return __lhs < __rhs; |
| } |
| }; |
| |
| struct __non_unique_impl : __string_impl_base { |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static size_t __hash(__type_name_t __ptr) _NOEXCEPT { |
| size_t __hash = 5381; |
| while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) |
| __hash = (__hash * 33) ^ __c; |
| return __hash; |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| return __builtin_strcmp(__lhs, __rhs) < 0; |
| } |
| }; |
| |
| struct __non_unique_arm_rtti_bit_impl { |
| typedef uintptr_t __type_name_t; |
| |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { |
| return reinterpret_cast<const char*>(__v & |
| ~__non_unique_rtti_bit::value); |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { |
| return reinterpret_cast<__type_name_t>(__v); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static size_t __hash(__type_name_t __v) _NOEXCEPT { |
| if (__is_type_name_unique(__v)) |
| return reinterpret_cast<size_t>(__v); |
| return __non_unique_impl::__hash(__type_name_to_string(__v)); |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| if (__lhs == __rhs) |
| return true; |
| if (__is_type_name_unique(__lhs, __rhs)) |
| return false; |
| return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; |
| } |
| _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE |
| static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| if (__is_type_name_unique(__lhs, __rhs)) |
| return __lhs < __rhs; |
| return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; |
| } |
| |
| private: |
| // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when |
| // this implementation is actually used. |
| typedef std::integral_constant<__type_name_t, |
| (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit; |
| |
| _LIBCPP_INLINE_VISIBILITY |
| static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { |
| return !(__lhs & __non_unique_rtti_bit::value); |
| } |
| _LIBCPP_INLINE_VISIBILITY |
| static bool __is_type_name_unique(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { |
| return !((__lhs & __rhs) & __non_unique_rtti_bit::value); |
| } |
| }; |
| |
| typedef |
| #if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) |
| __non_unique_arm_rtti_bit_impl |
| #elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 0 |
| __non_unique_impl |
| #elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 1 |
| __unique_impl |
| #else |
| # error invalid configuration for _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT |
| #endif |
| __impl; |
| }; |
| |
| class _LIBCPP_EXCEPTION_ABI type_info |
| { |
| type_info& operator=(const type_info&); |
| type_info(const type_info&); |
| |
| protected: |
| typedef __type_info_implementations::__impl __impl; |
| |
| __impl::__type_name_t __type_name; |
| |
| _LIBCPP_INLINE_VISIBILITY |
| explicit type_info(const char* __n) |
| : __type_name(__impl::__string_to_type_name(__n)) {} |
| |
| public: |
| _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE |
| virtual ~type_info(); |
| |
| _LIBCPP_INLINE_VISIBILITY |
| const char* name() const _NOEXCEPT |
| { |
| return __impl::__type_name_to_string(__type_name); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool before(const type_info& __arg) const _NOEXCEPT |
| { |
| return __impl::__lt(__type_name, __arg.__type_name); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| size_t hash_code() const _NOEXCEPT |
| { |
| return __impl::__hash(__type_name); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool operator==(const type_info& __arg) const _NOEXCEPT |
| { |
| return __impl::__eq(__type_name, __arg.__type_name); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| bool operator!=(const type_info& __arg) const _NOEXCEPT |
| { return !operator==(__arg); } |
| }; |
| #endif // defined(_LIBCPP_ABI_MICROSOFT) |
| |
| class _LIBCPP_EXCEPTION_ABI bad_cast |
| : public exception |
| { |
| public: |
| bad_cast() _NOEXCEPT; |
| virtual ~bad_cast() _NOEXCEPT; |
| virtual const char* what() const _NOEXCEPT; |
| }; |
| |
| class _LIBCPP_EXCEPTION_ABI bad_typeid |
| : public exception |
| { |
| public: |
| bad_typeid() _NOEXCEPT; |
| virtual ~bad_typeid() _NOEXCEPT; |
| virtual const char* what() const _NOEXCEPT; |
| }; |
| |
| } // std |
| |
| #endif // defined(_LIBCPP_ABI_VCRUNTIME) |
| |
| _LIBCPP_BEGIN_NAMESPACE_STD |
| _LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY |
| void __throw_bad_cast() |
| { |
| #ifndef _LIBCPP_NO_EXCEPTIONS |
| throw bad_cast(); |
| #else |
| _VSTD::abort(); |
| #endif |
| } |
| _LIBCPP_END_NAMESPACE_STD |
| |
| #endif // __LIBCPP_TYPEINFO |