Serenity Operating System
at master 291 lines 9.5 kB view raw
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