summaryrefslogtreecommitdiffstats
path: root/libcxx/include/typeinfo
blob: a52c984961bfca1dfc3a6db750d1e94318acdcfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// -*- 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

#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_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
OpenPOWER on IntegriCloud