1// -*- C++ -*-
2//===-------------------------- typeinfo ----------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef __LIBCPP_TYPEINFO
11#define __LIBCPP_TYPEINFO
12
13/*
14
15    typeinfo synopsis
16
17namespace std {
18
19class type_info
20{
21public:
22    virtual ~type_info();
23
24    bool operator==(const type_info& rhs) const noexcept;
25    bool operator!=(const type_info& rhs) const noexcept;
26
27    bool before(const type_info& rhs) const noexcept;
28    size_t hash_code() const noexcept;
29    const char* name() const noexcept;
30
31    type_info(const type_info& rhs) = delete;
32    type_info& operator=(const type_info& rhs) = delete;
33};
34
35class bad_cast
36    : public exception
37{
38public:
39    bad_cast() noexcept;
40    bad_cast(const bad_cast&) noexcept;
41    bad_cast& operator=(const bad_cast&) noexcept;
42    virtual const char* what() const noexcept;
43};
44
45class bad_typeid
46    : public exception
47{
48public:
49    bad_typeid() noexcept;
50    bad_typeid(const bad_typeid&) noexcept;
51    bad_typeid& operator=(const bad_typeid&) noexcept;
52    virtual const char* what() const noexcept;
53};
54
55}  // std
56
57*/
58
59#include <__config>
60#include <exception>
61#include <cstddef>
62#include <cstdint>
63#ifdef _LIBCPP_NO_EXCEPTIONS
64#include <cstdlib>
65#endif
66
67#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
68#pragma GCC system_header
69#endif
70
71#if defined(_LIBCPP_ABI_VCRUNTIME)
72#include <vcruntime_typeinfo.h>
73#else
74
75#if defined(_LIBCPP_NONUNIQUE_RTTI_BIT) && !defined(_LIBCPP_ABI_MICROSOFT)
76#   define _LIBCPP_HAS_NONUNIQUE_TYPEINFO
77#endif
78
79namespace std  // purposefully not using versioning namespace
80{
81
82#if defined(_LIBCPP_ABI_MICROSOFT)
83
84class _LIBCPP_EXCEPTION_ABI type_info
85{
86    type_info& operator=(const type_info&);
87    type_info(const type_info&);
88
89    mutable struct {
90      const char *__undecorated_name;
91      const char __decorated_name[1];
92    } __data;
93
94    int __compare(const type_info &__rhs) const _NOEXCEPT;
95
96public:
97    _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
98    virtual ~type_info();
99
100    const char *name() const _NOEXCEPT;
101
102    _LIBCPP_INLINE_VISIBILITY
103    bool before(const type_info& __arg) const _NOEXCEPT {
104      return __compare(__arg) < 0;
105    }
106
107    size_t hash_code() const _NOEXCEPT;
108
109    _LIBCPP_INLINE_VISIBILITY
110    bool operator==(const type_info& __arg) const _NOEXCEPT {
111      return __compare(__arg) == 0;
112    }
113
114    _LIBCPP_INLINE_VISIBILITY
115    bool operator!=(const type_info& __arg) const _NOEXCEPT
116    { return !operator==(__arg); }
117};
118
119#elif defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)
120
121// This implementation of type_info does not assume always a unique copy of
122// the RTTI for a given type inside a program. It packs the pointer to the
123// type name into a uintptr_t and reserves the high bit of that pointer (which
124// is assumed to be free for use under the ABI in use) to represent whether
125// that specific copy of the RTTI can be assumed unique inside the program.
126// To implement equality-comparison of type_infos, we check whether BOTH
127// type_infos are guaranteed unique, and if so, we simply compare the addresses
128// of their type names instead of doing a deep string comparison, which is
129// faster. If at least one of the type_infos can't guarantee uniqueness, we
130// have no choice but to fall back to a deep string comparison.
131//
132// Note that the compiler is the one setting (or unsetting) the high bit of
133// the pointer when it constructs the type_info, depending on whether it can
134// guarantee uniqueness for that specific type_info.
135class _LIBCPP_EXCEPTION_ABI type_info
136{
137    type_info& operator=(const type_info&);
138    type_info(const type_info&);
139
140    _LIBCPP_INLINE_VISIBILITY
141    int __compare_nonunique_names(const type_info &__arg) const _NOEXCEPT
142    { return __builtin_strcmp(name(), __arg.name()); }
143
144protected:
145    uintptr_t __type_name;
146
147    _LIBCPP_INLINE_VISIBILITY
148    explicit type_info(const char* __n)
149      : __type_name(reinterpret_cast<uintptr_t>(__n)) {}
150
151public:
152    _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
153    virtual ~type_info();
154
155    _LIBCPP_INLINE_VISIBILITY
156    const char* name() const _NOEXCEPT
157    {
158      return reinterpret_cast<const char*>(__type_name &
159                                           ~_LIBCPP_NONUNIQUE_RTTI_BIT);
160    }
161
162    _LIBCPP_INLINE_VISIBILITY
163    bool before(const type_info& __arg) const _NOEXCEPT
164    {
165      if (!((__type_name & __arg.__type_name) & _LIBCPP_NONUNIQUE_RTTI_BIT))
166        return __type_name < __arg.__type_name;
167      return __compare_nonunique_names(__arg) < 0;
168    }
169
170    _LIBCPP_INLINE_VISIBILITY
171    size_t hash_code() const _NOEXCEPT
172    {
173      if (!(__type_name & _LIBCPP_NONUNIQUE_RTTI_BIT))
174        return __type_name;
175
176      const char* __ptr = name();
177      size_t __hash = 5381;
178      while (unsigned char __c = static_cast<unsigned char>(*__ptr++))
179        __hash = (__hash * 33) ^ __c;
180      return __hash;
181    }
182
183    _LIBCPP_INLINE_VISIBILITY
184    bool operator==(const type_info& __arg) const _NOEXCEPT
185    {
186      if (__type_name == __arg.__type_name)
187        return true;
188
189      if (!((__type_name & __arg.__type_name) & _LIBCPP_NONUNIQUE_RTTI_BIT))
190        return false;
191      return __compare_nonunique_names(__arg) == 0;
192    }
193
194    _LIBCPP_INLINE_VISIBILITY
195    bool operator!=(const type_info& __arg) const _NOEXCEPT
196    { return !operator==(__arg); }
197};
198
199#else // !_LIBCPP_ABI_MICROSOFT && !_LIBCPP_HAS_NONUNIQUE_TYPEINFO
200
201// This implementation of type_info assumes a unique copy of the RTTI for a
202// given type inside a program. This is a valid assumption when abiding to
203// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components).
204// Under this assumption, we can always compare the addresses of the type names
205// to implement equality-comparison of type_infos instead of having to perform
206// a deep string comparison.
207class _LIBCPP_EXCEPTION_ABI type_info
208{
209    type_info& operator=(const type_info&);
210    type_info(const type_info&);
211
212protected:
213    const char *__type_name;
214
215    _LIBCPP_INLINE_VISIBILITY
216    explicit type_info(const char* __n) : __type_name(__n) {}
217
218public:
219    _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
220    virtual ~type_info();
221
222    _LIBCPP_INLINE_VISIBILITY
223    const char* name() const _NOEXCEPT
224    { return __type_name; }
225
226    _LIBCPP_INLINE_VISIBILITY
227    bool before(const type_info& __arg) const _NOEXCEPT
228    { return __type_name < __arg.__type_name; }
229
230    _LIBCPP_INLINE_VISIBILITY
231    size_t hash_code() const _NOEXCEPT
232    { return reinterpret_cast<size_t>(__type_name); }
233
234    _LIBCPP_INLINE_VISIBILITY
235    bool operator==(const type_info& __arg) const _NOEXCEPT
236    { return __type_name == __arg.__type_name; }
237
238    _LIBCPP_INLINE_VISIBILITY
239    bool operator!=(const type_info& __arg) const _NOEXCEPT
240    { return !operator==(__arg); }
241};
242
243#endif
244
245class _LIBCPP_EXCEPTION_ABI bad_cast
246    : public exception
247{
248public:
249    bad_cast() _NOEXCEPT;
250    virtual ~bad_cast() _NOEXCEPT;
251    virtual const char* what() const _NOEXCEPT;
252};
253
254class _LIBCPP_EXCEPTION_ABI bad_typeid
255    : public exception
256{
257public:
258    bad_typeid() _NOEXCEPT;
259    virtual ~bad_typeid() _NOEXCEPT;
260    virtual const char* what() const _NOEXCEPT;
261};
262
263}  // std
264
265#endif // defined(_LIBCPP_ABI_VCRUNTIME)
266
267_LIBCPP_BEGIN_NAMESPACE_STD
268_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
269void __throw_bad_cast()
270{
271#ifndef _LIBCPP_NO_EXCEPTIONS
272    throw bad_cast();
273#else
274    _VSTD::abort();
275#endif
276}
277_LIBCPP_END_NAMESPACE_STD
278
279#endif  // __LIBCPP_TYPEINFO
280