LeviLamina
Loading...
Searching...
No Matches
function_ref.h
1#pragma once
2
3#include "ll/api/base/TypeTraits.h"
4
5namespace brstd {
6
7template <auto V>
8struct nontype_t {
9 explicit nontype_t() = default;
10};
11
12template <auto V>
13constexpr nontype_t<V> nontype{};
14
15template <class T>
16constexpr bool is_nontype_v = false;
17template <auto f>
18constexpr bool is_nontype_v<nontype_t<f>> = true;
19
20template <class T>
21using transform_param_t = std::conditional_t<std::is_trivially_copyable_v<T>, T, std::add_rvalue_reference_t<T>>;
22
23template <class R, class F, class... Args>
24 requires std::is_invocable_r_v<R, F, Args...>
25constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
26 if constexpr (std::is_void_v<R>) std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
27 else return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
28}
29
31 union storage {
32 void* p_ = nullptr;
33 void const* cp_;
34 void (*fp_)();
35
36 constexpr storage() noexcept = default;
37
38 template <class T>
39 requires std::is_object_v<T>
40 constexpr explicit storage(T* p) noexcept : p_(p) {}
41
42 template <class T>
43 requires std::is_object_v<T>
44 constexpr explicit storage(T const* p) noexcept : cp_(p) {}
45
46 template <class T>
47 requires std::is_function_v<T>
48 constexpr explicit storage(T* p) noexcept : fp_(reinterpret_cast<decltype(fp_)>(p)) {}
49 };
50
51 template <class T>
52 static constexpr auto get(storage obj) {
53 if constexpr (std::is_const_v<T>) return static_cast<T*>(obj.cp_);
54 else if constexpr (std::is_object_v<T>) return static_cast<T*>(obj.p_);
55 else return reinterpret_cast<T*>(obj.fp_);
56 }
57};
58
59template <class Sig, class = typename ::ll::traits::function_traits<Sig>::function_type>
61
62template <class Sig, class R, class... Args>
63class function_ref<Sig, R(Args...)> : function_ref_base {
65
66 template <class T>
67 using cv = typename signature::template cvref<T>;
68 template <class T>
69 using cvref = cv<T>&;
70 static constexpr bool noex = signature::is_noexcept;
71
72 template <class... T>
73 static constexpr bool is_invocable_using =
74 noex ? std::is_nothrow_invocable_r_v<R, T..., Args...> : std::is_invocable_r_v<R, T..., Args...>;
75
76 using fwd_t = R(storage, transform_param_t<Args>...) noexcept(noex);
77 fwd_t* fptr_ = nullptr;
78 storage obj_;
79
80public:
81 template <class F>
82 function_ref(F* f) noexcept
83 requires std::is_function_v<F> && is_invocable_using<F>
84 : fptr_([](storage fn_, transform_param_t<Args>... args) noexcept(noex) -> R {
85 if constexpr (std::is_void_v<R>) get<F>(fn_)(static_cast<decltype(args)>(args)...);
86 else return get<F>(fn_)(static_cast<decltype(args)>(args)...);
87 }),
88 obj_(f) {}
89
90 template <class F, class T = std::remove_reference_t<F>>
91 constexpr function_ref(F&& f) noexcept
92 requires(!std::is_same_v<std::remove_cvref_t<F>, function_ref> && !std::is_member_pointer_v<T>
93 && is_invocable_using<cvref<T>>)
94 : fptr_([](storage fn_, transform_param_t<Args>... args) noexcept(noex) -> R {
95 cvref<T> obj = *get<T>(fn_);
96 if constexpr (std::is_void_v<R>) obj(static_cast<decltype(args)>(args)...);
97 else return obj(static_cast<decltype(args)>(args)...);
98 }),
99 obj_(std::addressof(f)) {}
100
101 constexpr function_ref(function_ref const&) noexcept = default;
102 constexpr function_ref& operator=(function_ref const&) noexcept = default;
103
104 template <class T>
105 function_ref& operator=(T)
106 requires(!std::is_same_v<std::remove_cvref_t<T>, function_ref> && !std::is_pointer_v<T> && !is_nontype_v<T>)
107 = delete;
108
109 template <auto f>
110 constexpr function_ref(nontype_t<f>) noexcept
111 requires is_invocable_using<decltype(f)>
112 : fptr_([](storage, transform_param_t<Args>... args) noexcept(noex) -> R {
113 return invoke_r<R>(f, static_cast<decltype(args)>(args)...);
114 }) {
115 using F = decltype(f);
116 if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>)
117 static_assert(f != nullptr, "NTTP callable must be usable");
118 }
119
120 template <auto f, class U, class T = std::remove_reference_t<U>>
121 constexpr function_ref(nontype_t<f>, U&& obj) noexcept
122 requires(!std::is_rvalue_reference_v<U &&> && is_invocable_using<decltype(f), cvref<T>>)
123 : fptr_([](storage this_, transform_param_t<Args>... args) noexcept(noex) -> R {
124 cvref<T> obj = *get<T>(this_);
125 return invoke_r<R>(f, obj, static_cast<decltype(args)>(args)...);
126 }),
127 obj_(std::addressof(obj)) {
128 using F = decltype(f);
129 if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>)
130 static_assert(f != nullptr, "NTTP callable must be usable");
131 }
132
133 template <auto f, class T>
134 constexpr function_ref(nontype_t<f>, cv<T>* obj) noexcept
135 requires is_invocable_using<decltype(f), decltype(obj)>
136 : fptr_([](storage this_, transform_param_t<Args>... args) noexcept(noex) -> R {
137 return invoke_r<R>(f, get<cv<T>>(this_), static_cast<decltype(args)>(args)...);
138 }),
139 obj_(obj) {
140 using F = decltype(f);
141 if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>)
142 static_assert(f != nullptr, "NTTP callable must be usable");
143 }
144
145 constexpr R operator()(Args... args) const noexcept(noex) { return fptr_(obj_, std::forward<Args>(args)...); }
146};
147
148template <class F>
149 requires std::is_function_v<F>
151
152template <auto V>
153function_ref(nontype_t<V>) -> function_ref<std::remove_pointer_t<decltype(V)>>;
154
155template <class F, class T>
157
158template <class T, class R, class G, class... Args>
159struct nontype_obj_deduction_guide<R (*)(G, Args...), T> {
160 using type = R(Args...);
161};
162
163template <class T, class R, class G, class... Args>
164struct nontype_obj_deduction_guide<R (*)(G, Args...) noexcept, T> {
165 using type = R(Args...) noexcept;
166};
167
168template <class T, class M, class G>
169 requires std::is_object_v<M>
170struct nontype_obj_deduction_guide<M G::*, T> {
171 using type = std::invoke_result_t<M G::*, T>();
172};
173
174template <class T, class M, class G>
175 requires std::is_function_v<M>
177 using type = typename ::ll::traits::function_traits<M>::function_type_noexcept;
178};
179
180template <auto V, class T>
181function_ref(nontype_t<V>, T&&) -> function_ref<typename nontype_obj_deduction_guide<decltype(V), T&>::type>;
182
183} // namespace brstd
Definition function_ref.h:60
Definition function_ref.h:30
Definition function_ref.h:156
Definition function_ref.h:8
Definition TypeTraits.h:53
Definition function_ref.h:31