#pragma once #include "RE/B/BSFixedString.h" #include "RE/B/BSScript_TypeInfo.h" #include "RE/B/BSTSmartPointer.h" #include "RE/M/MemoryManager.h" namespace RE { namespace BSScript { class Array; class Object; class Struct; namespace detail { struct variable_raw_accessor; } class Variable { public: Variable() noexcept = default; Variable(const Variable& a_rhs) { copy(a_rhs); } Variable(Variable&&) noexcept = default; ~Variable() { reset(); } Variable& operator=(const Variable& a_rhs) { if (this != std::addressof(a_rhs)) { reset(); copy(a_rhs); } return *this; } Variable& operator=(Variable&&) noexcept = default; Variable& operator=(std::nullptr_t) { reset(); assert(is()); return *this; } Variable& operator=(BSTSmartPointer a_object); Variable& operator=(BSFixedString a_string) { reset(); value.s = std::move(a_string); varType = RawType::kString; assert(is()); return *this; } Variable& operator=(std::uint32_t a_unsigned) { reset(); value.u = a_unsigned; varType = RawType::kInt; assert(is()); return *this; } Variable& operator=(std::int32_t a_signed) { reset(); value.i = a_signed; varType = RawType::kInt; assert(is()); return *this; } Variable& operator=(float a_float) { reset(); value.f = a_float; varType = RawType::kFloat; assert(is()); return *this; } Variable& operator=(bool a_boolean) { reset(); value.b = a_boolean; varType = RawType::kBool; assert(is()); return *this; } Variable& operator=(Variable* a_variable) { assert(a_variable != nullptr); assert(a_variable->varType.GetRawType() != RawType::kVar); reset(); value.v = a_variable; varType = RawType::kVar; return *this; } Variable& operator=(BSTSmartPointer a_struct); Variable& operator=(BSTSmartPointer a_array); F4_HEAP_REDEFINE_NEW(Variable); template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kNone; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kObject; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kString; } template [[nodiscard]] bool is() const // requires(std::same_as || std::same_as) { return varType.GetRawType() == RawType::kInt; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kFloat; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kBool; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kVar; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.GetRawType() == RawType::kStruct; } template [[nodiscard]] bool is() const // requires(std::same_as) { return varType.IsArray(); } TypeInfo GetType() const { return varType; } void reset(); private: friend detail::variable_raw_accessor; using RawType = TypeInfo::RawType; void copy(const Variable& a_rhs); // members TypeInfo varType; // 00 union V { // NOLINTNEXTLINE(modernize-use-equals-default) V() : v(nullptr) {} V(V&& a_rhs) noexcept : v(std::exchange(a_rhs.v, nullptr)) {} ~V() {} // NOLINT(modernize-use-equals-default) V& operator=(V&& a_rhs) noexcept { if (this != std::addressof(a_rhs)) { v = std::exchange(a_rhs.v, nullptr); } return *this; } BSTSmartPointer o; BSFixedString s; std::uint32_t u; std::int32_t i; float f; bool b; Variable* v; BSTSmartPointer t; BSTSmartPointer a; } value; // 08 }; static_assert(sizeof(Variable) == 0x10); namespace detail { struct variable_raw_accessor { public: template [[nodiscard]] static auto&& get_raw(T&& a_var) // requires(std::same_as, Variable>) { return std::forward(a_var).value; } }; } template [[nodiscard]] BSTSmartPointer get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).o; } template [[nodiscard]] BSFixedString get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).s; } template [[nodiscard]] std::uint32_t get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).u; } template [[nodiscard]] std::int32_t get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).i; } template [[nodiscard]] float get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).f; } template [[nodiscard]] bool get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).b; } template [[nodiscard]] Variable* get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).v; } template [[nodiscard]] BSTSmartPointer get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).t; } template [[nodiscard]] BSTSmartPointer get(const Variable& a_var) // requires(std::same_as) { assert(a_var.is()); return detail::variable_raw_accessor::get_raw(a_var).a; } } }