111 #include <functional>
113 #if !defined(VLINK_ENABLE_BASE_FUNCTIONAL)
114 #define VLINK_ENABLE_BASE_FUNCTIONAL
117 #ifdef VLINK_ENABLE_BASE_FUNCTIONAL
120 #include <type_traits>
129 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
true;
131 template <
typename SignatureT,
size_t SboSizeT = 64U>
134 template <
typename SignatureT,
size_t SboSizeT = 64U>
137 template <
typename SignatureT>
140 template <
typename SignatureT>
143 template <
typename SignatureT>
146 template <
typename SignatureT>
151 template <
typename TypeT>
154 template <
typename SignatureT>
157 template <
typename TypeT>
160 template <
typename SignatureT,
size_t SboSizeT>
163 template <
typename TypeT>
166 template <
typename SignatureT,
size_t SboSizeT>
169 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
170 template <
typename TypeT>
171 struct IsStdMoveOnlyFunction : std::false_type {};
173 template <
typename SignatureT>
174 struct IsStdMoveOnlyFunction<std::
move_only_function<SignatureT>> : std::true_type {};
199 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
201 static_assert(SboSizeT >=
sizeof(
void*),
202 "Function: SboSizeT must be at least sizeof(void*) so the heap-fallback "
203 "pointer can fit in the inline storage.");
209 static constexpr
size_t kSboSize = SboSizeT;
245 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
247 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
Function>>,
248 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
249 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
250 std::is_constructible<DecayFunctorT, FunctorT>,
251 std::is_copy_constructible<DecayFunctorT>>>>
267 Function& operator=(std::nullptr_t) noexcept;
274 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
276 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
Function>>,
277 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
278 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
279 std::is_constructible<DecayFunctorT, FunctorT>,
280 std::is_copy_constructible<DecayFunctorT>>>>
293 ReturnT operator()(ArgsT... args) const;
298 explicit operator
bool() const noexcept;
300 #if defined(__cpp_rtti)
304 const std::type_info& target_type() const noexcept;
311 template <typename FunctorT>
312 FunctorT* target() noexcept;
319 template <typename FunctorT>
320 const FunctorT* target() const noexcept;
329 template <
typename FunctorT>
330 static constexpr
bool kIsPointerLike = std::is_pointer_v<FunctorT> || std::is_member_pointer_v<FunctorT> ||
331 std::is_function_v<std::remove_pointer_t<FunctorT>>;
333 template <
typename FunctorT>
334 static constexpr
bool kIsFunctionWrapper =
337 template <
typename FunctorT>
338 static constexpr
bool kIsInline =
sizeof(FunctorT) <= kSboSize &&
alignof(FunctorT) <=
alignof(std::max_align_t) &&
339 std::is_nothrow_move_constructible_v<FunctorT>;
341 struct VTable final {
342 ReturnT (*invoke)(
const void* storage, ArgsT&&... args);
344 void (*copy_construct)(
void* dst,
const void* src);
346 void (*move_construct)(
void* dst,
void* src) noexcept;
348 void (*destroy)(
void* storage) noexcept;
350 #if defined(__cpp_rtti)
351 const std::type_info& (*target_type)() noexcept;
353 void* (*target)(
void* storage) noexcept;
355 const void* (*target_const)(
const void* storage) noexcept;
359 template <
typename FunctorT>
360 struct InlineVTable {
361 static ReturnT invoke(
const void* storage, ArgsT&&... args);
363 static void copy_construct(
void* dst,
const void* src);
365 static void move_construct(
void* dst,
void* src) noexcept;
367 static void destroy(
void* storage) noexcept;
369 #if defined(__cpp_rtti)
370 static const std::type_info& target_type() noexcept;
372 static
void* target(
void* storage) noexcept;
374 static const
void* target_const(const
void* storage) noexcept;
378 template <
typename FunctorT>
380 static ReturnT invoke(
const void* storage, ArgsT&&... args);
382 static void copy_construct(
void* dst,
const void* src);
384 static void move_construct(
void* dst,
void* src) noexcept;
386 static void destroy(
void* storage) noexcept;
388 #if defined(__cpp_rtti)
389 static const std::type_info& target_type() noexcept;
391 static
void* target(
void* storage) noexcept;
393 static const
void* target_const(const
void* storage) noexcept;
397 template <
typename FunctorT>
398 static const VTable* get_vtable() noexcept;
400 template <typename FunctorT, typename SourceT>
401 void construct_from(SourceT&& src);
403 void copy_from(const Function& other);
405 void move_from(Function&& other) noexcept;
407 void reset() noexcept;
409 alignas(std::max_align_t) std::
byte storage_[SboSizeT];
411 const VTable* vtable_{
nullptr};
417 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
418 void swap(Function<ReturnT(ArgsT...), SboSizeT>& lhs, Function<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept;
423 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
424 bool operator==(
const Function<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
429 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
430 bool operator==(std::nullptr_t,
const Function<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
435 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
436 bool operator!=(
const Function<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
441 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
442 bool operator!=(std::nullptr_t,
const Function<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
461 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
463 static_assert(SboSizeT >=
sizeof(
void*),
464 "MoveFunction: SboSizeT must be at least sizeof(void*) so the "
465 "heap-fallback pointer can fit in the inline storage.");
471 static constexpr
size_t kSboSize = SboSizeT;
506 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
508 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
MoveFunction>>,
509 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
510 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
511 std::is_constructible<DecayFunctorT, FunctorT>,
512 std::is_move_constructible<DecayFunctorT>>>>
530 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
532 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
MoveFunction>>,
533 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
534 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
535 std::is_constructible<DecayFunctorT, FunctorT>,
536 std::is_move_constructible<DecayFunctorT>>>>
549 ReturnT operator()(ArgsT... args);
554 explicit operator
bool() const noexcept;
556 #if defined(__cpp_rtti)
560 const std::type_info& target_type() const noexcept;
567 template <typename FunctorT>
568 FunctorT* target() noexcept;
575 template <typename FunctorT>
576 const FunctorT* target() const noexcept;
585 template <
typename FunctorT>
586 static constexpr
bool kIsPointerLike = std::is_pointer_v<FunctorT> || std::is_member_pointer_v<FunctorT> ||
587 std::is_function_v<std::remove_pointer_t<FunctorT>>;
589 template <
typename FunctorT>
590 static constexpr
bool kIsFunctionWrapper =
592 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
598 template <
typename FunctorT>
599 static constexpr
bool kIsInline =
sizeof(FunctorT) <= kSboSize &&
alignof(FunctorT) <=
alignof(std::max_align_t) &&
600 std::is_nothrow_move_constructible_v<FunctorT>;
602 struct VTable final {
603 ReturnT (*invoke)(
void* storage, ArgsT&&... args);
605 void (*move_construct)(
void* dst,
void* src) noexcept;
607 void (*destroy)(
void* storage) noexcept;
609 #if defined(__cpp_rtti)
610 const std::type_info& (*target_type)() noexcept;
612 void* (*target)(
void* storage) noexcept;
614 const void* (*target_const)(
const void* storage) noexcept;
618 template <
typename FunctorT>
619 struct InlineVTable {
620 static ReturnT invoke(
void* storage, ArgsT&&... args);
622 static void move_construct(
void* dst,
void* src) noexcept;
624 static void destroy(
void* storage) noexcept;
626 #if defined(__cpp_rtti)
627 static const std::type_info& target_type() noexcept;
629 static
void* target(
void* storage) noexcept;
631 static const
void* target_const(const
void* storage) noexcept;
635 template <
typename FunctorT>
637 static ReturnT invoke(
void* storage, ArgsT&&... args);
639 static void move_construct(
void* dst,
void* src) noexcept;
641 static void destroy(
void* storage) noexcept;
643 #if defined(__cpp_rtti)
644 static const std::type_info& target_type() noexcept;
646 static
void* target(
void* storage) noexcept;
648 static const
void* target_const(const
void* storage) noexcept;
652 template <
typename FunctorT>
653 static const VTable* get_vtable() noexcept;
655 template <typename FunctorT, typename SourceT>
656 void construct_from(SourceT&& src);
658 void move_from(MoveFunction&& other) noexcept;
660 void reset() noexcept;
662 alignas(std::max_align_t) std::
byte storage_[SboSizeT];
664 const VTable* vtable_{
nullptr};
670 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
671 void swap(MoveFunction<ReturnT(ArgsT...), SboSizeT>& lhs, MoveFunction<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept;
676 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
677 bool operator==(
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
682 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
683 bool operator==(std::nullptr_t,
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
688 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
689 bool operator!=(
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
694 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
695 bool operator!=(std::nullptr_t,
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
701 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
704 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
709 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
711 move_from(std::move(other));
714 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
715 template <
typename FunctorT,
typename DecayFunctorT,
typename>
717 if constexpr (kIsFunctionWrapper<DecayFunctorT>) {
721 }
else if constexpr (kIsPointerLike<DecayFunctorT>) {
722 if constexpr (std::is_pointer_v<std::remove_reference_t<FunctorT>> ||
723 std::is_member_pointer_v<std::remove_reference_t<FunctorT>>) {
730 construct_from<DecayFunctorT>(std::forward<FunctorT>(f));
733 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
739 move_from(std::move(tmp));
745 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
746 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(
750 move_from(std::move(other));
756 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
757 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(
758 std::nullptr_t) noexcept {
763 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
764 template <
typename FunctorT,
typename DecayFunctorT,
typename>
765 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(FunctorT&& f) {
766 Function tmp(std::forward<FunctorT>(f));
768 move_from(std::move(tmp));
772 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
773 inline Function<ReturnT(ArgsT...), SboSizeT>::~Function() {
777 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
778 inline ReturnT
Function<ReturnT(ArgsT...), SboSizeT>::operator()(ArgsT... args)
const {
783 return vtable_->invoke(&storage_, std::forward<ArgsT>(args)...);
786 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
787 inline Function<ReturnT(ArgsT...), SboSizeT>::operator bool() const noexcept {
788 return vtable_ !=
nullptr;
791 #if defined(__cpp_rtti)
792 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
793 inline const std::type_info&
Function<ReturnT(ArgsT...), SboSizeT>::target_type() const noexcept {
794 if VLIKELY (vtable_ !=
nullptr) {
795 return vtable_->target_type();
801 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
802 template <
typename FunctorT>
803 inline FunctorT* Function<ReturnT(ArgsT...), SboSizeT>::target() noexcept {
804 if constexpr (std::is_object_v<FunctorT>) {
805 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
806 return static_cast<FunctorT*
>(vtable_->target(&storage_));
813 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
814 template <
typename FunctorT>
815 inline const FunctorT* Function<ReturnT(ArgsT...), SboSizeT>::target() const noexcept {
816 if constexpr (std::is_object_v<FunctorT>) {
817 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
818 return static_cast<const FunctorT*
>(vtable_->target_const(&storage_));
826 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
833 *
this = std::move(other);
834 other = std::move(tmp);
837 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
838 template <
typename FunctorT>
839 inline ReturnT
Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::invoke(
const void* storage,
841 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(
const_cast<void*
>(storage)));
843 if constexpr (std::is_void_v<ReturnT>) {
844 std::invoke(*f, std::forward<ArgsT>(args)...);
846 return std::invoke(*f, std::forward<ArgsT>(args)...);
850 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
851 template <
typename FunctorT>
852 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::copy_construct(
void* dst,
const void* src) {
853 const auto* src_f = std::launder(
reinterpret_cast<const FunctorT*
>(src));
854 ::new (dst) FunctorT(*src_f);
857 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
858 template <
typename FunctorT>
859 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::move_construct(
void* dst,
860 void* src) noexcept {
861 auto* src_f = std::launder(
reinterpret_cast<FunctorT*
>(src));
862 ::new (dst) FunctorT(std::move(*src_f));
866 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
867 template <
typename FunctorT>
868 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::destroy(
void* storage) noexcept {
869 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
873 #if defined(__cpp_rtti)
874 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
875 template <
typename FunctorT>
876 inline const std::type_info& Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_type() noexcept {
877 return typeid(FunctorT);
880 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
881 template <
typename FunctorT>
882 inline void* Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target(
void* storage) noexcept {
886 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
887 template <
typename FunctorT>
888 inline const void* Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_const(
889 const void* storage) noexcept {
894 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
895 template <
typename FunctorT>
896 inline ReturnT Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::invoke(
const void* storage,
898 FunctorT* f = *std::launder(
static_cast<FunctorT* const*
>(storage));
900 if constexpr (std::is_void_v<ReturnT>) {
901 std::invoke(*f, std::forward<ArgsT>(args)...);
903 return std::invoke(*f, std::forward<ArgsT>(args)...);
907 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
908 template <
typename FunctorT>
909 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::copy_construct(
void* dst,
const void* src) {
910 FunctorT* src_f = *std::launder(
static_cast<FunctorT* const*
>(src));
913 void* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
916 throw std::bad_alloc();
920 auto* new_f = ::new (mem) FunctorT(*src_f);
921 ::new (dst) FunctorT*(new_f);
923 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
928 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
929 template <
typename FunctorT>
930 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::move_construct(
void* dst,
void* src) noexcept {
931 FunctorT** src_slot = std::launder(
static_cast<FunctorT**
>(src));
932 FunctorT* src_f = *src_slot;
933 ::new (dst) FunctorT*(src_f);
937 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
938 template <
typename FunctorT>
939 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::destroy(
void* storage) noexcept {
940 FunctorT** slot = std::launder(
static_cast<FunctorT**
>(storage));
947 pool.deallocate(f,
sizeof(FunctorT),
alignof(FunctorT));
953 #if defined(__cpp_rtti)
954 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
955 template <
typename FunctorT>
956 inline const std::type_info& Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_type() noexcept {
957 return typeid(FunctorT);
960 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
961 template <
typename FunctorT>
962 inline void* Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target(
void* storage) noexcept {
963 return *std::launder(
static_cast<FunctorT**
>(storage));
966 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
967 template <
typename FunctorT>
968 inline const void* Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_const(
969 const void* storage) noexcept {
970 return *std::launder(
static_cast<FunctorT* const*
>(storage));
974 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
975 template <
typename FunctorT>
976 inline const typename Function<ReturnT(ArgsT...), SboSizeT>::VTable*
977 Function<ReturnT(ArgsT...), SboSizeT>::get_vtable() noexcept {
978 if constexpr (kIsInline<FunctorT>) {
979 static constexpr VTable kVTable = {
980 &InlineVTable<FunctorT>::invoke, &InlineVTable<FunctorT>::copy_construct,
981 &InlineVTable<FunctorT>::move_construct, &InlineVTable<FunctorT>::destroy,
982 #if defined(__cpp_rtti)
983 &InlineVTable<FunctorT>::target_type, &InlineVTable<FunctorT>::target,
984 &InlineVTable<FunctorT>::target_const,
989 static constexpr VTable kVTable = {
990 &HeapVTable<FunctorT>::invoke, &HeapVTable<FunctorT>::copy_construct,
991 &HeapVTable<FunctorT>::move_construct, &HeapVTable<FunctorT>::destroy,
992 #if defined(__cpp_rtti)
993 &HeapVTable<FunctorT>::target_type, &HeapVTable<FunctorT>::target,
994 &HeapVTable<FunctorT>::target_const,
1001 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1002 template <
typename FunctorT,
typename SourceT>
1003 inline void Function<ReturnT(ArgsT...), SboSizeT>::construct_from(SourceT&& src) {
1004 if constexpr (kIsInline<FunctorT>) {
1005 ::new (&storage_) FunctorT(std::forward<SourceT>(src));
1008 auto* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
1011 throw std::bad_alloc();
1015 auto* new_f = ::new (mem) FunctorT(std::forward<SourceT>(src));
1016 ::new (
static_cast<void*
>(&storage_)) FunctorT*(new_f);
1018 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
1023 vtable_ = get_vtable<FunctorT>();
1026 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1027 inline void Function<ReturnT(ArgsT...), SboSizeT>::copy_from(
const Function& other) {
1028 if VLIKELY (other.vtable_ !=
nullptr) {
1029 other.vtable_->copy_construct(&storage_, &other.storage_);
1030 vtable_ = other.vtable_;
1034 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1035 inline void Function<ReturnT(ArgsT...), SboSizeT>::move_from(Function&& other) noexcept {
1036 if VLIKELY (other.vtable_ !=
nullptr) {
1037 other.vtable_->move_construct(&storage_, &other.storage_);
1038 vtable_ = other.vtable_;
1039 other.vtable_ =
nullptr;
1043 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1044 inline void Function<ReturnT(ArgsT...), SboSizeT>::reset() noexcept {
1045 if VLIKELY (vtable_ !=
nullptr) {
1046 vtable_->destroy(&storage_);
1051 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1052 inline void swap(
Function<ReturnT(ArgsT...), SboSizeT>& lhs,
Function<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept {
1056 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1061 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1066 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1068 return static_cast<bool>(cb);
1071 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1073 return static_cast<bool>(cb);
1076 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1079 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1081 move_from(std::move(other));
1084 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1085 template <
typename FunctorT,
typename DecayFunctorT,
typename>
1087 if constexpr (kIsFunctionWrapper<DecayFunctorT>) {
1091 }
else if constexpr (kIsPointerLike<DecayFunctorT>) {
1092 if constexpr (std::is_pointer_v<std::remove_reference_t<FunctorT>> ||
1093 std::is_member_pointer_v<std::remove_reference_t<FunctorT>>) {
1100 construct_from<DecayFunctorT>(std::forward<FunctorT>(f));
1103 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1108 move_from(std::move(other));
1114 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1116 std::nullptr_t) noexcept {
1121 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1122 template <
typename FunctorT,
typename DecayFunctorT,
typename>
1126 move_from(std::move(tmp));
1130 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1135 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1136 inline ReturnT
MoveFunction<ReturnT(ArgsT...), SboSizeT>::operator()(ArgsT... args) {
1141 return vtable_->invoke(&storage_, std::forward<ArgsT>(args)...);
1144 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1145 inline MoveFunction<ReturnT(ArgsT...), SboSizeT>::operator bool() const noexcept {
1146 return vtable_ !=
nullptr;
1149 #if defined(__cpp_rtti)
1150 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1151 inline const std::type_info&
MoveFunction<ReturnT(ArgsT...), SboSizeT>::target_type() const noexcept {
1152 if VLIKELY (vtable_ !=
nullptr) {
1153 return vtable_->target_type();
1156 return typeid(void);
1159 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1160 template <
typename FunctorT>
1161 inline FunctorT* MoveFunction<ReturnT(ArgsT...), SboSizeT>::target() noexcept {
1162 if constexpr (std::is_object_v<FunctorT>) {
1163 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
1164 return static_cast<FunctorT*
>(vtable_->target(&storage_));
1171 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1172 template <
typename FunctorT>
1173 inline const FunctorT* MoveFunction<ReturnT(ArgsT...), SboSizeT>::target() const noexcept {
1174 if constexpr (std::is_object_v<FunctorT>) {
1175 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
1176 return static_cast<const FunctorT*
>(vtable_->target_const(&storage_));
1184 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1191 *
this = std::move(other);
1192 other = std::move(tmp);
1195 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1196 template <
typename FunctorT>
1197 inline ReturnT
MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::invoke(
void* storage,
1199 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
1201 if constexpr (std::is_void_v<ReturnT>) {
1202 std::invoke(*f, std::forward<ArgsT>(args)...);
1204 return std::invoke(*f, std::forward<ArgsT>(args)...);
1208 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1209 template <
typename FunctorT>
1210 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::move_construct(
void* dst,
1211 void* src) noexcept {
1212 auto* src_f = std::launder(
reinterpret_cast<FunctorT*
>(src));
1213 ::new (dst) FunctorT(std::move(*src_f));
1217 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1218 template <
typename FunctorT>
1219 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::destroy(
void* storage) noexcept {
1220 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
1224 #if defined(__cpp_rtti)
1225 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1226 template <
typename FunctorT>
1227 inline const std::type_info& MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_type() noexcept {
1228 return typeid(FunctorT);
1231 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1232 template <
typename FunctorT>
1233 inline void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target(
void* storage) noexcept {
1237 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1238 template <
typename FunctorT>
1239 inline const void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_const(
1240 const void* storage) noexcept {
1245 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1246 template <
typename FunctorT>
1247 inline ReturnT MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::invoke(
void* storage, ArgsT&&... args) {
1248 FunctorT* f = *std::launder(
static_cast<FunctorT**
>(storage));
1250 if constexpr (std::is_void_v<ReturnT>) {
1251 std::invoke(*f, std::forward<ArgsT>(args)...);
1253 return std::invoke(*f, std::forward<ArgsT>(args)...);
1257 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1258 template <
typename FunctorT>
1259 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::move_construct(
void* dst,
1260 void* src) noexcept {
1261 FunctorT** src_slot = std::launder(
static_cast<FunctorT**
>(src));
1262 FunctorT* src_f = *src_slot;
1263 ::new (dst) FunctorT*(src_f);
1264 *src_slot =
nullptr;
1267 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1268 template <
typename FunctorT>
1269 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::destroy(
void* storage) noexcept {
1270 FunctorT** slot = std::launder(
static_cast<FunctorT**
>(storage));
1271 FunctorT* f = *slot;
1277 pool.deallocate(f,
sizeof(FunctorT),
alignof(FunctorT));
1283 #if defined(__cpp_rtti)
1284 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1285 template <
typename FunctorT>
1286 inline const std::type_info& MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_type() noexcept {
1287 return typeid(FunctorT);
1290 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1291 template <
typename FunctorT>
1292 inline void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target(
void* storage) noexcept {
1293 return *std::launder(
static_cast<FunctorT**
>(storage));
1296 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1297 template <
typename FunctorT>
1298 inline const void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_const(
1299 const void* storage) noexcept {
1300 return *std::launder(
static_cast<FunctorT* const*
>(storage));
1304 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1305 template <
typename FunctorT>
1306 inline const typename MoveFunction<ReturnT(ArgsT...), SboSizeT>::VTable*
1308 if constexpr (kIsInline<FunctorT>) {
1309 static constexpr VTable kVTable = {
1310 &InlineVTable<FunctorT>::invoke, &InlineVTable<FunctorT>::move_construct,
1311 &InlineVTable<FunctorT>::destroy,
1312 #if defined(__cpp_rtti)
1313 &InlineVTable<FunctorT>::target_type, &InlineVTable<FunctorT>::target,
1314 &InlineVTable<FunctorT>::target_const,
1319 static constexpr VTable kVTable = {
1320 &HeapVTable<FunctorT>::invoke, &HeapVTable<FunctorT>::move_construct, &HeapVTable<FunctorT>::destroy,
1321 #if defined(__cpp_rtti)
1322 &HeapVTable<FunctorT>::target_type, &HeapVTable<FunctorT>::target, &HeapVTable<FunctorT>::target_const,
1329 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1330 template <
typename FunctorT,
typename SourceT>
1331 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::construct_from(SourceT&& src) {
1332 if constexpr (kIsInline<FunctorT>) {
1333 ::new (&storage_) FunctorT(std::forward<SourceT>(src));
1336 auto* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
1339 throw std::bad_alloc();
1343 auto* new_f = ::new (mem) FunctorT(std::forward<SourceT>(src));
1344 ::new (
static_cast<void*
>(&storage_)) FunctorT*(new_f);
1346 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
1351 vtable_ = get_vtable<FunctorT>();
1354 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1355 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::move_from(MoveFunction&& other) noexcept {
1356 if VLIKELY (other.vtable_ !=
nullptr) {
1357 other.vtable_->move_construct(&storage_, &other.storage_);
1358 vtable_ = other.vtable_;
1359 other.vtable_ =
nullptr;
1363 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1364 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::reset() noexcept {
1365 if VLIKELY (vtable_ !=
nullptr) {
1366 vtable_->destroy(&storage_);
1371 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1373 MoveFunction<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept {
1377 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1382 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1387 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1389 return static_cast<bool>(cb);
1392 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1394 return static_cast<bool>(cb);
1403 template <
typename SignatureT>
1404 using Function = std::function<SignatureT>;
1406 template <
typename SignatureT>
1409 template <
typename SignatureT>
1410 using function = std::function<SignatureT>;
1412 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
1413 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
true;
1414 template <
typename SignatureT>
1415 using MoveFunction = std::move_only_function<SignatureT>;
1417 template <
typename SignatureT>
1420 template <
typename SignatureT>
1423 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
false;
1424 template <
typename SignatureT>
1425 using MoveFunction = std::function<SignatureT>;
1427 template <
typename SignatureT>
1430 template <
typename SignatureT>
Function() noexcept=default
Constructs an empty wrapper with no stored target.
ReturnT result_type
Result type alias matching std::function.
Definition: functional.h:214
Copyable type-erased callable analogue of std::function with a tunable SBO and pool spill.
Definition: functional.h:132
static MemoryPool & global_instance(bool use_env_level=true)
Returns the process-wide shared MemoryPool instance.
MoveFunction() noexcept=default
Constructs an empty wrapper with no stored target.
ReturnT result_type
Result type alias matching std::move_only_function.
Definition: functional.h:476
Move-only type-erased callable analogue of std::move_only_function with pool spill.
Definition: functional.h:135
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLINK_EXPORT
Definition: macros.h:81
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
Size-class tiered memory pool with per-tier free lists and runtime statistics.
VLINK_EXPORT void throw_bad_function_call()
bool operator==(const Function< ReturnT(ArgsT...), SboSizeT > &cb, std::nullptr_t) noexcept
Equality with nullptr; true when cb has no stored target.
Definition: functional.h:1057
void swap(Function< ReturnT(ArgsT...), SboSizeT > &lhs, Function< ReturnT(ArgsT...), SboSizeT > &rhs) noexcept
Free-function swap; defers to the member swap of lhs.
Definition: functional.h:1052
MoveFunction< SignatureT > move_only_function
Definition: functional.h:147
Function< SignatureT, 256U > LargeFunction
Definition: functional.h:138
bool operator!=(const Function< ReturnT(ArgsT...), SboSizeT > &cb, std::nullptr_t) noexcept
Inequality with nullptr; true when cb stores a target.
Definition: functional.h:1067
MoveFunction< SignatureT, 256U > LargeMoveFunction
Definition: functional.h:141
Definition: functional.h:152
Definition: functional.h:158
Definition: functional.h:164