17 static auto getArg(std::any& any
18 ) -> std::conditional_t<std::is_reference_v<Arg>, Arg, std::add_lvalue_reference_t<Arg>> {
19 using Ret = std::conditional_t<std::is_reference_v<Arg>, Arg, std::add_lvalue_reference_t<Arg>>;
20 using Decay = std::decay_t<Arg>;
21 using Wrap = std::remove_cvref_t<Arg>;
22 if constexpr (std::is_const_v<std::remove_reference_t<Arg>>) {
23 if (
auto* res = std::any_cast<std::reference_wrapper<std::add_const_t<Wrap>>>(&any)) {
24 return static_cast<Ret
>(res->get());
27 if (
auto* res = std::any_cast<std::reference_wrapper<Wrap>>(&any)) {
28 return static_cast<Ret
>(res->get());
30 return static_cast<Ret
>(std::any_cast<std::add_lvalue_reference_t<std::decay_t<Arg>>>(any));
34 static constexpr inline size_t anyFnSizeNumPtrs = 8;
35 static constexpr inline size_t smallObjSize = ((anyFnSizeNumPtrs - 1) *
sizeof(
void*));
39 virtual void tidy()
noexcept = 0;
40 virtual std::any invoke(std::span<std::any>) = 0;
46 template <std::size_t... I>
47 std::any invokeImpl(std::span<std::any> args, std::index_sequence<I...>) {
48 if constexpr (std::is_void_v<Ret>) {
49 (void)std::invoke(std::forward<
decltype(fn)>(fn), getArg<Args>(args[I])...);
52 return std::make_any<Ret>(std::invoke(std::forward<
decltype(fn)>(fn), getArg<Args>(args[I])...));
57 static constexpr inline bool nothrowMove = std::is_nothrow_move_constructible_v<Fn>;
60 requires(!std::is_same_v<T, AnyFunctionObj>)
61 constexpr explicit AnyFunctionObj(T&& fn) : fn(std::forward<T>(fn)) {}
63 std::any invoke(std::span<std::any> args)
override {
return invokeImpl(args, std::index_sequence_for<Args...>{}); }
67 return constructImpl<AnyFunctionObj>(to, std::forward<F>(f));
70 AnyFunctionObjBase* copy(
void* to)
const override {
return constructImpl<AnyFunctionObj>(to, fn); }
71 AnyFunctionObjBase* move(
void* to)
noexcept override {
return constructImpl<AnyFunctionObj>(to, std::move(fn)); }
72 void tidy()
noexcept override { destroyImpl<AnyFunctionObj>(
this); }
77 std::max_align_t dummy;
78 char soo[AnyFunctionObjBase::smallObjSize];
81 constexpr bool isLarge()
const noexcept {
return dataPtr !=
static_cast<void const*
>(&soo); }
83 constexpr bool hasValue()
const noexcept {
return dataPtr; }
85 void tidy()
noexcept {
87 std::exchange(dataPtr,
nullptr)->tidy();
91 if (other.hasValue()) {
92 dataPtr = other.dataPtr->copy(&soo);
96 if (other.hasValue()) {
97 if (other.isLarge()) {
98 dataPtr = std::exchange(other.dataPtr,
nullptr);
100 dataPtr = other.dataPtr->move(&soo);
115 if (
this != std::addressof(other)) {
122 if (
this != std::addressof(other)) {
124 move(std::move(other));
129 if (isLarge() && other.isLarge()) {
130 std::swap(dataPtr, other.dataPtr);
133 temp.move(std::move(*
this));
134 move(std::move(other));
135 other.move(std::move(temp));
139 template <
class Fn,
class Ret,
class... Args>
140 requires(std::invocable<Fn, Args...>)
141 AnyFunction(std::in_place_type_t<Ret(Args...)>, Fn&& fn) {
142 if constexpr (std::is_pointer_v<Fn> || traits::is_specialization_of_v<Fn, std::function>
143 || std::is_member_pointer_v<Fn>) {
155 std::any invoke(std::span<std::any> args)
const {
return dataPtr->invoke(args); }
157 template <
class... Args>
158 std::any operator()(Args&&... args)
const {
160 std::array<std::any,
sizeof...(Args)>{std::make_any<std::decay_t<Args>>(std::forward<Args>(args))...};
163 constexpr explicit operator bool()
const noexcept {
return hasValue(); }