1 | #pragma once |
2 | |
3 | #include <type_traits> |
4 | #include <typeinfo> |
5 | #include <typeindex> |
6 | #include <memory> |
7 | #include <string> |
8 | |
9 | #include <ext/shared_ptr_helper.h> |
10 | #include <Common/Exception.h> |
11 | #include <common/demangle.h> |
12 | |
13 | |
14 | namespace DB |
15 | { |
16 | namespace ErrorCodes |
17 | { |
18 | extern const int BAD_CAST; |
19 | } |
20 | } |
21 | |
22 | |
23 | /** Checks type by comparing typeid. |
24 | * The exact match of the type is checked. That is, cast to the ancestor will be unsuccessful. |
25 | * In the rest, behaves like a dynamic_cast. |
26 | */ |
27 | template <typename To, typename From> |
28 | std::enable_if_t<std::is_reference_v<To>, To> typeid_cast(From & from) |
29 | { |
30 | try |
31 | { |
32 | if ((typeid(From) == typeid(To)) || (typeid(from) == typeid(To))) |
33 | return static_cast<To>(from); |
34 | } |
35 | catch (const std::exception & e) |
36 | { |
37 | throw DB::Exception(e.what(), DB::ErrorCodes::BAD_CAST); |
38 | } |
39 | |
40 | throw DB::Exception("Bad cast from type " + demangle(typeid(from).name()) + " to " + demangle(typeid(To).name()), |
41 | DB::ErrorCodes::BAD_CAST); |
42 | } |
43 | |
44 | |
45 | template <typename To, typename From> |
46 | std::enable_if_t<std::is_pointer_v<To>, To> typeid_cast(From * from) |
47 | { |
48 | try |
49 | { |
50 | if ((typeid(From) == typeid(std::remove_pointer_t<To>)) || (typeid(*from) == typeid(std::remove_pointer_t<To>))) |
51 | return static_cast<To>(from); |
52 | else |
53 | return nullptr; |
54 | } |
55 | catch (const std::exception & e) |
56 | { |
57 | throw DB::Exception(e.what(), DB::ErrorCodes::BAD_CAST); |
58 | } |
59 | } |
60 | |
61 | |
62 | template <typename To, typename From> |
63 | std::enable_if_t<ext::is_shared_ptr_v<To>, To> typeid_cast(const std::shared_ptr<From> & from) |
64 | { |
65 | try |
66 | { |
67 | if ((typeid(From) == typeid(typename To::element_type)) || (typeid(*from) == typeid(typename To::element_type))) |
68 | return std::static_pointer_cast<typename To::element_type>(from); |
69 | else |
70 | return nullptr; |
71 | } |
72 | catch (const std::exception & e) |
73 | { |
74 | throw DB::Exception(e.what(), DB::ErrorCodes::BAD_CAST); |
75 | } |
76 | } |
77 | |