110 #include <functional>
112 #if !defined(VLINK_ENABLE_BASE_FUNCTIONAL)
113 #define VLINK_ENABLE_BASE_FUNCTIONAL
116 #ifdef VLINK_ENABLE_BASE_FUNCTIONAL
119 #include <type_traits>
128 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
true;
130 template <
typename SignatureT,
size_t SboSizeT = 64U>
133 template <
typename SignatureT,
size_t SboSizeT = 64U>
136 template <
typename SignatureT>
139 template <
typename SignatureT>
142 template <
typename SignatureT>
145 template <
typename SignatureT>
150 template <
typename TypeT>
153 template <
typename SignatureT>
156 template <
typename TypeT>
159 template <
typename SignatureT,
size_t SboSizeT>
162 template <
typename TypeT>
165 template <
typename SignatureT,
size_t SboSizeT>
168 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
169 template <
typename TypeT>
170 struct IsStdMoveOnlyFunction : std::false_type {};
172 template <
typename SignatureT>
173 struct IsStdMoveOnlyFunction<std::
move_only_function<SignatureT>> : std::true_type {};
198 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
200 static_assert(SboSizeT >=
sizeof(
void*),
201 "Function: SboSizeT must be at least sizeof(void*) so the heap-fallback "
202 "pointer can fit in the inline storage.");
208 static constexpr
size_t kSboSize = SboSizeT;
244 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
246 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
Function>>,
247 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
248 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
249 std::is_copy_constructible<DecayFunctorT>>>>
265 Function& operator=(std::nullptr_t) noexcept;
272 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
274 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
Function>>,
275 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
276 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
277 std::is_copy_constructible<DecayFunctorT>>>>
290 ReturnT operator()(ArgsT... args) const;
295 explicit operator
bool() const noexcept;
297 #if defined(__cpp_rtti)
301 const std::type_info& target_type() const noexcept;
308 template <typename FunctorT>
309 FunctorT* target() noexcept;
316 template <typename FunctorT>
317 const FunctorT* target() const noexcept;
326 template <
typename FunctorT>
327 static constexpr
bool kIsPointerLike = std::is_pointer_v<FunctorT> || std::is_member_pointer_v<FunctorT> ||
328 std::is_function_v<std::remove_pointer_t<FunctorT>>;
330 template <
typename FunctorT>
331 static constexpr
bool kIsFunctionWrapper =
334 template <
typename FunctorT>
335 static constexpr
bool kIsInline =
sizeof(FunctorT) <= kSboSize &&
alignof(FunctorT) <=
alignof(std::max_align_t) &&
336 std::is_nothrow_move_constructible_v<FunctorT>;
338 struct VTable final {
339 ReturnT (*invoke)(
const void* storage, ArgsT... args);
341 void (*copy_construct)(
void* dst,
const void* src);
343 void (*move_construct)(
void* dst,
void* src) noexcept;
345 void (*destroy)(
void* storage) noexcept;
347 #if defined(__cpp_rtti)
348 const std::type_info& (*target_type)() noexcept;
350 void* (*target)(
void* storage) noexcept;
352 const void* (*target_const)(
const void* storage) noexcept;
356 template <
typename FunctorT>
357 struct InlineVTable {
358 static ReturnT invoke(
const void* storage, ArgsT... args);
360 static void copy_construct(
void* dst,
const void* src);
362 static void move_construct(
void* dst,
void* src) noexcept;
364 static void destroy(
void* storage) noexcept;
366 #if defined(__cpp_rtti)
367 static const std::type_info& target_type() noexcept;
369 static
void* target(
void* storage) noexcept;
371 static const
void* target_const(const
void* storage) noexcept;
375 template <
typename FunctorT>
377 static ReturnT invoke(
const void* storage, ArgsT... args);
379 static void copy_construct(
void* dst,
const void* src);
381 static void move_construct(
void* dst,
void* src) noexcept;
383 static void destroy(
void* storage) noexcept;
385 #if defined(__cpp_rtti)
386 static const std::type_info& target_type() noexcept;
388 static
void* target(
void* storage) noexcept;
390 static const
void* target_const(const
void* storage) noexcept;
394 template <
typename FunctorT>
395 static const VTable* get_vtable() noexcept;
397 template <typename FunctorT, typename SourceT>
398 void construct_from(SourceT&& src);
400 void copy_from(const Function& other);
402 void move_from(Function&& other) noexcept;
404 void reset() noexcept;
406 alignas(std::max_align_t) std::
byte storage_[SboSizeT]{};
408 const VTable* vtable_{
nullptr};
414 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
415 void swap(Function<ReturnT(ArgsT...), SboSizeT>& lhs, Function<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept;
420 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
421 bool operator==(
const Function<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
426 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
427 bool operator==(std::nullptr_t,
const Function<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
432 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
433 bool operator!=(
const Function<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
438 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
439 bool operator!=(std::nullptr_t,
const Function<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
458 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
460 static_assert(SboSizeT >=
sizeof(
void*),
461 "MoveFunction: SboSizeT must be at least sizeof(void*) so the "
462 "heap-fallback pointer can fit in the inline storage.");
468 static constexpr
size_t kSboSize = SboSizeT;
503 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
505 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
MoveFunction>>,
506 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
507 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
508 std::is_constructible<DecayFunctorT, FunctorT>,
509 std::is_move_constructible<DecayFunctorT>>>>
527 template <typename FunctorT, typename DecayFunctorT = std::decay_t<FunctorT>,
529 typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayFunctorT,
MoveFunction>>,
530 std::negation<std::is_same<DecayFunctorT, std::nullptr_t>>,
531 std::is_invocable_r<ReturnT, DecayFunctorT&, ArgsT...>,
532 std::is_constructible<DecayFunctorT, FunctorT>,
533 std::is_move_constructible<DecayFunctorT>>>>
546 ReturnT operator()(ArgsT... args);
551 explicit operator
bool() const noexcept;
553 #if defined(__cpp_rtti)
557 const std::type_info& target_type() const noexcept;
564 template <typename FunctorT>
565 FunctorT* target() noexcept;
572 template <typename FunctorT>
573 const FunctorT* target() const noexcept;
582 template <
typename FunctorT>
583 static constexpr
bool kIsPointerLike = std::is_pointer_v<FunctorT> || std::is_member_pointer_v<FunctorT> ||
584 std::is_function_v<std::remove_pointer_t<FunctorT>>;
586 template <
typename FunctorT>
587 static constexpr
bool kIsFunctionWrapper =
589 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
595 template <
typename FunctorT>
596 static constexpr
bool kIsInline =
sizeof(FunctorT) <= kSboSize &&
alignof(FunctorT) <=
alignof(std::max_align_t) &&
597 std::is_nothrow_move_constructible_v<FunctorT>;
599 struct VTable final {
600 ReturnT (*invoke)(
void* storage, ArgsT... args);
602 void (*move_construct)(
void* dst,
void* src) noexcept;
604 void (*destroy)(
void* storage) noexcept;
606 #if defined(__cpp_rtti)
607 const std::type_info& (*target_type)() noexcept;
609 void* (*target)(
void* storage) noexcept;
611 const void* (*target_const)(
const void* storage) noexcept;
615 template <
typename FunctorT>
616 struct InlineVTable {
617 static ReturnT invoke(
void* storage, ArgsT... args);
619 static void move_construct(
void* dst,
void* src) noexcept;
621 static void destroy(
void* storage) noexcept;
623 #if defined(__cpp_rtti)
624 static const std::type_info& target_type() noexcept;
626 static
void* target(
void* storage) noexcept;
628 static const
void* target_const(const
void* storage) noexcept;
632 template <
typename FunctorT>
634 static ReturnT invoke(
void* storage, ArgsT... args);
636 static void move_construct(
void* dst,
void* src) noexcept;
638 static void destroy(
void* storage) noexcept;
640 #if defined(__cpp_rtti)
641 static const std::type_info& target_type() noexcept;
643 static
void* target(
void* storage) noexcept;
645 static const
void* target_const(const
void* storage) noexcept;
649 template <
typename FunctorT>
650 static const VTable* get_vtable() noexcept;
652 template <typename FunctorT, typename SourceT>
653 void construct_from(SourceT&& src);
655 void move_from(MoveFunction&& other) noexcept;
657 void reset() noexcept;
659 alignas(std::max_align_t) std::
byte storage_[SboSizeT]{};
661 const VTable* vtable_{
nullptr};
667 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
668 void swap(MoveFunction<ReturnT(ArgsT...), SboSizeT>& lhs, MoveFunction<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept;
673 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
674 bool operator==(
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
679 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
680 bool operator==(std::nullptr_t,
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
685 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
686 bool operator!=(
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb, std::nullptr_t) noexcept;
691 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
692 bool operator!=(std::nullptr_t,
const MoveFunction<ReturnT(ArgsT...), SboSizeT>& cb) noexcept;
698 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
701 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
706 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
708 move_from(std::move(other));
711 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
712 template <
typename FunctorT,
typename DecayFunctorT,
typename>
714 if constexpr (kIsFunctionWrapper<DecayFunctorT>) {
718 }
else if constexpr (kIsPointerLike<DecayFunctorT>) {
719 if constexpr (std::is_pointer_v<std::remove_reference_t<FunctorT>> ||
720 std::is_member_pointer_v<std::remove_reference_t<FunctorT>>) {
727 construct_from<DecayFunctorT>(std::forward<FunctorT>(f));
730 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
741 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
742 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(
746 move_from(std::move(other));
752 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
753 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(
754 std::nullptr_t) noexcept {
759 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
760 template <
typename FunctorT,
typename DecayFunctorT,
typename>
761 inline Function<ReturnT(ArgsT...), SboSizeT>&
Function<ReturnT(ArgsT...), SboSizeT>::operator=(FunctorT&& f) {
762 Function tmp(std::forward<FunctorT>(f));
767 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
768 inline Function<ReturnT(ArgsT...), SboSizeT>::~Function() {
772 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
773 inline ReturnT
Function<ReturnT(ArgsT...), SboSizeT>::operator()(ArgsT... args)
const {
778 return vtable_->invoke(&storage_, std::forward<ArgsT>(args)...);
781 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
782 inline Function<ReturnT(ArgsT...), SboSizeT>::operator bool() const noexcept {
783 return vtable_ !=
nullptr;
786 #if defined(__cpp_rtti)
787 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
788 inline const std::type_info&
Function<ReturnT(ArgsT...), SboSizeT>::target_type() const noexcept {
789 if VLIKELY (vtable_ !=
nullptr) {
790 return vtable_->target_type();
796 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
797 template <
typename FunctorT>
798 inline FunctorT* Function<ReturnT(ArgsT...), SboSizeT>::target() noexcept {
799 if constexpr (std::is_object_v<FunctorT>) {
800 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
801 return static_cast<FunctorT*
>(vtable_->target(&storage_));
808 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
809 template <
typename FunctorT>
810 inline const FunctorT* Function<ReturnT(ArgsT...), SboSizeT>::target() const noexcept {
811 if constexpr (std::is_object_v<FunctorT>) {
812 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
813 return static_cast<const FunctorT*
>(vtable_->target_const(&storage_));
821 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
828 *
this = std::move(other);
829 other = std::move(tmp);
832 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
833 template <
typename FunctorT>
834 inline ReturnT
Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::invoke(
const void* storage,
836 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(
const_cast<void*
>(storage)));
838 if constexpr (std::is_void_v<ReturnT>) {
839 std::invoke(*f, std::forward<ArgsT>(args)...);
841 return std::invoke(*f, std::forward<ArgsT>(args)...);
845 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
846 template <
typename FunctorT>
847 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::copy_construct(
void* dst,
const void* src) {
848 const auto* src_f = std::launder(
reinterpret_cast<const FunctorT*
>(src));
849 ::new (dst) FunctorT(*src_f);
852 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
853 template <
typename FunctorT>
854 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::move_construct(
void* dst,
855 void* src) noexcept {
856 auto* src_f = std::launder(
reinterpret_cast<FunctorT*
>(src));
857 ::new (dst) FunctorT(std::move(*src_f));
861 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
862 template <
typename FunctorT>
863 inline void Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::destroy(
void* storage) noexcept {
864 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
868 #if defined(__cpp_rtti)
869 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
870 template <
typename FunctorT>
871 inline const std::type_info& Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_type() noexcept {
872 return typeid(FunctorT);
875 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
876 template <
typename FunctorT>
877 inline void* Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target(
void* storage) noexcept {
881 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
882 template <
typename FunctorT>
883 inline const void* Function<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_const(
884 const void* storage) noexcept {
889 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
890 template <
typename FunctorT>
891 inline ReturnT Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::invoke(
const void* storage, ArgsT... args) {
892 FunctorT* f = *std::launder(
static_cast<FunctorT* const*
>(storage));
894 if constexpr (std::is_void_v<ReturnT>) {
895 std::invoke(*f, std::forward<ArgsT>(args)...);
897 return std::invoke(*f, std::forward<ArgsT>(args)...);
901 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
902 template <
typename FunctorT>
903 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::copy_construct(
void* dst,
const void* src) {
904 FunctorT* src_f = *std::launder(
static_cast<FunctorT* const*
>(src));
907 void* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
910 throw std::bad_alloc();
914 auto* new_f = ::new (mem) FunctorT(*src_f);
915 ::new (dst) FunctorT*(new_f);
917 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
922 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
923 template <
typename FunctorT>
924 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::move_construct(
void* dst,
void* src) noexcept {
925 FunctorT** src_slot = std::launder(
static_cast<FunctorT**
>(src));
926 FunctorT* src_f = *src_slot;
927 ::new (dst) FunctorT*(src_f);
931 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
932 template <
typename FunctorT>
933 inline void Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::destroy(
void* storage) noexcept {
934 FunctorT** slot = std::launder(
static_cast<FunctorT**
>(storage));
941 pool.deallocate(f,
sizeof(FunctorT),
alignof(FunctorT));
947 #if defined(__cpp_rtti)
948 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
949 template <
typename FunctorT>
950 inline const std::type_info& Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_type() noexcept {
951 return typeid(FunctorT);
954 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
955 template <
typename FunctorT>
956 inline void* Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target(
void* storage) noexcept {
957 return *std::launder(
static_cast<FunctorT**
>(storage));
960 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
961 template <
typename FunctorT>
962 inline const void* Function<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_const(
963 const void* storage) noexcept {
964 return *std::launder(
static_cast<FunctorT* const*
>(storage));
968 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
969 template <
typename FunctorT>
970 inline const typename Function<ReturnT(ArgsT...), SboSizeT>::VTable*
971 Function<ReturnT(ArgsT...), SboSizeT>::get_vtable() noexcept {
972 if constexpr (kIsInline<FunctorT>) {
973 static constexpr VTable kVTable = {
974 &InlineVTable<FunctorT>::invoke, &InlineVTable<FunctorT>::copy_construct,
975 &InlineVTable<FunctorT>::move_construct, &InlineVTable<FunctorT>::destroy,
976 #if defined(__cpp_rtti)
977 &InlineVTable<FunctorT>::target_type, &InlineVTable<FunctorT>::target,
978 &InlineVTable<FunctorT>::target_const,
983 static constexpr VTable kVTable = {
984 &HeapVTable<FunctorT>::invoke, &HeapVTable<FunctorT>::copy_construct,
985 &HeapVTable<FunctorT>::move_construct, &HeapVTable<FunctorT>::destroy,
986 #if defined(__cpp_rtti)
987 &HeapVTable<FunctorT>::target_type, &HeapVTable<FunctorT>::target,
988 &HeapVTable<FunctorT>::target_const,
995 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
996 template <
typename FunctorT,
typename SourceT>
997 inline void Function<ReturnT(ArgsT...), SboSizeT>::construct_from(SourceT&& src) {
998 if constexpr (kIsInline<FunctorT>) {
999 ::new (&storage_) FunctorT(std::forward<SourceT>(src));
1002 auto* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
1005 throw std::bad_alloc();
1009 auto* new_f = ::new (mem) FunctorT(std::forward<SourceT>(src));
1010 ::new (
static_cast<void*
>(&storage_)) FunctorT*(new_f);
1012 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
1017 vtable_ = get_vtable<FunctorT>();
1020 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1021 inline void Function<ReturnT(ArgsT...), SboSizeT>::copy_from(
const Function& other) {
1022 if VLIKELY (other.vtable_ !=
nullptr) {
1023 other.vtable_->copy_construct(&storage_, &other.storage_);
1024 vtable_ = other.vtable_;
1028 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1029 inline void Function<ReturnT(ArgsT...), SboSizeT>::move_from(Function&& other) noexcept {
1030 if VLIKELY (other.vtable_ !=
nullptr) {
1031 other.vtable_->move_construct(&storage_, &other.storage_);
1032 vtable_ = other.vtable_;
1033 other.vtable_ =
nullptr;
1037 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1038 inline void Function<ReturnT(ArgsT...), SboSizeT>::reset() noexcept {
1039 if VLIKELY (vtable_ !=
nullptr) {
1040 vtable_->destroy(&storage_);
1045 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1046 inline void swap(
Function<ReturnT(ArgsT...), SboSizeT>& lhs,
Function<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept {
1050 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1055 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1060 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1062 return static_cast<bool>(cb);
1065 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1067 return static_cast<bool>(cb);
1070 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1073 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1075 move_from(std::move(other));
1078 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1079 template <
typename FunctorT,
typename DecayFunctorT,
typename>
1081 if constexpr (kIsFunctionWrapper<DecayFunctorT>) {
1085 }
else if constexpr (kIsPointerLike<DecayFunctorT>) {
1086 if constexpr (std::is_pointer_v<std::remove_reference_t<FunctorT>> ||
1087 std::is_member_pointer_v<std::remove_reference_t<FunctorT>>) {
1094 construct_from<DecayFunctorT>(std::forward<FunctorT>(f));
1097 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1102 move_from(std::move(other));
1108 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1110 std::nullptr_t) noexcept {
1115 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1116 template <
typename FunctorT,
typename DecayFunctorT,
typename>
1123 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1128 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1129 inline ReturnT
MoveFunction<ReturnT(ArgsT...), SboSizeT>::operator()(ArgsT... args) {
1134 return vtable_->invoke(&storage_, std::forward<ArgsT>(args)...);
1137 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1138 inline MoveFunction<ReturnT(ArgsT...), SboSizeT>::operator bool() const noexcept {
1139 return vtable_ !=
nullptr;
1142 #if defined(__cpp_rtti)
1143 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1144 inline const std::type_info&
MoveFunction<ReturnT(ArgsT...), SboSizeT>::target_type() const noexcept {
1145 if VLIKELY (vtable_ !=
nullptr) {
1146 return vtable_->target_type();
1149 return typeid(void);
1152 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1153 template <
typename FunctorT>
1154 inline FunctorT* MoveFunction<ReturnT(ArgsT...), SboSizeT>::target() noexcept {
1155 if constexpr (std::is_object_v<FunctorT>) {
1156 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
1157 return static_cast<FunctorT*
>(vtable_->target(&storage_));
1164 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1165 template <
typename FunctorT>
1166 inline const FunctorT* MoveFunction<ReturnT(ArgsT...), SboSizeT>::target() const noexcept {
1167 if constexpr (std::is_object_v<FunctorT>) {
1168 if VLIKELY (vtable_ !=
nullptr &&
typeid(FunctorT) == target_type()) {
1169 return static_cast<const FunctorT*
>(vtable_->target_const(&storage_));
1177 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1184 *
this = std::move(other);
1185 other = std::move(tmp);
1188 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1189 template <
typename FunctorT>
1190 inline ReturnT
MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::invoke(
void* storage, ArgsT... args) {
1191 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
1193 if constexpr (std::is_void_v<ReturnT>) {
1194 std::invoke(*f, std::forward<ArgsT>(args)...);
1196 return std::invoke(*f, std::forward<ArgsT>(args)...);
1200 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1201 template <
typename FunctorT>
1202 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::move_construct(
void* dst,
1203 void* src) noexcept {
1204 auto* src_f = std::launder(
reinterpret_cast<FunctorT*
>(src));
1205 ::new (dst) FunctorT(std::move(*src_f));
1209 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1210 template <
typename FunctorT>
1211 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::destroy(
void* storage) noexcept {
1212 auto* f = std::launder(
reinterpret_cast<FunctorT*
>(storage));
1216 #if defined(__cpp_rtti)
1217 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1218 template <
typename FunctorT>
1219 inline const std::type_info& MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_type() noexcept {
1220 return typeid(FunctorT);
1223 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1224 template <
typename FunctorT>
1225 inline void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target(
void* storage) noexcept {
1229 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1230 template <
typename FunctorT>
1231 inline const void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::InlineVTable<FunctorT>::target_const(
1232 const void* storage) noexcept {
1237 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1238 template <
typename FunctorT>
1239 inline ReturnT MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::invoke(
void* storage, ArgsT... args) {
1240 FunctorT* f = *std::launder(
static_cast<FunctorT**
>(storage));
1242 if constexpr (std::is_void_v<ReturnT>) {
1243 std::invoke(*f, std::forward<ArgsT>(args)...);
1245 return std::invoke(*f, std::forward<ArgsT>(args)...);
1249 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1250 template <
typename FunctorT>
1251 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::move_construct(
void* dst,
1252 void* src) noexcept {
1253 FunctorT** src_slot = std::launder(
static_cast<FunctorT**
>(src));
1254 FunctorT* src_f = *src_slot;
1255 ::new (dst) FunctorT*(src_f);
1256 *src_slot =
nullptr;
1259 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1260 template <
typename FunctorT>
1261 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::destroy(
void* storage) noexcept {
1262 FunctorT** slot = std::launder(
static_cast<FunctorT**
>(storage));
1263 FunctorT* f = *slot;
1269 pool.deallocate(f,
sizeof(FunctorT),
alignof(FunctorT));
1275 #if defined(__cpp_rtti)
1276 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1277 template <
typename FunctorT>
1278 inline const std::type_info& MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_type() noexcept {
1279 return typeid(FunctorT);
1282 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1283 template <
typename FunctorT>
1284 inline void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target(
void* storage) noexcept {
1285 return *std::launder(
static_cast<FunctorT**
>(storage));
1288 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1289 template <
typename FunctorT>
1290 inline const void* MoveFunction<ReturnT(ArgsT...), SboSizeT>::HeapVTable<FunctorT>::target_const(
1291 const void* storage) noexcept {
1292 return *std::launder(
static_cast<FunctorT* const*
>(storage));
1296 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1297 template <
typename FunctorT>
1298 inline const typename MoveFunction<ReturnT(ArgsT...), SboSizeT>::VTable*
1300 if constexpr (kIsInline<FunctorT>) {
1301 static constexpr VTable kVTable = {
1302 &InlineVTable<FunctorT>::invoke, &InlineVTable<FunctorT>::move_construct,
1303 &InlineVTable<FunctorT>::destroy,
1304 #if defined(__cpp_rtti)
1305 &InlineVTable<FunctorT>::target_type, &InlineVTable<FunctorT>::target,
1306 &InlineVTable<FunctorT>::target_const,
1311 static constexpr VTable kVTable = {
1312 &HeapVTable<FunctorT>::invoke, &HeapVTable<FunctorT>::move_construct, &HeapVTable<FunctorT>::destroy,
1313 #if defined(__cpp_rtti)
1314 &HeapVTable<FunctorT>::target_type, &HeapVTable<FunctorT>::target, &HeapVTable<FunctorT>::target_const,
1321 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1322 template <
typename FunctorT,
typename SourceT>
1323 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::construct_from(SourceT&& src) {
1324 if constexpr (kIsInline<FunctorT>) {
1325 ::new (&storage_) FunctorT(std::forward<SourceT>(src));
1328 auto* mem = pool.allocate(
sizeof(FunctorT),
alignof(FunctorT));
1331 throw std::bad_alloc();
1335 auto* new_f = ::new (mem) FunctorT(std::forward<SourceT>(src));
1336 ::new (
static_cast<void*
>(&storage_)) FunctorT*(new_f);
1338 pool.deallocate(mem,
sizeof(FunctorT),
alignof(FunctorT));
1343 vtable_ = get_vtable<FunctorT>();
1346 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1347 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::move_from(MoveFunction&& other) noexcept {
1348 if VLIKELY (other.vtable_ !=
nullptr) {
1349 other.vtable_->move_construct(&storage_, &other.storage_);
1350 vtable_ = other.vtable_;
1351 other.vtable_ =
nullptr;
1355 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1356 inline void MoveFunction<ReturnT(ArgsT...), SboSizeT>::reset() noexcept {
1357 if VLIKELY (vtable_ !=
nullptr) {
1358 vtable_->destroy(&storage_);
1363 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1365 MoveFunction<ReturnT(ArgsT...), SboSizeT>& rhs) noexcept {
1369 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1374 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1379 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1381 return static_cast<bool>(cb);
1384 template <
typename ReturnT,
typename... ArgsT,
size_t SboSizeT>
1386 return static_cast<bool>(cb);
1395 template <
typename SignatureT>
1396 using Function = std::function<SignatureT>;
1398 template <
typename SignatureT>
1401 template <
typename SignatureT>
1402 using function = std::function<SignatureT>;
1404 #if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
1405 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
true;
1406 template <
typename SignatureT>
1407 using MoveFunction = std::move_only_function<SignatureT>;
1409 template <
typename SignatureT>
1412 template <
typename SignatureT>
1415 [[maybe_unused]]
static constexpr
bool kIsSupportMoveFunction =
false;
1416 template <
typename SignatureT>
1417 using MoveFunction = std::function<SignatureT>;
1419 template <
typename SignatureT>
1422 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:213
Copyable type-erased callable analogue of std::function with a tunable SBO and pool spill.
Definition: functional.h:131
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:473
Move-only type-erased callable analogue of std::move_only_function with pool spill.
Definition: functional.h:134
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:1051
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:1046
MoveFunction< SignatureT > move_only_function
Definition: functional.h:146
Function< SignatureT, 256U > LargeFunction
Definition: functional.h:137
bool operator!=(const Function< ReturnT(ArgsT...), SboSizeT > &cb, std::nullptr_t) noexcept
Inequality with nullptr; true when cb stores a target.
Definition: functional.h:1061
MoveFunction< SignatureT, 256U > LargeMoveFunction
Definition: functional.h:140
Definition: functional.h:151
Definition: functional.h:157
Definition: functional.h:163