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
|
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
* Hand-rolled LLVM-style RTTI system for class hierarchies where dynamic_cast isn't fast enough.
*/
#ifndef INKSCAPE_UTIL_CAST_H
#define INKSCAPE_UTIL_CAST_H
#include <type_traits>
/*
* In order to use this system with a class hierarchy, specialize the following templates for
* every member of the hierarchy. The only requirement is that
*
* first_tag<T> <= first_tag<S> <= last_tag<T>
*
* exactly when S is a derived class of T. Then add to each class the line of boilerplate
*
* int tag() const override { return tag_of<decltype(*this)>; }
*/
template <typename T> inline constexpr int first_tag = std::enable_if<!sizeof(T), void>::value;
template <typename T> inline constexpr int last_tag = std::enable_if<!sizeof(T), void>::value;
/**
* Convenience function to retrieve the tag (class id) of a given type.
*/
template <typename T> inline constexpr int tag_of = first_tag<std::remove_cv_t<std::remove_reference_t<T>>>;
/**
* Equivalent to the boolean value of dynamic_cast<T const*>(...).
*
* If the supplied pointer is null, the check fails.
*
* To help catch redundant checks, checks that are known at compile time currently generate
* a compile error. Please feel free to remove these static_asserts if they become unhelpful.
*/
template<typename T, typename S>
bool is(S const *s)
{
if (!s) return false;
if constexpr (std::is_base_of_v<T, S>) {
static_assert(!sizeof(T), "check is always true");
return true;
} else if constexpr (std::is_base_of_v<S, T>) {
auto const s_tag = s->tag();
return first_tag<T> <= s_tag && s_tag <= last_tag<T>;
} else {
static_assert(!sizeof(T), "check is always false");
return false;
}
}
/**
* Equivalent to static_cast<T [const]*>(...) where the const is deduced.
*/
template<typename T, typename S>
auto cast_unsafe(S *s)
{
return static_cast<T*>(s);
}
template<typename T, typename S>
auto cast_unsafe(S const *s)
{
return static_cast<T const*>(s);
}
/**
* Equivalent to dynamic_cast<T [const]*>(...) where the const is deduced.
*
* If the supplied pointer is null, the result is null.
*
* To help catch redundant casts, casts that are known at compile time currently generate
* a compile error. Please feel free to remove these static_asserts if they become unhelpful.
*/
template<typename T, typename S>
auto cast(S *s)
{
if constexpr (std::is_base_of_v<T, S>) {
// Removed static assert; it complicates template "collect_items"
// static_assert(!sizeof(T), "cast is unnecessary");
return cast_unsafe<T>(s);
} else if constexpr (std::is_base_of_v<S, T>) {
return is<T>(s) ? cast_unsafe<T>(s) : nullptr;
} else {
static_assert(!sizeof(T), "cast is impossible");
return nullptr;
}
}
#endif // INKSCAPE_UTIL_CAST_H
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
|