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
14namespace 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 */
27template <typename To, typename From>
28std::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
45template <typename To, typename From>
46std::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
62template <typename To, typename From>
63std::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