diff options
Diffstat (limited to 'core/src/Utils')
-rw-r--r-- | core/src/Utils/Macros.hpp | 8 | ||||
-rw-r--r-- | core/src/Utils/RTTI.hpp | 44 | ||||
-rw-r--r-- | core/src/Utils/Variant.hpp | 27 |
3 files changed, 78 insertions, 1 deletions
diff --git a/core/src/Utils/Macros.hpp b/core/src/Utils/Macros.hpp index cb949b2..ab846f4 100644 --- a/core/src/Utils/Macros.hpp +++ b/core/src/Utils/Macros.hpp @@ -1,6 +1,12 @@ -#pragma once +#pragma once #define CONCAT_IMPL(a, b) a##b #define CONCAT(a, b) CONCAT_IMPL(a, b) #define UNIQUE_NAME(prefix) CONCAT(prefix, __LINE__) + +#if defined(_MSC_VER) +# define UNREACHABLE __assume(false) +#elif defined(__clang__) || defined(__GNUC__) +# define UUNREACHABLE __builtin_unreachable() +#endif diff --git a/core/src/Utils/RTTI.hpp b/core/src/Utils/RTTI.hpp new file mode 100644 index 0000000..bc0d289 --- /dev/null +++ b/core/src/Utils/RTTI.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include <cassert> + +template <class T, class TBase> +bool is_a(TBase* t) { + assert(t != nullptr); + return T::IsInstance(t); +} + +template <class T, class TBase> +bool is_a_nullable(TBase* t) { + if (t) { + return is_a<T, TBase>(t); + } else { + return false; + } +} + +template <class T, class TBase> +T* dyn_cast(TBase* t) { + assert(t != nullptr); + if (T::IsInstance(t)) { + return static_cast<T*>(t); + } else { + return nullptr; + } +} + +template <class T, class TBase> +const T* dyn_cast(const TBase* t) { + assert(t != nullptr); + if (T::IsInstance(t)) { + return static_cast<const T*>(t); + } else { + return nullptr; + } +} + +template <class T, class TBase> +T* dyn_cast_nullable(TBase* t) { + if (!t) return nullptr; + return dyn_cast<T, TBase>(t); +} diff --git a/core/src/Utils/Variant.hpp b/core/src/Utils/Variant.hpp new file mode 100644 index 0000000..7fdb2dc --- /dev/null +++ b/core/src/Utils/Variant.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <utility> +#include <variant> + +template <class... Ts> +struct Overloaded : Ts... { using Ts::operator()...; }; +template <class... Ts> +Overloaded(Ts...) -> Overloaded<Ts...>; + +template <class... Args> +struct VariantCastProxy { + std::variant<Args...> v; + + template <class... ToArgs> + operator std::variant<ToArgs...>() const { + return std::visit( + [](auto&& arg) -> std::variant<ToArgs...> { return arg; }, + v); + } +}; + +/// Use snake_case naming to align with `static_cast`, `dynamic_cast`, etc.. +template <class... Args> +auto variant_cast(std::variant<Args...> v) -> VariantCastProxy<Args...> { + return { std::move(v) }; +} |