geode/loader/include/Geode/utils/casts.hpp

66 lines
1.5 KiB
C++
Raw Normal View History

2022-07-30 12:24:03 -04:00
#pragma once
#include <inttypes.h>
2022-10-30 14:59:20 -04:00
#include <iostream>
2022-07-30 12:24:03 -04:00
#include <string>
#include <type_traits>
namespace geode::cast {
2022-10-30 14:59:20 -04:00
/**
* Alias for static_cast
2022-07-30 12:24:03 -04:00
*/
template <class T, class F>
2022-07-30 12:24:03 -04:00
static constexpr T as(F const v) {
return static_cast<T>(v);
2022-07-30 12:24:03 -04:00
}
/**
* Cast from anything to anything else,
* provided they are the same size
*/
template <class T, class F>
static constexpr T union_cast(F const v) {
2022-07-30 12:24:03 -04:00
static_assert(sizeof(F) == sizeof(T), "union_cast: R and T don't match in size!");
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
union {
T t;
F f;
} x;
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
x.f = v;
return x.t;
}
2022-10-30 14:59:20 -04:00
/**
2022-07-30 12:24:03 -04:00
* Reference casting. Does a pointer-to-pointer
* cast but uses reference syntactic sugar to
* look cleaner.
*/
template <class T, class F>
2022-10-30 14:59:20 -04:00
static constexpr T reference_cast(F v) {
return reinterpret_cast<T&>(v);
}
2022-07-30 12:24:03 -04:00
2022-10-30 14:59:20 -04:00
/**
* Cast based on RTTI. Casts an adjusted this pointer
* to it's non offset form.
2022-07-30 12:24:03 -04:00
*/
template <class T, class F>
static constexpr T base_cast(F const obj) {
return static_cast<T>(dynamic_cast<void*>(obj));
2022-10-30 14:59:20 -04:00
}
2022-07-30 12:24:03 -04:00
2022-10-30 14:59:20 -04:00
/**
* Cast based on RTTI. This is used to check
* if an object is exactly the class needed. Returns
* nullptr on failure.
2022-07-30 12:24:03 -04:00
*/
template <class T, class F>
static T exact_cast(F const obj) {
if (std::strcmp(typeid(*obj).name(), typeid(std::remove_pointer_t<T>).name()) == 0) {
return base_cast<T>(obj);
}
return nullptr;
}
2022-07-30 12:24:03 -04:00
}