diff --git a/.gitignore b/.gitignore index 62866b9..bf7ff4f 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,4 @@ Module.symvers Mkfile.old dkms.conf +build \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0edd86e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.ignoreCMakeListsMissing": true +} \ No newline at end of file diff --git a/TSE_Base/CMakeLists.txt b/TSE_Base/CMakeLists.txt new file mode 100644 index 0000000..1224fab --- /dev/null +++ b/TSE_Base/CMakeLists.txt @@ -0,0 +1,53 @@ +#cmake version +cmake_minimum_required(VERSION 3.31) + +#project name +project(TSE_Base) + +#cpp settings +find_program(CLANG_C NAMES clang) +find_program(CLANG_CXX NAMES clang++) + +if(CLANG_C AND CLANG_CXX) + message(STATUS "foung Clang, using as Compiler") + set(CMAKE_C_COMPILER ${CLANG_C} CACHE STRING "C Compiler" FORCE) + set(CMAKE_CXX_COMPILER ${CLANG_CXX} CACHE STRING "C++ Compiler" FORCE) +else() + message(STATUS "Clang not found, using Standard-Compiler") +endif() +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +#project output settings +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release") + +#source files +file(GLOB CPP_SOURCE_TSE + "${PROJECT_SOURCE_DIR}/src/*.cpp" + "${PROJECT_SOURCE_DIR}/src/*/*.cpp" + "${PROJECT_SOURCE_DIR}/src/*/*/*.cpp" + "${PROJECT_SOURCE_DIR}/src/*/*/*/*.cpp" + "${PROJECT_SOURCE_DIR}/src/*.c" + "${PROJECT_SOURCE_DIR}/src/*/*.c" + "${PROJECT_SOURCE_DIR}/src/*/*/*.c" + "${PROJECT_SOURCE_DIR}/src/*/*/*/*.c" +) + +#includes +include_directories(${PROJECT_SOURCE_DIR}/src) +include_directories(${PROJECT_SOURCE_DIR}/include) + +#project def +if(Lib) + add_library(TSE_Base SHARED ${CPP_SOURCE_TSE}) +else() + add_library(TSE_Base STATIC ${CPP_SOURCE_TSE}) +endif() + +#flags +target_compile_options(TSE_Base PRIVATE -march=native) \ No newline at end of file diff --git a/TSE_Base/include/LuaBridge.h b/TSE_Base/include/LuaBridge.h new file mode 100644 index 0000000..d8accff --- /dev/null +++ b/TSE_Base/include/LuaBridge.h @@ -0,0 +1,10664 @@ +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2025, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +// clang-format off + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Begin File: Source/LuaBridge/detail/Config.h + +#if !(__cplusplus >= 201703L || (defined(_MSC_VER) && _HAS_CXX17)) +#error LuaBridge 3 requires a compliant C++17 compiler, or C++17 has not been enabled ! +#endif + +#if !defined(LUABRIDGE_HAS_EXCEPTIONS) +#if defined(_MSC_VER) +#if _CPPUNWIND || _HAS_EXCEPTIONS +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#elif defined(__clang__) +#if __EXCEPTIONS && __has_feature(cxx_exceptions) +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#elif defined(__GNUC__) +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#endif +#endif + +#if LUABRIDGE_HAS_EXCEPTIONS +#define LUABRIDGE_IF_EXCEPTIONS(...) __VA_ARGS__ +#define LUABRIDGE_IF_NO_EXCEPTIONS(...) +#else +#define LUABRIDGE_IF_EXCEPTIONS(...) +#define LUABRIDGE_IF_NO_EXCEPTIONS(...) __VA_ARGS__ +#endif + +#if defined(LUAU_FASTMATH_BEGIN) +#define LUABRIDGE_ON_LUAU 1 +#elif defined(LUAJIT_VERSION) +#define LUABRIDGE_ON_LUAJIT 1 +#elif defined(RAVI_OPTION_STRING2) +#define LUABRIDGE_ON_RAVI 1 +#elif defined(LUA_VERSION_NUM) +#define LUABRIDGE_ON_LUA 1 +#else +#error "Lua headers must be included prior to LuaBridge ones" +#endif + +#if defined(__OBJC__) +#define LUABRIDGE_ON_OBJECTIVE_C 1 +#endif + +#if !defined(LUABRIDGE_SAFE_STACK_CHECKS) +#define LUABRIDGE_SAFE_STACK_CHECKS 1 +#endif + +#if !defined(LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING) +#define LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING 0 +#endif + +#if !defined(LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE) +#if LUABRIDGE_HAS_EXCEPTIONS +#define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 1 +#else +#define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 0 +#endif +#endif + +#if !defined(LUABRIDGE_ASSERT) +#if defined(NDEBUG) && !defined(LUABRIDGE_FORCE_ASSERT_RELEASE) +#define LUABRIDGE_ASSERT(expr) ((void)(expr)) +#else +#define LUABRIDGE_ASSERT(expr) assert(expr) +#endif +#endif + + +// End File: Source/LuaBridge/detail/Config.h + +// Begin File: Source/LuaBridge/detail/LuaHelpers.h + +namespace luabridge { + +template +constexpr void unused(Args&&...) +{ +} + +#if LUABRIDGE_ON_LUAU +inline int luaL_ref(lua_State* L, int idx) +{ + LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX); + + const int ref = lua_ref(L, -1); + + lua_pop(L, 1); + + return ref; +} + +inline void luaL_unref(lua_State* L, int idx, int ref) +{ + unused(idx); + + lua_unref(L, ref); +} + +template +inline void* lua_newuserdata_x(lua_State* L, size_t sz) +{ + return lua_newuserdatadtor(L, sz, [](void* x) + { + T* object = static_cast(x); + object->~T(); + }); +} + +inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +{ + lua_pushcfunction(L, fn, debugname); +} + +inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +{ + lua_pushcclosure(L, fn, debugname, n); +} + +inline int lua_error_x(lua_State* L) +{ + lua_error(L); + return 0; +} + +inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +{ + return lua_getinfo(L, level, "nlS", ar); +} + +inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +{ + return lua_getinfo(L, level, what, ar); +} + +#else +using ::luaL_ref; +using ::luaL_unref; + +template +inline void* lua_newuserdata_x(lua_State* L, size_t sz) +{ + return lua_newuserdata(L, sz); +} + +inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +{ + unused(debugname); + + lua_pushcfunction(L, fn); +} + +inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +{ + unused(debugname); + + lua_pushcclosure(L, fn, n); +} + +inline int lua_error_x(lua_State* L) +{ + return lua_error(L); +} + +inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +{ + return lua_getstack(L, level, ar); +} + +inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +{ + lua_getstack(L, level, ar); + return lua_getinfo(L, what, ar); +} + +#endif + +#if LUA_VERSION_NUM < 503 +inline lua_Number to_numberx(lua_State* L, int idx, int* isnum) +{ + lua_Number n = lua_tonumber(L, idx); + + if (isnum) + *isnum = (n != 0 || lua_isnumber(L, idx)); + + return n; +} + +inline lua_Integer to_integerx(lua_State* L, int idx, int* isnum) +{ + int ok = 0; + lua_Number n = to_numberx(L, idx, &ok); + + if (ok) + { + const auto int_n = static_cast(n); + if (n == static_cast(int_n)) + { + if (isnum) + *isnum = 1; + + return int_n; + } + } + + if (isnum) + *isnum = 0; + + return 0; +} + +#endif + +#if LUA_VERSION_NUM < 502 +using lua_Unsigned = std::make_unsigned_t; + +#if ! LUABRIDGE_ON_LUAU +inline int lua_absindex(lua_State* L, int idx) +{ + if (idx > LUA_REGISTRYINDEX && idx < 0) + return lua_gettop(L) + idx + 1; + else + return idx; +} +#endif + +inline int lua_rawgetp(lua_State* L, int idx, const void* p) +{ + idx = lua_absindex(L, idx); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, const_cast(p)); + lua_rawget(L, idx); + return lua_type(L, -1); +} + +inline void lua_rawsetp(lua_State* L, int idx, const void* p) +{ + idx = lua_absindex(L, idx); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, const_cast(p)); + lua_insert(L, -2); + lua_rawset(L, idx); +} + +#define LUA_OPEQ 1 +#define LUA_OPLT 2 +#define LUA_OPLE 3 + +inline int lua_compare(lua_State* L, int idx1, int idx2, int op) +{ + switch (op) + { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + + case LUA_OPLE: + return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); + + default: + return 0; + } +} + +#if ! LUABRIDGE_ON_LUAJIT +inline void* luaL_testudata(lua_State* L, int ud, const char* tname) +{ + void* p = lua_touserdata(L, ud); + if (p == nullptr) + return nullptr; + + if (! lua_getmetatable(L, ud)) + return nullptr; + + luaL_getmetatable(L, tname); + if (! lua_rawequal(L, -1, -2)) + p = nullptr; + + lua_pop(L, 2); + return p; +} +#endif + +inline int get_length(lua_State* L, int idx) +{ + return static_cast(lua_objlen(L, idx)); +} + +#else +inline int get_length(lua_State* L, int idx) +{ + lua_len(L, idx); + const int len = static_cast(luaL_checknumber(L, -1)); + lua_pop(L, 1); + return len; +} + +#endif + +#ifndef LUA_OK +#define LUABRIDGE_LUA_OK 0 +#else +#define LUABRIDGE_LUA_OK LUA_OK +#endif + +template +std::error_code throw_or_error_code(ErrorType error) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(makeErrorCode(error).message().c_str()); +#else + return makeErrorCode(error); +#endif +} + +template +std::error_code throw_or_error_code(lua_State* L, ErrorType error) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(L, makeErrorCode(error)); +#else + return unused(L), makeErrorCode(error); +#endif +} + +template +void throw_or_assert(Args&&... args) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(std::forward(args)...); +#else + unused(std::forward(args)...); + LUABRIDGE_ASSERT(false); +#endif +} + +template +void pushunsigned(lua_State* L, T value) +{ + static_assert(std::is_unsigned_v); + + lua_pushinteger(L, static_cast(value)); +} + +inline lua_Number tonumber(lua_State* L, int idx, int* isnum) +{ +#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502 + return lua_tonumberx(L, idx, isnum); +#else + return to_numberx(L, idx, isnum); +#endif +} + +inline lua_Integer tointeger(lua_State* L, int idx, int* isnum) +{ +#if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502 + return lua_tointegerx(L, idx, isnum); +#else + return to_integerx(L, idx, isnum); +#endif +} + +inline constexpr char main_thread_name[] = "__luabridge_main_thread"; + +inline void register_main_thread(lua_State* threadL) +{ +#if LUA_VERSION_NUM < 502 + if (threadL == nullptr) + lua_pushnil(threadL); + else + lua_pushthread(threadL); + + lua_setglobal(threadL, main_thread_name); +#else + unused(threadL); +#endif +} + +inline lua_State* main_thread(lua_State* threadL) +{ +#if LUA_VERSION_NUM < 502 + lua_getglobal(threadL, main_thread_name); + if (lua_isthread(threadL, -1)) + { + auto L = lua_tothread(threadL, -1); + lua_pop(threadL, 1); + return L; + } + LUABRIDGE_ASSERT(false); + lua_pop(threadL, 1); + return threadL; +#else + lua_rawgeti(threadL, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); + lua_State* L = lua_tothread(threadL, -1); + lua_pop(threadL, 1); + return L; +#endif +} + +inline int rawgetfield(lua_State* L, int index, const char* key) +{ + LUABRIDGE_ASSERT(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); +#if LUA_VERSION_NUM <= 502 + lua_rawget(L, index); + return lua_type(L, -1); +#else + return lua_rawget(L, index); +#endif +} + +inline void rawsetfield(lua_State* L, int index, const char* key) +{ + LUABRIDGE_ASSERT(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); + lua_insert(L, -2); + lua_rawset(L, index); +} + +[[nodiscard]] inline bool isfulluserdata(lua_State* L, int index) +{ + return lua_isuserdata(L, index) && !lua_islightuserdata(L, index); +} + +[[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2) +{ + return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX); +} + +[[nodiscard]] inline int table_length(lua_State* L, int index) +{ + LUABRIDGE_ASSERT(lua_istable(L, index)); + + int items_count = 0; + + lua_pushnil(L); + while (lua_next(L, index) != 0) + { + ++items_count; + + lua_pop(L, 1); + } + + return items_count; +} + +template +[[nodiscard]] T* align(void* ptr) noexcept +{ + const auto address = reinterpret_cast(ptr); + + const auto offset = address % alignof(T); + const auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset); + + return reinterpret_cast(aligned_address); +} + +template , int> = 0> +[[nodiscard]] bool is_aligned(T address) noexcept +{ + static_assert(Alignment > 0u); + + return (reinterpret_cast(address) & (Alignment - 1u)) == 0u; +} + +template +[[nodiscard]] constexpr size_t maximum_space_needed_to_align() noexcept +{ + return sizeof(T) + alignof(T) - 1; +} + +template +int lua_deleteuserdata_aligned(lua_State* L) +{ + LUABRIDGE_ASSERT(isfulluserdata(L, 1)); + + T* aligned = align(lua_touserdata(L, 1)); + aligned->~T(); + + return 0; +} + +template +void* lua_newuserdata_aligned(lua_State* L, Args&&... args) +{ + using U = std::remove_reference_t; + +#if LUABRIDGE_ON_LUAU + void* pointer = lua_newuserdatadtor(L, maximum_space_needed_to_align(), [](void* x) + { + U* aligned = align(x); + aligned->~U(); + }); +#else + void* pointer = lua_newuserdata_x(L, maximum_space_needed_to_align()); + + lua_newtable(L); + lua_pushcfunction_x(L, &lua_deleteuserdata_aligned, ""); + rawsetfield(L, -2, "__gc"); + lua_setmetatable(L, -2); +#endif + + U* aligned = align(pointer); + + new (aligned) U(std::forward(args)...); + + return pointer; +} + +inline int raise_lua_error(lua_State* L, const char* fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + + const char* message = lua_tostring(L, -1); + if (message != nullptr) + { + if (auto str = std::string_view(message); !str.empty() && str[0] == '[') + return lua_error_x(L); + } + + bool pushed_error = false; + for (int level = 1; level <= 2; ++level) + { + lua_Debug ar; + +#if LUABRIDGE_ON_LUAU + if (lua_getinfo(L, level, "sl", &ar) == 0) + continue; +#else + if (lua_getstack(L, level, &ar) == 0 || lua_getinfo(L, "Sl", &ar) == 0) + continue; +#endif + + if (ar.currentline <= 0) + continue; + + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + pushed_error = true; + + break; + } + + if (! pushed_error) + lua_pushliteral(L, ""); + + lua_pushvalue(L, -2); + lua_remove(L, -3); + lua_concat(L, 2); + + return lua_error_x(L); +} + +template +constexpr bool is_integral_representable_by(T value) +{ + constexpr bool same_signedness = (std::is_unsigned_v && std::is_unsigned_v) + || (!std::is_unsigned_v && !std::is_unsigned_v); + + if constexpr (sizeof(T) == sizeof(U)) + { + if constexpr (same_signedness) + return true; + + if constexpr (std::is_unsigned_v) + return value <= static_cast((std::numeric_limits::max)()); + + return value >= static_cast((std::numeric_limits::min)()) + && static_cast(value) <= (std::numeric_limits::max)(); + } + + if constexpr (sizeof(T) < sizeof(U)) + { + return static_cast(value) >= (std::numeric_limits::min)() + && static_cast(value) <= (std::numeric_limits::max)(); + } + + if constexpr (std::is_unsigned_v) + return value <= static_cast((std::numeric_limits::max)()); + + return value >= static_cast((std::numeric_limits::min)()) + && value <= static_cast((std::numeric_limits::max)()); +} + +template +bool is_integral_representable_by(lua_State* L, int index) +{ + int isValid = 0; + + const auto value = tointeger(L, index, &isValid); + + return isValid ? is_integral_representable_by(value) : false; +} + +template +constexpr bool is_floating_point_representable_by(T value) +{ + if constexpr (sizeof(T) == sizeof(U)) + return true; + + if constexpr (sizeof(T) < sizeof(U)) + return static_cast(value) >= -(std::numeric_limits::max)() + && static_cast(value) <= (std::numeric_limits::max)(); + + return value >= static_cast(-(std::numeric_limits::max)()) + && value <= static_cast((std::numeric_limits::max)()); +} + +template +bool is_floating_point_representable_by(lua_State* L, int index) +{ + int isValid = 0; + + const auto value = tonumber(L, index, &isValid); + + return isValid ? is_floating_point_representable_by(value) : false; +} + +} + + +// End File: Source/LuaBridge/detail/LuaHelpers.h + +// Begin File: Source/LuaBridge/detail/Errors.h + +namespace luabridge { + +namespace detail { + +static inline constexpr char error_lua_stack_overflow[] = "stack overflow"; + +} + +enum class ErrorCode +{ + ClassNotRegistered = 1, + + LuaStackOverflow, + + LuaFunctionCallFailed, + + IntegerDoesntFitIntoLuaInteger, + + FloatingPointDoesntFitIntoLuaNumber, + + InvalidTypeCast, + + InvalidTableSizeInCast +}; + +namespace detail { +struct ErrorCategory : std::error_category +{ + const char* name() const noexcept override + { + return "luabridge"; + } + + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case ErrorCode::ClassNotRegistered: + return "The class is not registered in LuaBridge"; + + case ErrorCode::LuaStackOverflow: + return "The lua stack has overflow"; + + case ErrorCode::LuaFunctionCallFailed: + return "The lua function invocation raised an error"; + + case ErrorCode::IntegerDoesntFitIntoLuaInteger: + return "The native integer can't fit inside a lua integer"; + + case ErrorCode::FloatingPointDoesntFitIntoLuaNumber: + return "The native floating point can't fit inside a lua number"; + + case ErrorCode::InvalidTypeCast: + return "The lua object can't be cast to desired type"; + + case ErrorCode::InvalidTableSizeInCast: + return "The lua table has different size than expected"; + + default: + return "Unknown error"; + } + } + + static const ErrorCategory& getInstance() noexcept + { + static ErrorCategory category; + return category; + } +}; +} + +inline std::error_code makeErrorCode(ErrorCode e) +{ + return { static_cast(e), detail::ErrorCategory::getInstance() }; +} + +inline std::error_code make_error_code(ErrorCode e) +{ + return { static_cast(e), detail::ErrorCategory::getInstance() }; +} +} + +namespace std { +template <> struct is_error_code_enum : true_type {}; +} + + +// End File: Source/LuaBridge/detail/Errors.h + +// Begin File: Source/LuaBridge/detail/Expected.h + +#if LUABRIDGE_HAS_EXCEPTIONS +#endif + +namespace luabridge { +namespace detail { +using std::swap; + +template +T* construct_at(T* ptr, Args&&... args) noexcept(std::is_nothrow_constructible::value) +{ + return static_cast(::new (const_cast(static_cast(ptr))) T(std::forward(args)...)); +} + +template +struct is_swappable_with_impl : std::false_type +{ +}; + +template +struct is_swappable_with_impl(), std::declval()))>> + : std::true_type +{ +}; + +template +struct is_nothrow_swappable_with_impl +{ + static constexpr bool value = noexcept(swap(std::declval(), std::declval())) && noexcept(swap(std::declval(), std::declval())); + + using type = std::bool_constant; +}; + +template +struct is_swappable_with + : std::conjunction< + is_swappable_with_impl, std::add_lvalue_reference_t>, + is_swappable_with_impl, std::add_lvalue_reference_t>>::type +{ +}; + +template +struct is_nothrow_swappable_with + : std::conjunction, is_nothrow_swappable_with_impl>::type +{ +}; + +template +struct is_nothrow_swappable + : std::is_nothrow_swappable_with, std::add_lvalue_reference_t> +{ +}; + +template +struct has_member_message : std::false_type +{ +}; + +template +struct has_member_message().message())>> : std::true_type +{ +}; + +template +inline static constexpr bool has_member_message_v = has_member_message::value; +} + +template +class Expected; + +struct UnexpectType +{ + constexpr UnexpectType() = default; +}; + +static constexpr auto unexpect = UnexpectType(); + +namespace detail { +template , bool = (std::is_void_v || std::is_trivial_v) && std::is_trivial_v> +union expected_storage +{ +public: + template >> + constexpr expected_storage() noexcept + : value_() + { + } + + template + constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept + : value_(std::forward(args)...) + { + } + + template + constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept + : error_(std::forward(args)...) + { + } + + ~expected_storage() = default; + + constexpr const T& value() const noexcept + { + return value_; + } + + constexpr T& value() noexcept + { + return value_; + } + + constexpr const E& error() const noexcept + { + return error_; + } + + constexpr E& error() noexcept + { + return error_; + } + +private: + T value_; + E error_; +}; + +template +union expected_storage +{ +public: + constexpr expected_storage() noexcept + : dummy_(0) + { + } + + template + constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept + : error_(std::forward(args)...) + { + } + + ~expected_storage() = default; + + constexpr const E& error() const noexcept + { + return error_; + } + + constexpr E& error() noexcept + { + return error_; + } + +private: + char dummy_; + E error_; +}; + +template +union expected_storage +{ +public: + constexpr expected_storage() noexcept(std::is_nothrow_default_constructible_v) + : value_() + { + } + + template + constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : value_(std::forward(args)...) + { + } + + template + constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : error_(std::forward(args)...) + { + } + + ~expected_storage() + { + } + + constexpr const T& value() const noexcept + { + return value_; + } + + constexpr T& value() noexcept + { + return value_; + } + + constexpr const E& error() const noexcept + { + return error_; + } + + constexpr E& error() noexcept + { + return error_; + } + +private: + T value_; + E error_; +}; + +template +union expected_storage +{ +public: + constexpr explicit expected_storage() noexcept + : dummy_(0) + { + } + + template + constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : value_(std::forward(args)...) + { + } + + template + constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : error_(std::forward(args)...) + { + } + + ~expected_storage() + { + } + + constexpr const T& value() const noexcept + { + return value_; + } + + constexpr T& value() noexcept + { + return value_; + } + + constexpr const E& error() const noexcept + { + return error_; + } + + constexpr E& error() noexcept + { + return error_; + } + +private: + char dummy_; + T value_; + E error_; +}; + +template +union expected_storage +{ +public: + constexpr expected_storage() noexcept + : dummy_(0) + { + } + + template + constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : error_(std::forward(args)...) + { + } + + ~expected_storage() = default; + + constexpr const E& error() const noexcept + { + return error_; + } + + constexpr E& error() noexcept + { + return error_; + } + +private: + char dummy_; + E error_; +}; + +template +class expected_base_trivial +{ + using this_type = expected_base_trivial; + +protected: + using storage_type = expected_storage; + + constexpr expected_base_trivial() noexcept + : valid_(true) + { + } + + template + constexpr expected_base_trivial(std::in_place_t, Args&&... args) noexcept + : storage_(std::in_place, std::forward(args)...) + , valid_(true) + { + } + + template + constexpr expected_base_trivial(UnexpectType, Args&&... args) noexcept + : storage_(unexpect, std::forward(args)...) + , valid_(false) + { + } + + expected_base_trivial(const expected_base_trivial& other) noexcept + { + if (other.valid_) + { + construct(std::in_place, other.value()); + } + else + { + construct(unexpect, other.error()); + } + } + + expected_base_trivial(expected_base_trivial&& other) noexcept + { + if (other.valid_) + { + construct(std::in_place, std::move(other.value())); + } + else + { + construct(unexpect, std::move(other.error())); + } + } + + ~expected_base_trivial() noexcept = default; + + constexpr const T& value() const noexcept + { + return storage_.value(); + } + + constexpr T& value() noexcept + { + return storage_.value(); + } + + constexpr const E& error() const noexcept + { + return storage_.error(); + } + + constexpr E& error() noexcept + { + return storage_.error(); + } + + constexpr const T* valuePtr() const noexcept + { + return std::addressof(value()); + } + + constexpr T* valuePtr() noexcept + { + return std::addressof(value()); + } + + constexpr const E* errorPtr() const noexcept + { + return std::addressof(error()); + } + + constexpr E* errorPtr() noexcept + { + return std::addressof(error()); + } + + constexpr bool valid() const noexcept + { + return valid_; + } + + template + inline T& construct(std::in_place_t, Args&&... args) noexcept + { + valid_ = true; + return *detail::construct_at(valuePtr(), std::forward(args)...); + } + + template + inline E& construct(UnexpectType, Args&&... args) noexcept + { + valid_ = false; + return *detail::construct_at(errorPtr(), std::forward(args)...); + } + + inline void destroy() noexcept + { + } + +private: + storage_type storage_; + bool valid_; +}; + +template +class expected_base_non_trivial +{ + using this_type = expected_base_non_trivial; + +protected: + using storage_type = expected_storage; + + constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) + : valid_(true) + { + } + + template + constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(std::in_place, std::forward(args)...) + , valid_(true) + { + } + + template + constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(unexpect, std::forward(args)...) + , valid_(false) + { + } + + expected_base_non_trivial(const expected_base_non_trivial& other) + { + if (other.valid_) + { + construct(std::in_place, other.value()); + } + else + { + construct(unexpect, other.error()); + } + } + + expected_base_non_trivial(expected_base_non_trivial&& other) noexcept + { + if (other.valid_) + { + construct(std::in_place, std::move(other.value())); + } + else + { + construct(unexpect, std::move(other.error())); + } + } + + ~expected_base_non_trivial() + { + destroy(); + } + + constexpr const T& value() const noexcept + { + return storage_.value(); + } + + constexpr T& value() noexcept + { + return storage_.value(); + } + + constexpr const E& error() const noexcept + { + return storage_.error(); + } + + constexpr E& error() noexcept + { + return storage_.error(); + } + + constexpr const T* valuePtr() const noexcept + { + return std::addressof(value()); + } + + constexpr T* valuePtr() noexcept + { + return std::addressof(value()); + } + + constexpr const E* errorPtr() const noexcept + { + return std::addressof(error()); + } + + constexpr E* errorPtr() noexcept + { + return std::addressof(error()); + } + + constexpr bool valid() const noexcept + { + return valid_; + } + + template + inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = true; + return *detail::construct_at(valuePtr(), std::forward(args)...); + } + + template + inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = false; + return *detail::construct_at(errorPtr(), std::forward(args)...); + } + + inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) + { + if (valid_) + { + std::destroy_at(valuePtr()); + } + else + { + std::destroy_at(errorPtr()); + } + } + +private: + storage_type storage_; + bool valid_; +}; + +template +class expected_base_non_trivial +{ + using this_type = expected_base_non_trivial; + +protected: + using storage_type = expected_storage; + + constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) + : valid_(true) + { + } + + template + constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(std::in_place, std::forward(args)...) + , valid_(true) + { + } + + template + constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(unexpect, std::forward(args)...) + , valid_(false) + { + } + + expected_base_non_trivial(const expected_base_non_trivial& other) = delete; + + expected_base_non_trivial(expected_base_non_trivial&& other) noexcept + { + if (other.valid_) + { + construct(std::in_place, std::move(other.value())); + } + else + { + construct(unexpect, std::move(other.error())); + } + } + + ~expected_base_non_trivial() + { + destroy(); + } + + constexpr const T& value() const noexcept + { + return storage_.value(); + } + + constexpr T& value() noexcept + { + return storage_.value(); + } + + constexpr const E& error() const noexcept + { + return storage_.error(); + } + + constexpr E& error() noexcept + { + return storage_.error(); + } + + constexpr const T* valuePtr() const noexcept + { + return std::addressof(value()); + } + + constexpr T* valuePtr() noexcept + { + return std::addressof(value()); + } + + constexpr const E* errorPtr() const noexcept + { + return std::addressof(error()); + } + + constexpr E* errorPtr() noexcept + { + return std::addressof(error()); + } + + constexpr bool valid() const noexcept + { + return valid_; + } + + template + inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = true; + return *detail::construct_at(valuePtr(), std::forward(args)...); + } + + template + inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = false; + return *detail::construct_at(errorPtr(), std::forward(args)...); + } + + inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) + { + if (valid_) + { + std::destroy_at(valuePtr()); + } + else + { + std::destroy_at(errorPtr()); + } + } + +private: + storage_type storage_; + bool valid_; +}; + +template +class expected_base_non_trivial +{ + using this_type = expected_base_non_trivial; + +protected: + using storage_type = expected_storage; + + template >> + constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) + : valid_(true) + { + } + + template + constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(std::in_place, std::forward(args)...) + , valid_(true) + { + } + + template + constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(unexpect, std::forward(args)...) + , valid_(false) + { + } + + expected_base_non_trivial(const expected_base_non_trivial& other) + { + if (other.valid_) + { + construct(std::in_place, other.value()); + } + else + { + construct(unexpect, other.error()); + } + } + + expected_base_non_trivial(expected_base_non_trivial&& other) = delete; + + ~expected_base_non_trivial() + { + destroy(); + } + + constexpr const T& value() const noexcept + { + return storage_.value(); + } + + constexpr T& value() noexcept + { + return storage_.value(); + } + + constexpr const E& error() const noexcept + { + return storage_.error(); + } + + constexpr E& error() noexcept + { + return storage_.error(); + } + + constexpr const T* valuePtr() const noexcept + { + return std::addressof(value()); + } + + constexpr T* valuePtr() noexcept + { + return std::addressof(value()); + } + + constexpr const E* errorPtr() const noexcept + { + return std::addressof(error()); + } + + constexpr E* errorPtr() noexcept + { + return std::addressof(error()); + } + + constexpr bool valid() const noexcept + { + return valid_; + } + + template + inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = true; + return *detail::construct_at(valuePtr(), std::forward(args)...); + } + + template + inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = false; + return *detail::construct_at(errorPtr(), std::forward(args)...); + } + + inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) + { + if (valid_) + { + std::destroy_at(valuePtr()); + } + else + { + std::destroy_at(errorPtr()); + } + } + +private: + storage_type storage_; + bool valid_; +}; + +template +class expected_base_non_trivial +{ + using this_type = expected_base_non_trivial; + +protected: + using storage_type = expected_storage; + + template >> + constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) + : valid_(true) + { + } + + template + constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(std::in_place, std::forward(args)...) + , valid_(true) + { + } + + template + constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : storage_(unexpect, std::forward(args)...) + , valid_(false) + { + } + + expected_base_non_trivial(const expected_base_non_trivial& other) = delete; + + expected_base_non_trivial(expected_base_non_trivial&& other) = delete; + + ~expected_base_non_trivial() + { + destroy(); + } + + constexpr const T& value() const noexcept + { + return storage_.value(); + } + + constexpr T& value() noexcept + { + return storage_.value(); + } + + constexpr const E& error() const noexcept + { + return storage_.error(); + } + + constexpr E& error() noexcept + { + return storage_.error(); + } + + constexpr const T* valuePtr() const noexcept + { + return std::addressof(value()); + } + + constexpr T* valuePtr() noexcept + { + return std::addressof(value()); + } + + constexpr const E* errorPtr() const noexcept + { + return std::addressof(error()); + } + + constexpr E* errorPtr() noexcept + { + return std::addressof(error()); + } + + constexpr bool valid() const noexcept + { + return valid_; + } + + template + inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = true; + return *detail::construct_at(valuePtr(), std::forward(args)...); + } + + template + inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + valid_ = false; + return *detail::construct_at(errorPtr(), std::forward(args)...); + } + + inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) + { + if (valid_) + { + std::destroy_at(valuePtr()); + } + else + { + std::destroy_at(errorPtr()); + } + } + +private: + storage_type storage_; + bool valid_; +}; + +template +using expected_base = std::conditional_t< + (std::is_void_v || std::is_trivially_destructible_v) && std::is_trivially_destructible_v, + expected_base_trivial, + expected_base_non_trivial>; + +} + +template +class Unexpected +{ + static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); + +public: + Unexpected() = delete; + + constexpr explicit Unexpected(E&& e) noexcept(std::is_nothrow_move_constructible_v) + : error_(std::move(e)) + { + } + + constexpr explicit Unexpected(const E& e) noexcept(std::is_nothrow_copy_constructible_v) + : error_(e) + { + } + + constexpr const E& value() const& noexcept + { + return error_; + } + + constexpr E& value() & noexcept + { + return error_; + } + + constexpr const E&& value() const&& noexcept + { + return std::move(error_); + } + + constexpr E&& value() && noexcept + { + return std::move(error_); + } + +private: + E error_; +}; + +template +constexpr bool operator==(const Unexpected& lhs, const Unexpected& rhs) noexcept +{ + return lhs.value() == rhs.value(); +} + +template +constexpr bool operator!=(const Unexpected& lhs, const Unexpected& rhs) noexcept +{ + return lhs.value() != rhs.value(); +} + +template +constexpr inline Unexpected> makeUnexpected(E&& error) noexcept(std::is_nothrow_constructible_v>, E>) +{ + return Unexpected>{ std::forward(error) }; +} + +#if LUABRIDGE_HAS_EXCEPTIONS +template +class BadExpectedAccess; + +template <> +class BadExpectedAccess : public std::runtime_error +{ + template + friend class BadExpectedAccess; + + BadExpectedAccess(std::in_place_t) noexcept + : std::runtime_error("Bad access to expected value") + { + } + +public: + BadExpectedAccess() noexcept + : BadExpectedAccess(std::in_place) + { + } + + explicit BadExpectedAccess(const std::string& message) noexcept + : std::runtime_error(message) + { + } +}; + +template +class BadExpectedAccess : public std::runtime_error +{ +public: + explicit BadExpectedAccess(E error) noexcept(std::is_nothrow_constructible_v) + : std::runtime_error([](const E& error) + { + if constexpr (detail::has_member_message_v) + return error.message(); + else + return "Bad access to expected value"; + }(error)) + , error_(std::move(error)) + { + } + + const E& error() const& noexcept + { + return error_; + } + + E& error() & noexcept + { + return error_; + } + + E&& error() && noexcept + { + return std::move(error_); + } + +private: + E error_; +}; +#endif + +template +struct is_expected : std::false_type +{ +}; + +template +struct is_expected> : std::true_type +{ +}; +template +struct is_unexpected : std::false_type +{ +}; + +template +struct is_unexpected> : std::true_type +{ +}; + +template +class Expected : public detail::expected_base, std::is_move_constructible_v> +{ + static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); + + using base_type = detail::expected_base, std::is_move_constructible_v>; + using this_type = Expected; + +public: + using value_type = T; + + using error_type = E; + + using unexpected_type = Unexpected; + + template + struct rebind + { + using type = Expected; + }; + + template >> + constexpr Expected() noexcept(std::is_nothrow_default_constructible_v) + : base_type() + { + } + + constexpr Expected(const Expected& other) noexcept(std::is_nothrow_copy_constructible_v) = default; + + constexpr Expected(Expected&& other) noexcept(std::is_nothrow_move_constructible_v) = default; + + template + Expected(const Expected& other) + { + if (other.hasValue()) + { + this->construct(std::in_place, other.value()); + } + else + { + this->construct(unexpect, other.error()); + } + } + + template + Expected(Expected&& other) + { + if (other.hasValue()) + { + this->construct(std::in_place, std::move(other.value())); + } + else + { + this->construct(unexpect, std::move(other.error())); + } + } + + template && std::is_constructible_v && !std::is_same_v, std::in_place_t> && !is_expected>::value && !is_unexpected>::value, int> = 0> + constexpr Expected(U&& value) noexcept(std::is_nothrow_constructible_v) + : base_type(std::in_place, std::forward(value)) + { + } + + template + constexpr explicit Expected(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : base_type(std::in_place, std::forward(args)...) + { + } + + template + constexpr explicit Expected(std::in_place_t, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) + : base_type(std::in_place, ilist, std::forward(args)...) + { + } + + template + constexpr Expected(const Unexpected& u) noexcept(std::is_nothrow_constructible_v) + : base_type(unexpect, u.value()) + { + } + + template + constexpr Expected(Unexpected&& u) noexcept(std::is_nothrow_constructible_v) + : base_type(unexpect, std::move(u.value())) + { + } + + template + constexpr explicit Expected(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) + : base_type(unexpect, std::forward(args)...) + { + } + + template + constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) + : base_type(unexpect, ilist, std::forward(args)...) + { + } + + Expected& operator=(const Expected& other) + { + if (other.hasValue()) + { + assign(std::in_place, other.value()); + } + else + { + assign(unexpect, other.error()); + } + + return *this; + } + + Expected& operator=(Expected&& other) noexcept + { + if (other.hasValue()) + { + assign(std::in_place, std::move(other.value())); + } + else + { + assign(unexpect, std::move(other.error())); + } + + return *this; + } + + template >::value && !is_unexpected>::value, int> = 0> + Expected& operator=(U&& value) + { + assign(std::in_place, std::forward(value)); + return *this; + } + + template + Expected& operator=(const Unexpected& u) + { + assign(unexpect, u.value()); + return *this; + } + + template + Expected& operator=(Unexpected&& u) + { + assign(unexpect, std::move(u.value())); + return *this; + } + + template + T& emplace(Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, std::forward(args)...))) + { + return assign(std::in_place, std::forward(args)...); + } + + template + T& emplace(std::initializer_list ilist, Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, ilist, std::forward(args)...))) + { + return assign(std::in_place, ilist, std::forward(args)...); + } + + void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value && detail::is_nothrow_swappable::value) + { + using std::swap; + + if (hasValue()) + { + if (other.hasValue()) + { + swap(value(), other.value()); + } + else + { + E error = std::move(other.error()); + other.assign(std::in_place, std::move(value())); + assign(unexpect, std::move(error)); + } + } + else + { + if (other.hasValue()) + { + other.swap(*this); + } + else + { + swap(error(), other.error()); + } + } + } + + constexpr const T* operator->() const + { + return base_type::valuePtr(); + } + + constexpr T* operator->() + { + return base_type::valuePtr(); + } + + constexpr const T& operator*() const& + { + return value(); + } + + constexpr T& operator*() & + { + return value(); + } + + constexpr const T&& operator*() const&& + { + return std::move(value()); + } + + constexpr T&& operator*() && + { + return std::move(value()); + } + + constexpr explicit operator bool() const noexcept + { + return hasValue(); + } + + constexpr bool hasValue() const noexcept + { + return base_type::valid(); + } + + constexpr const T& value() const& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) + { +#if LUABRIDGE_HAS_EXCEPTIONS + if (!hasValue()) + throw BadExpectedAccess(error()); +#endif + + return base_type::value(); + } + + constexpr T& value() & LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) + { +#if LUABRIDGE_HAS_EXCEPTIONS + if (!hasValue()) + throw BadExpectedAccess(error()); +#endif + + return base_type::value(); + } + + constexpr const T&& value() const&& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) + { +#if LUABRIDGE_HAS_EXCEPTIONS + if (!hasValue()) + throw BadExpectedAccess(error()); +#endif + + return std::move(base_type::value()); + } + + constexpr T&& value() && LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) + { +#if LUABRIDGE_HAS_EXCEPTIONS + if (!hasValue()) + throw BadExpectedAccess(error()); +#endif + return std::move(base_type::value()); + } + + constexpr const E& error() const& noexcept + { + return base_type::error(); + } + + constexpr E& error() & noexcept + { + return base_type::error(); + } + + constexpr const E&& error() const&& noexcept + { + return std::move(base_type::error()); + } + + constexpr E&& error() && noexcept + { + return std::move(base_type::error()); + } + + template + constexpr T valueOr(U&& defaultValue) const& + { + return hasValue() ? value() : static_cast(std::forward(defaultValue)); + } + + template + T valueOr(U&& defaultValue) && + { + return hasValue() ? std::move(value()) : static_cast(std::forward(defaultValue)); + } + +private: + template + auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) + -> decltype(std::declval().construct(tag, std::forward(args)...)) + { + this->destroy(); + + return this->construct(tag, std::forward(args)...); + } +}; + +template +class Expected : public detail::expected_base, std::is_move_constructible_v> +{ + static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); + + using base_type = detail::expected_base, std::is_move_constructible_v>; + using this_type = Expected; + +public: + using value_type = void; + + using error_type = E; + + using unexpected_type = Unexpected; + + template + struct rebind + { + using type = Expected; + }; + + constexpr Expected() = default; + + constexpr Expected(const Expected& other) = default; + + constexpr Expected(Expected&& other) = default; + + template + Expected(const Expected& other) + { + if (other.hasValue()) + { + this->valid_ = true; + } + else + { + this->construct(unexpect, other.error()); + } + } + + template + Expected(Expected&& other) + { + if (other.hasValue()) + { + this->valid_ = true; + } + else + { + this->construct(unexpect, std::move(other.error())); + } + } + + template + constexpr Expected(const Unexpected& u) + : base_type(unexpect, u.value()) + { + } + + template + constexpr Expected(Unexpected&& u) + : base_type(unexpect, std::move(u.value())) + { + } + + template + constexpr explicit Expected(UnexpectType, Args&&... args) + : base_type(unexpect, std::forward(args)...) + { + } + + template + constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) + : base_type(unexpect, ilist, std::forward(args)...) + { + } + + Expected& operator=(const Expected& other) + { + if (other.hasValue()) + { + assign(std::in_place); + } + else + { + assign(unexpect, other.error()); + } + + return *this; + } + + Expected& operator=(Expected&& other) + { + if (other.hasValue()) + { + assign(std::in_place); + } + else + { + assign(unexpect, std::move(other.error())); + } + + return *this; + } + + template + Expected& operator=(const Unexpected& u) + { + assign(unexpect, u.value()); + return *this; + } + + template + Expected& operator=(Unexpected&& u) + { + assign(unexpect, std::move(u.value())); + return *this; + } + + void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value) + { + using std::swap; + + if (hasValue()) + { + if (!other.hasValue()) + { + assign(unexpect, std::move(other.error())); + other.assign(std::in_place); + } + } + else + { + if (other.hasValue()) + { + other.swap(*this); + } + else + { + swap(error(), other.error()); + } + } + } + + constexpr explicit operator bool() const noexcept + { + return hasValue(); + } + + constexpr bool hasValue() const noexcept + { + return base_type::valid(); + } + + constexpr const E& error() const& noexcept + { + return base_type::error(); + } + + constexpr E& error() & noexcept + { + return base_type::error(); + } + + constexpr const E&& error() const&& noexcept + { + return std::move(base_type::error()); + } + + constexpr E&& error() && noexcept + { + return std::move(base_type::error()); + } + +private: + template + void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) + { + this->destroy(); + this->construct(tag, std::forward(args)...); + } +}; + +template +constexpr bool operator==(const Expected& lhs, const Expected& rhs) +{ + return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); +} + +template +constexpr bool operator==(const Expected& lhs, const Expected& rhs) +{ + return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); +} + +template +constexpr bool operator!=(const Expected& lhs, const Expected& rhs) +{ + return !(lhs == rhs); +} + +template +constexpr bool operator==(const Expected& lhs, const T& rhs) +{ + return lhs ? *lhs == rhs : false; +} + +template +constexpr bool operator==(const T& lhs, const Expected& rhs) +{ + return rhs == lhs; +} + +template +constexpr bool operator!=(const Expected& lhs, const T& rhs) +{ + return !(lhs == rhs); +} + +template +constexpr bool operator!=(const T& lhs, const Expected& rhs) +{ + return rhs != lhs; +} + +template +constexpr bool operator==(const Expected& lhs, const Unexpected& rhs) +{ + return lhs ? false : lhs.error() == rhs.value(); +} + +template +constexpr bool operator==(const Unexpected& lhs, const Expected& rhs) +{ + return rhs == lhs; +} + +template +constexpr bool operator!=(const Expected& lhs, const Unexpected& rhs) +{ + return !(lhs == rhs); +} + +template +constexpr bool operator!=(const Unexpected& lhs, const Expected& rhs) +{ + return rhs != lhs; +} +} + + +// End File: Source/LuaBridge/detail/Expected.h + +// Begin File: Source/LuaBridge/detail/Result.h + +namespace luabridge { + +struct Result +{ + Result() noexcept = default; + + Result(std::error_code ec) noexcept + : m_ec(ec) + { + } + + Result(const Result&) noexcept = default; + Result(Result&&) noexcept = default; + Result& operator=(const Result&) noexcept = default; + Result& operator=(Result&&) noexcept = default; + + explicit operator bool() const noexcept + { + return !m_ec; + } + + std::error_code error() const noexcept + { + return m_ec; + } + + operator std::error_code() const noexcept + { + return m_ec; + } + + std::string message() const + { + return m_ec.message(); + } + +#if LUABRIDGE_HAS_EXCEPTIONS + void throw_on_error() const + { + if (m_ec) + throw std::system_error(m_ec); + } +#endif + +private: + std::error_code m_ec; +}; + +template +struct TypeResult +{ + TypeResult() noexcept = default; + + template && !std::is_same_v, std::error_code>>> + TypeResult(U&& value) noexcept + : m_value(std::in_place, std::forward(value)) + { + } + + TypeResult(std::error_code ec) noexcept + : m_value(makeUnexpected(ec)) + { + } + + TypeResult(const TypeResult&) = default; + TypeResult(TypeResult&&) = default; + TypeResult& operator=(const TypeResult&) = default; + TypeResult& operator=(TypeResult&&) = default; + + explicit operator bool() const noexcept + { + return m_value.hasValue(); + } + + const T& value() const + { + return m_value.value(); + } + + T& operator*() & + { + return m_value.value(); + } + + T operator*() && + { + return std::move(m_value.value()); + } + + const T& operator*() const& + { + return m_value.value(); + } + + T operator*() const&& + { + return std::move(m_value.value()); + } + + template + T valueOr(U&& defaultValue) const& + { + return m_value.valueOr(std::forward(defaultValue)); + } + + template + T valueOr(U&& defaultValue) && + { + return m_value.valueOr(std::forward(defaultValue)); + } + + std::error_code error() const + { + return m_value.error(); + } + + operator std::error_code() const + { + return m_value.error(); + } + + std::string message() const + { + return m_value.error().message(); + } + +#if LUABRIDGE_HAS_EXCEPTIONS + void throw_on_error() const + { + if (! m_value.hasValue()) + throw std::system_error(m_value.error()); + } +#endif + +private: + Expected m_value; +}; + +template +inline bool operator==(const TypeResult& lhs, const U& rhs) noexcept +{ + return lhs ? *lhs == rhs : false; +} + +template +inline bool operator==(const U& lhs, const TypeResult& rhs) noexcept +{ + return rhs == lhs; +} + +template +inline bool operator!=(const TypeResult& lhs, const U& rhs) noexcept +{ + return !(lhs == rhs); +} + +template +inline bool operator!=(const U& lhs, const TypeResult& rhs) noexcept +{ + return !(rhs == lhs); +} + +} + + +// End File: Source/LuaBridge/detail/Result.h + +// Begin File: Source/LuaBridge/detail/ClassInfo.h + +#if defined __clang__ || defined __GNUC__ +#define LUABRIDGE_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '=' +#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX ']' +#elif defined _MSC_VER +#define LUABRIDGE_PRETTY_FUNCTION __FUNCSIG__ +#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '<' +#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX '>' +#endif + +namespace luabridge { +namespace detail { + +[[nodiscard]] constexpr auto fnv1a(const char* s, std::size_t count) noexcept +{ + uint32_t seed = 2166136261u; + + for (std::size_t i = 0; i < count; ++i) + seed = static_cast(static_cast(seed ^ static_cast(*s++)) * 16777619u); + + if constexpr (sizeof(void*) == 8) + return static_cast(seed); + else + return seed; +} + +template +[[nodiscard]] static constexpr auto typeName(T* = nullptr) noexcept +{ + constexpr std::string_view prettyName{ LUABRIDGE_PRETTY_FUNCTION }; + + constexpr auto first = prettyName.find_first_not_of(' ', prettyName.find_first_of(LUABRIDGE_PRETTY_FUNCTION_PREFIX) + 1); + + return prettyName.substr(first, prettyName.find_last_of(LUABRIDGE_PRETTY_FUNCTION_SUFFIX) - first); +} + +template ().find_first_of('.')> +[[nodiscard]] static constexpr auto typeHash(T* = nullptr) noexcept +{ + constexpr auto stripped = typeName(); + + return fnv1a(stripped.data(), stripped.size()); +} + +[[nodiscard]] inline void* getExceptionsKey() noexcept +{ + return reinterpret_cast(0xc7); +} + +[[nodiscard]] inline const void* getTypeKey() noexcept +{ + return reinterpret_cast(0x71); +} + +[[nodiscard]] inline const void* getConstKey() noexcept +{ + return reinterpret_cast(0xc07); +} + +[[nodiscard]] inline const void* getClassKey() noexcept +{ + return reinterpret_cast(0xc1a); +} + +[[nodiscard]] inline const void* getClassOptionsKey() noexcept +{ + return reinterpret_cast(0xc2b); +} + +[[nodiscard]] inline const void* getPropgetKey() noexcept +{ + return reinterpret_cast(0x6e7); +} + +[[nodiscard]] inline const void* getPropsetKey() noexcept +{ + return reinterpret_cast(0x5e7); +} + +[[nodiscard]] inline const void* getStaticKey() noexcept +{ + return reinterpret_cast(0x57a); +} + +[[nodiscard]] inline const void* getParentKey() noexcept +{ + return reinterpret_cast(0xdad); +} + +[[nodiscard]] inline const void* getIndexFallbackKey() +{ + return reinterpret_cast(0x81ca); +} + +[[nodiscard]] inline const void* getIndexExtensibleKey() +{ + return reinterpret_cast(0x81cb); +} + +[[nodiscard]] inline const void* getNewIndexFallbackKey() +{ + return reinterpret_cast(0x8107); +} + +[[nodiscard]] inline const void* getNewIndexExtensibleKey() +{ + return reinterpret_cast(0x8108); +} + +template +[[nodiscard]] const void* getStaticRegistryKey() noexcept +{ + static auto value = typeHash(); + + return reinterpret_cast(value); +} + +template +[[nodiscard]] const void* getClassRegistryKey() noexcept +{ + static auto value = typeHash() ^ 1; + + return reinterpret_cast(value); +} + +template +[[nodiscard]] const void* getConstRegistryKey() noexcept +{ + static auto value = typeHash() ^ 2; + + return reinterpret_cast(value); +} +} +} + + +// End File: Source/LuaBridge/detail/ClassInfo.h + +// Begin File: Source/LuaBridge/detail/LuaException.h + +namespace luabridge { + +class LuaException : public std::exception +{ +public: + + LuaException(lua_State* L, std::error_code code) + : m_L(L) + , m_code(code) + { + } + + ~LuaException() noexcept override + { + } + + const char* what() const noexcept override + { + return m_what.c_str(); + } + + static void raise(lua_State* L, std::error_code code) + { + LUABRIDGE_ASSERT(areExceptionsEnabled(L)); + +#if LUABRIDGE_HAS_EXCEPTIONS + throw LuaException(L, code, FromLua{}); +#else + unused(L, code); + + std::abort(); +#endif + } + + static bool areExceptionsEnabled(lua_State* L) noexcept + { + lua_pushlightuserdata(L, detail::getExceptionsKey()); + lua_gettable(L, LUA_REGISTRYINDEX); + + const bool enabled = lua_isboolean(L, -1) ? static_cast(lua_toboolean(L, -1)) : false; + lua_pop(L, 1); + + return enabled; + } + + static void enableExceptions(lua_State* L) noexcept + { + lua_pushlightuserdata(L, detail::getExceptionsKey()); + lua_pushboolean(L, true); + lua_settable(L, LUA_REGISTRYINDEX); + +#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT + lua_pushlightuserdata(L, (void*)luajitWrapperCallback); + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); + lua_pop(L, 1); +#endif + +#if LUABRIDGE_ON_LUAU + auto callbacks = lua_callbacks(L); + callbacks->panic = +[](lua_State* L, int) { panicHandlerCallback(L); }; +#else + lua_atpanic(L, panicHandlerCallback); +#endif + } + + lua_State* state() const { return m_L; } + +private: + struct FromLua {}; + + LuaException(lua_State* L, std::error_code code, FromLua) + : m_L(L) + , m_code(code) + { + whatFromStack(); + } + + void whatFromStack() + { + std::stringstream ss; + + const char* errorText = nullptr; + + if (lua_gettop(m_L) > 0) + { + errorText = lua_tostring(m_L, -1); + lua_pop(m_L, 1); + } + + ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")"; + + m_what = std::move(ss).str(); + } + + static int panicHandlerCallback(lua_State* L) + { +#if LUABRIDGE_HAS_EXCEPTIONS + throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{}); +#else + unused(L); + + std::abort(); +#endif + } + +#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT + static int luajitWrapperCallback(lua_State* L, lua_CFunction f) + { + try + { + return f(L); + } + catch (const std::exception& e) + { + lua_pushstring(L, e.what()); + return lua_error_x(L); + } + } +#endif + + lua_State* m_L = nullptr; + std::error_code m_code; + std::string m_what; +}; + +inline void enableExceptions(lua_State* L) noexcept +{ +#if LUABRIDGE_HAS_EXCEPTIONS + LuaException::enableExceptions(L); +#else + unused(L); + + LUABRIDGE_ASSERT(false); +#endif +} + +} + + +// End File: Source/LuaBridge/detail/LuaException.h + +// Begin File: Source/LuaBridge/detail/TypeTraits.h + +namespace luabridge { +namespace detail { +template