| 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 | |