134 lines
2.6 KiB
C++
134 lines
2.6 KiB
C++
#pragma once
|
|
|
|
namespace RE
|
|
{
|
|
class NiRTTI
|
|
{
|
|
public:
|
|
NiRTTI(const char* a_name, const NiRTTI* a_baseRTTI) :
|
|
name(a_name), baseRTTI(a_baseRTTI)
|
|
{}
|
|
|
|
[[nodiscard]] constexpr const char* GetName() const noexcept { return name; }
|
|
[[nodiscard]] constexpr const NiRTTI* GetBaseRTTI() const noexcept { return baseRTTI; }
|
|
|
|
[[nodiscard]] constexpr bool IsKindOf(const NiRTTI* a_rtti) const noexcept
|
|
{
|
|
for (auto iter = this; iter; iter = iter->GetBaseRTTI()) {
|
|
if (iter == a_rtti) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// members
|
|
const char* name; // 00
|
|
const NiRTTI* baseRTTI; // 08
|
|
};
|
|
static_assert(sizeof(NiRTTI) == 0x10);
|
|
|
|
namespace Ni_Impl
|
|
{
|
|
template <class T>
|
|
using remove_cvpr_t =
|
|
std::remove_pointer_t<
|
|
std::remove_reference_t<
|
|
std::remove_cv_t<T>>>;
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat :
|
|
std::false_type
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To&, From> :
|
|
std::is_lvalue_reference<
|
|
std::remove_cv_t<From>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct types_are_compat<To*, From> :
|
|
std::is_pointer<
|
|
std::remove_cv_t<From>>
|
|
{};
|
|
|
|
template <class Base, class Derived>
|
|
struct is_base_of_no_cvpr :
|
|
std::is_base_of<
|
|
remove_cvpr_t<Base>,
|
|
remove_cvpr_t<Derived>>
|
|
{};
|
|
|
|
template <class T, class Enable = void>
|
|
struct _has_rtti :
|
|
std::false_type
|
|
{};
|
|
|
|
template <class T>
|
|
struct _has_rtti<T, std::void_t<decltype(T::Ni_RTTI)>> :
|
|
std::true_type
|
|
{};
|
|
|
|
template <class T>
|
|
struct has_rtti :
|
|
_has_rtti<remove_cvpr_t<T>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
struct cast_is_valid :
|
|
std::conjunction<
|
|
types_are_compat<To, From>,
|
|
is_base_of_no_cvpr<From, To>,
|
|
has_rtti<To>,
|
|
has_rtti<From>>
|
|
{};
|
|
|
|
template <class To, class From>
|
|
inline constexpr bool cast_is_valid_v = cast_is_valid<To, From>::value;
|
|
}
|
|
}
|
|
|
|
// downcast
|
|
template <
|
|
class To,
|
|
class From,
|
|
std::enable_if_t<
|
|
RE::Ni_Impl::cast_is_valid_v<
|
|
To,
|
|
const From*>,
|
|
int> = 0>
|
|
To netimmerse_cast(const From* a_from)
|
|
{
|
|
if (!a_from) {
|
|
return nullptr;
|
|
}
|
|
|
|
static REL::Relocation<const RE::NiRTTI*> to{ RE::Ni_Impl::remove_cvpr_t<To>::Ni_RTTI };
|
|
|
|
const RE::NiRTTI* toRTTI = to.get();
|
|
const RE::NiRTTI* fromRTTI = a_from->GetRTTI();
|
|
while (fromRTTI) {
|
|
if (fromRTTI == toRTTI) {
|
|
return static_cast<To>(const_cast<From*>(a_from));
|
|
}
|
|
fromRTTI = fromRTTI->GetBaseRTTI();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// upcast
|
|
template <
|
|
class To,
|
|
class From,
|
|
std::enable_if_t<
|
|
RE::Ni_Impl::cast_is_valid_v<
|
|
const From*,
|
|
To>,
|
|
int> = 0>
|
|
To netimmerse_cast(const From* a_from)
|
|
{
|
|
return static_cast<To>(const_cast<From*>(a_from));
|
|
}
|