aboutsummaryrefslogtreecommitdiff
path: root/core/src/Utils
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/Utils')
-rw-r--r--core/src/Utils/Macros.hpp8
-rw-r--r--core/src/Utils/RTTI.hpp44
-rw-r--r--core/src/Utils/Variant.hpp27
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) };
+}