Serenity Operating System
1/*
2 * Copyright (C) 2016 Apple Inc. All rights reserved.
3 * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Assertions.h>
30#include <AK/Atomic.h>
31#include <AK/BitCast.h>
32#include <AK/Noncopyable.h>
33#include <AK/ScopeGuard.h>
34#include <AK/StdLibExtras.h>
35#include <AK/Types.h>
36
37namespace AK {
38
39namespace Detail {
40
41template<typename T, typename Out, typename... Args>
42inline constexpr bool IsCallableWithArguments = requires(T t) {
43 {
44 t(declval<Args>()...)
45 } -> ConvertibleTo<Out>;
46 } || requires(T t) {
47 {
48 t(declval<Args>()...)
49 } -> SameAs<Out>;
50 };
51}
52
53using Detail::IsCallableWithArguments;
54
55template<typename>
56class Function;
57
58template<typename F>
59inline constexpr bool IsFunctionPointer = (IsPointer<F> && IsFunction<RemovePointer<F>>);
60
61// Not a function pointer, and not an lvalue reference.
62template<typename F>
63inline constexpr bool IsFunctionObject = (!IsFunctionPointer<F> && IsRvalueReference<F&&>);
64
65template<typename Out, typename... In>
66class Function<Out(In...)> {
67 AK_MAKE_NONCOPYABLE(Function);
68
69public:
70 using ReturnType = Out;
71
72 Function() = default;
73 Function(nullptr_t)
74 {
75 }
76
77 ~Function()
78 {
79 clear(false);
80 }
81
82 template<typename CallableType>
83 Function(CallableType&& callable)
84 requires((IsFunctionObject<CallableType> && IsCallableWithArguments<CallableType, Out, In...> && !IsSame<RemoveCVReference<CallableType>, Function>))
85 {
86 init_with_callable(forward<CallableType>(callable));
87 }
88
89 template<typename FunctionType>
90 Function(FunctionType f)
91 requires((IsFunctionPointer<FunctionType> && IsCallableWithArguments<RemovePointer<FunctionType>, Out, In...> && !IsSame<RemoveCVReference<FunctionType>, Function>))
92 {
93 init_with_callable(move(f));
94 }
95
96 Function(Function&& other)
97 {
98 move_from(move(other));
99 }
100
101 // Note: Despite this method being const, a mutable lambda _may_ modify its own captures.
102 Out operator()(In... in) const
103 {
104 auto* wrapper = callable_wrapper();
105 VERIFY(wrapper);
106 ++m_call_nesting_level;
107 ScopeGuard guard([this] {
108 if (--m_call_nesting_level == 0 && m_deferred_clear)
109 const_cast<Function*>(this)->clear(false);
110 });
111 return wrapper->call(forward<In>(in)...);
112 }
113
114 explicit operator bool() const { return !!callable_wrapper(); }
115
116 template<typename CallableType>
117 Function& operator=(CallableType&& callable)
118 requires((IsFunctionObject<CallableType> && IsCallableWithArguments<CallableType, Out, In...>))
119 {
120 clear();
121 init_with_callable(forward<CallableType>(callable));
122 return *this;
123 }
124
125 template<typename FunctionType>
126 Function& operator=(FunctionType f)
127 requires((IsFunctionPointer<FunctionType> && IsCallableWithArguments<RemovePointer<FunctionType>, Out, In...>))
128 {
129 clear();
130 if (f)
131 init_with_callable(move(f));
132 return *this;
133 }
134
135 Function& operator=(nullptr_t)
136 {
137 clear();
138 return *this;
139 }
140
141 Function& operator=(Function&& other)
142 {
143 if (this != &other) {
144 clear();
145 move_from(move(other));
146 }
147 return *this;
148 }
149
150private:
151 class CallableWrapperBase {
152 public:
153 virtual ~CallableWrapperBase() = default;
154 // Note: This is not const to allow storing mutable lambdas.
155 virtual Out call(In...) = 0;
156 virtual void destroy() = 0;
157 virtual void init_and_swap(u8*, size_t) = 0;
158 };
159
160 template<typename CallableType>
161 class CallableWrapper final : public CallableWrapperBase {
162 AK_MAKE_NONMOVABLE(CallableWrapper);
163 AK_MAKE_NONCOPYABLE(CallableWrapper);
164
165 public:
166 explicit CallableWrapper(CallableType&& callable)
167 : m_callable(move(callable))
168 {
169 }
170
171 Out call(In... in) final override
172 {
173 return m_callable(forward<In>(in)...);
174 }
175
176 void destroy() final override
177 {
178 delete this;
179 }
180
181 // NOLINTNEXTLINE(readability-non-const-parameter) False positive; destination is used in a placement new expression
182 void init_and_swap(u8* destination, size_t size) final override
183 {
184 VERIFY(size >= sizeof(CallableWrapper));
185 new (destination) CallableWrapper { move(m_callable) };
186 }
187
188 private:
189 CallableType m_callable;
190 };
191
192 enum class FunctionKind {
193 NullPointer,
194 Inline,
195 Outline,
196 };
197
198 CallableWrapperBase* callable_wrapper() const
199 {
200 switch (m_kind) {
201 case FunctionKind::NullPointer:
202 return nullptr;
203 case FunctionKind::Inline:
204 return bit_cast<CallableWrapperBase*>(&m_storage);
205 case FunctionKind::Outline:
206 return *bit_cast<CallableWrapperBase**>(&m_storage);
207 default:
208 VERIFY_NOT_REACHED();
209 }
210 }
211
212 void clear(bool may_defer = true)
213 {
214 bool called_from_inside_function = m_call_nesting_level > 0;
215 // NOTE: This VERIFY could fail because a Function is destroyed from within itself.
216 VERIFY(may_defer || !called_from_inside_function);
217 if (called_from_inside_function && may_defer) {
218 m_deferred_clear = true;
219 return;
220 }
221 m_deferred_clear = false;
222 auto* wrapper = callable_wrapper();
223 if (m_kind == FunctionKind::Inline) {
224 VERIFY(wrapper);
225 wrapper->~CallableWrapperBase();
226 } else if (m_kind == FunctionKind::Outline) {
227 VERIFY(wrapper);
228 wrapper->destroy();
229 }
230 m_kind = FunctionKind::NullPointer;
231 }
232
233 template<typename Callable>
234 void init_with_callable(Callable&& callable)
235 {
236 VERIFY(m_call_nesting_level == 0);
237 using WrapperType = CallableWrapper<Callable>;
238#ifndef KERNEL
239 if constexpr (sizeof(WrapperType) > inline_capacity) {
240 *bit_cast<CallableWrapperBase**>(&m_storage) = new WrapperType(forward<Callable>(callable));
241 m_kind = FunctionKind::Outline;
242 } else {
243#endif
244 static_assert(sizeof(WrapperType) <= inline_capacity);
245 new (m_storage) WrapperType(forward<Callable>(callable));
246 m_kind = FunctionKind::Inline;
247#ifndef KERNEL
248 }
249#endif
250 }
251
252 void move_from(Function&& other)
253 {
254 VERIFY(m_call_nesting_level == 0 && other.m_call_nesting_level == 0);
255 auto* other_wrapper = other.callable_wrapper();
256 switch (other.m_kind) {
257 case FunctionKind::NullPointer:
258 break;
259 case FunctionKind::Inline:
260 other_wrapper->init_and_swap(m_storage, inline_capacity);
261 m_kind = FunctionKind::Inline;
262 break;
263 case FunctionKind::Outline:
264 *bit_cast<CallableWrapperBase**>(&m_storage) = other_wrapper;
265 m_kind = FunctionKind::Outline;
266 break;
267 default:
268 VERIFY_NOT_REACHED();
269 }
270 other.m_kind = FunctionKind::NullPointer;
271 }
272
273 FunctionKind m_kind { FunctionKind::NullPointer };
274 bool m_deferred_clear { false };
275 mutable Atomic<u16> m_call_nesting_level { 0 };
276#ifndef KERNEL
277 // Empirically determined to fit most lambdas and functions.
278 static constexpr size_t inline_capacity = 4 * sizeof(void*);
279#else
280 // FIXME: Try to decrease this.
281 static constexpr size_t inline_capacity = 6 * sizeof(void*);
282#endif
283 alignas(max(alignof(CallableWrapperBase), alignof(CallableWrapperBase*))) u8 m_storage[inline_capacity];
284};
285
286}
287
288#if USING_AK_GLOBALLY
289using AK::Function;
290using AK::IsCallableWithArguments;
291#endif