Summary: We currently have effectively 3 implementations of type_info: one for the Microsoft ABI, one that does not assume that there's a unique copy of each RTTI in a progran, and one that assumes a unique copy. Those 3 implementations are entangled into the same class with nested ifdefs, which makes it very difficult to understand. Furthermore, the benefit of doing this is rather small since the code that is duplicated across implementations is just a couple of trivial lines. This patch stamps out the 3 versions of type_info explicitly to increase readability. It also explains what's going on with short comments, because it's far from obvious. Reviewers: EricWF, mclow.lists Subscribers: christof, jkorous, dexonsmith Differential Revision: https://reviews.llvm.org/D57606 llvm-svn: 352905
280 lines
7.5 KiB
C++
280 lines
7.5 KiB
C++
// -*- 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_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
|
|
#include <vcruntime_typeinfo.h>
|
|
#else
|
|
|
|
#if defined(_LIBCPP_NONUNIQUE_RTTI_BIT) && !defined(_LIBCPP_ABI_MICROSOFT)
|
|
# define _LIBCPP_HAS_NONUNIQUE_TYPEINFO
|
|
#endif
|
|
|
|
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); }
|
|
};
|
|
|
|
#elif defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)
|
|
|
|
// 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.
|
|
//
|
|
// 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.
|
|
class _LIBCPP_EXCEPTION_ABI type_info
|
|
{
|
|
type_info& operator=(const type_info&);
|
|
type_info(const type_info&);
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
int __compare_nonunique_names(const type_info &__arg) const _NOEXCEPT
|
|
{ return __builtin_strcmp(name(), __arg.name()); }
|
|
|
|
protected:
|
|
uintptr_t __type_name;
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
explicit type_info(const char* __n)
|
|
: __type_name(reinterpret_cast<uintptr_t>(__n)) {}
|
|
|
|
public:
|
|
_LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
|
|
virtual ~type_info();
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
const char* name() const _NOEXCEPT
|
|
{
|
|
return reinterpret_cast<const char*>(__type_name &
|
|
~_LIBCPP_NONUNIQUE_RTTI_BIT);
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool before(const type_info& __arg) const _NOEXCEPT
|
|
{
|
|
if (!((__type_name & __arg.__type_name) & _LIBCPP_NONUNIQUE_RTTI_BIT))
|
|
return __type_name < __arg.__type_name;
|
|
return __compare_nonunique_names(__arg) < 0;
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
size_t hash_code() const _NOEXCEPT
|
|
{
|
|
if (!(__type_name & _LIBCPP_NONUNIQUE_RTTI_BIT))
|
|
return __type_name;
|
|
|
|
const char* __ptr = name();
|
|
size_t __hash = 5381;
|
|
while (unsigned char __c = static_cast<unsigned char>(*__ptr++))
|
|
__hash = (__hash * 33) ^ __c;
|
|
return __hash;
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool operator==(const type_info& __arg) const _NOEXCEPT
|
|
{
|
|
if (__type_name == __arg.__type_name)
|
|
return true;
|
|
|
|
if (!((__type_name & __arg.__type_name) & _LIBCPP_NONUNIQUE_RTTI_BIT))
|
|
return false;
|
|
return __compare_nonunique_names(__arg) == 0;
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool operator!=(const type_info& __arg) const _NOEXCEPT
|
|
{ return !operator==(__arg); }
|
|
};
|
|
|
|
#else // !_LIBCPP_ABI_MICROSOFT && !_LIBCPP_HAS_NONUNIQUE_TYPEINFO
|
|
|
|
// 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.
|
|
class _LIBCPP_EXCEPTION_ABI type_info
|
|
{
|
|
type_info& operator=(const type_info&);
|
|
type_info(const type_info&);
|
|
|
|
protected:
|
|
const char *__type_name;
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
explicit type_info(const char* __n) : __type_name(__n) {}
|
|
|
|
public:
|
|
_LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
|
|
virtual ~type_info();
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
const char* name() const _NOEXCEPT
|
|
{ return __type_name; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool before(const type_info& __arg) const _NOEXCEPT
|
|
{ return __type_name < __arg.__type_name; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
size_t hash_code() const _NOEXCEPT
|
|
{ return reinterpret_cast<size_t>(__type_name); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool operator==(const type_info& __arg) const _NOEXCEPT
|
|
{ return __type_name == __arg.__type_name; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool operator!=(const type_info& __arg) const _NOEXCEPT
|
|
{ return !operator==(__arg); }
|
|
};
|
|
|
|
#endif
|
|
|
|
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_MICROSOFT) && !defined(_LIBCPP_NO_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
|