diff --git a/src/ll/api/base/CompilerPredefine.h b/src/ll/api/base/CompilerPredefine.h index 41913b3db2..d7c6b086f8 100644 --- a/src/ll/api/base/CompilerPredefine.h +++ b/src/ll/api/base/CompilerPredefine.h @@ -240,9 +240,6 @@ template consteval bool virtualDetector() noexcept { return reflection::getRawName().find("::`vcall'{") != std::string_view::npos; } -#if LL_HAS_CXX23 -using stdOptionalConstructFromInvokeTag = std::_Construct_from_invoke_result_tag; -#endif using FileHandleT = void*; @@ -326,10 +323,6 @@ namespace ll::internal { [[nodiscard]] void* getCurrentModuleHandle() noexcept; // Implemented in SystemUtils_linux.cpp -#if LL_HAS_CXX23 -using stdOptionalConstructFromInvokeTag = std::__optional_construct_from_invoke_tag; -#endif - using FileHandleT = int; template > diff --git a/src/ll/api/base/Meta.h b/src/ll/api/base/Meta.h index 8b27b96bf9..ff6a1d48b2 100644 --- a/src/ll/api/base/Meta.h +++ b/src/ll/api/base/Meta.h @@ -254,4 +254,55 @@ template return Id; } } + +template + requires std::is_reference_v && (std::is_reference_v && ...) +class elide { + using R = std::invoke_result_t; + static_assert(!std::is_reference_v, "F must return by value"); + + inline static constexpr bool excepts = noexcept(std::invoke(std::declval(), std::declval()...)); + + static constexpr decltype(auto) to_invokable(FR f, PRs... args) noexcept { + using F = std::remove_reference_t; + using DF = std::remove_pointer_t; + if constexpr (sizeof...(PRs)) { + return [&f, &args...]() noexcept(excepts) -> decltype(auto) { + return std::invoke(static_cast(f), static_cast(args)...); + }; + } else if constexpr (std::is_function_v) { + return static_cast(f); + } else if constexpr (std::is_trivial_v && sizeof(F) <= sizeof(void*)) { + return static_cast(f); + } else { + return static_cast(f); + } + } + using invokable_t = decltype(to_invokable(std::declval(), std::declval()...)); + invokable_t invokable; + +public: + template + constexpr explicit elide(F&& arg, Params&&... args) noexcept + : invokable(to_invokable(std::forward(arg), std::forward(args)...)) {} + + constexpr operator R() noexcept(excepts) { + return std::invoke( + static_cast, invokable_t&, invokable_t&&>>(invokable) + ); + } + constexpr R operator()() noexcept(excepts) { return this->operator R(); } + + constexpr elide() = delete; + constexpr elide(elide const&) = delete; + constexpr elide(elide&&) = delete; + elide& operator=(elide const&) = delete; + elide& operator=(elide&&) = delete; + elide const volatile* operator&() const volatile = delete; + template + void operator,(U&&) = delete; +}; +template +elide(F&&, Params&&...) -> elide; + } // namespace ll::meta diff --git a/src/ll/api/command/Optional.h b/src/ll/api/command/Optional.h index 57bf91562d..1143b6b74d 100644 --- a/src/ll/api/command/Optional.h +++ b/src/ll/api/command/Optional.h @@ -6,7 +6,7 @@ #include #include -#include "ll/api/base/Macro.h" +#include "ll/api/base/Meta.h" namespace ll::command { @@ -109,7 +109,7 @@ class Optional { } return static_cast(std::forward(right)); } -#if LL_HAS_CXX23 + template constexpr auto and_then(Fn&& fn) & { using Ret = std::invoke_result_t; @@ -155,9 +155,8 @@ class Optional { using Ret = std::remove_cv_t>; if (has_value()) { return std::optional{ - internal::stdOptionalConstructFromInvokeTag{}, - std::forward(fn), - static_cast(mValue) + + meta::elide(std::forward(fn), static_cast(mValue)) }; } else { return std::optional{}; @@ -168,11 +167,7 @@ class Optional { constexpr auto transform(Fn&& fn) const& { using Ret = std::remove_cv_t>; if (has_value()) { - return std::optional{ - internal::stdOptionalConstructFromInvokeTag{}, - std::forward(fn), - static_cast(mValue) - }; + return std::optional{meta::elide(std::forward(fn), static_cast(mValue))}; } else { return std::optional{}; } @@ -182,11 +177,7 @@ class Optional { constexpr auto transform(Fn&& fn) && { using Ret = std::remove_cv_t>; if (has_value()) { - return std::optional{ - internal::stdOptionalConstructFromInvokeTag{}, - std::forward(fn), - static_cast(mValue) - }; + return std::optional{meta::elide(std::forward(fn), static_cast(mValue))}; } else { return std::optional{}; } @@ -196,15 +187,12 @@ class Optional { constexpr auto transform(Fn&& fn) const&& { using Ret = std::remove_cv_t>; if (has_value()) { - return std::optional{ - internal::stdOptionalConstructFromInvokeTag{}, - std::forward(fn), - static_cast(mValue) - }; + return std::optional{meta::elide(std::forward(fn), static_cast(mValue))}; } else { return std::optional{}; } } + template Fn> requires std::copy_constructible constexpr std::optional or_else(Fn&& fn) const& { @@ -224,7 +212,6 @@ class Optional { return std::invoke(std::forward(fn)); } } -#endif // LL_HAS_CXX23 [[nodiscard]] constexpr T const&& value_or_default() const&& { return std::move(value()); } [[nodiscard]] constexpr T&& value_or_default() && { return std::move(value()); } diff --git a/src/mc/deps/core/utility/optional_ref.h b/src/mc/deps/core/utility/optional_ref.h index 0a2dc71792..3370bbd24d 100644 --- a/src/mc/deps/core/utility/optional_ref.h +++ b/src/mc/deps/core/utility/optional_ref.h @@ -4,7 +4,7 @@ #include #include -#include "ll/api/base/Macro.h" +#include "ll/api/base/Meta.h" template requires(!std::is_reference_v) @@ -115,7 +115,6 @@ class optional_ref { [[nodiscard]] constexpr decltype(auto) crend() const { return (value().crend()); } [[nodiscard]] constexpr decltype(auto) crbegin() const { return (value().crbegin()); } -#if LL_HAS_CXX23 template constexpr auto and_then(Fn&& fn) const { using Ret = std::invoke_result_t; @@ -138,11 +137,7 @@ class optional_ref { } else { using UnwrapT = std::remove_cv_t; if (has_value()) { - return std::optional{ - ll::internal::stdOptionalConstructFromInvokeTag{}, - std::forward(fn), - static_cast(*mPtr) - }; + return std::optional{ll::meta::elide(std::forward(fn), static_cast(*mPtr))}; } else { return std::optional{}; } @@ -156,7 +151,6 @@ class optional_ref { return std::invoke(std::forward(fn)); } } -#endif // LL_HAS_CXX23 }; // NOLINTEND template