join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
function.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_FUNCTION_HPP
26#define JOIN_CORE_FUNCTION_HPP
27
28// C++.
29#include <type_traits>
30#include <functional>
31#include <utility>
32#include <new>
33
34// C.
35#include <cstddef>
36#include <cstring>
37
38namespace join
39{
43 template <typename Signature, std::size_t Capacity = 32, std::size_t Alignment = alignof (std::max_align_t)>
44 class Function;
45
49 template <typename Return, typename... Args, std::size_t Capacity, std::size_t Alignment>
50 class Function<Return (Args...), Capacity, Alignment>
51 {
52 public:
56 Function () noexcept = default;
57
62 Function (const Function& other) = delete;
63
69 Function& operator= (const Function& other) = delete;
70
75 Function (Function&& other) noexcept
76 {
77 moveFrom (std::move (other));
78 }
79
85 Function& operator= (Function&& other) noexcept
86 {
87 clear ();
88 moveFrom (std::move (other));
89 return *this;
90 }
91
95 Function (std::nullptr_t) noexcept
96 : Function ()
97 {
98 }
99
103 Function& operator= (std::nullptr_t) noexcept
104 {
105 clear ();
106 return *this;
107 }
108
113 template <typename Func, typename DecayedFunc = std::decay_t<Func>,
114 typename = std::enable_if_t<
115 !std::is_same<DecayedFunc, Function>::value &&
116 (std::is_void<Return>::value ||
117 std::is_convertible<typename std::result_of<DecayedFunc&(Args...)>::type, Return>::value)>>
118 Function (Func&& callable)
119 {
120 static_assert (sizeof (DecayedFunc) <= Capacity, "Callable size exceeds Function capacity.");
121 static_assert (alignof (DecayedFunc) <= Alignment, "Callable alignment exceeds Function alignment.");
122 static_assert (std::is_nothrow_move_constructible<DecayedFunc>::value,
123 "Callable must be nothrow move constructible.");
124
125 new (&_storage) DecayedFunc (std::forward<Func> (callable));
126
127 _invoker = [] (void* storage, Args&&... args) -> Return {
128 return static_cast<Return> ((*static_cast<DecayedFunc*> (storage)) (std::forward<Args> (args)...));
129 };
130
131 _manager = nullptr;
132 _destructor = nullptr;
133
134 if (!std::is_trivially_copyable<DecayedFunc>::value)
135 {
136 _manager = [] (void* dst, void* src) noexcept {
137 DecayedFunc* source = static_cast<DecayedFunc*> (src);
138 new (dst) DecayedFunc (std::move (*source));
139 source->~DecayedFunc ();
140 };
141 }
142
143 if (!std::is_trivially_destructible<DecayedFunc>::value)
144 {
145 _destructor = [] (void* storage) noexcept {
146 static_cast<DecayedFunc*> (storage)->~DecayedFunc ();
147 };
148 }
149
150 // an empty target holds no state, so relocating it copies nothing at all and never
151 // reads the storage, which is left uninitialized by the placement new above.
152 _size = std::is_empty<DecayedFunc>::value ? 0 : sizeof (DecayedFunc);
153 }
154
159 {
160 clear ();
161 }
162
169 Return operator() (Args... args) const
170 {
171 if (!_invoker)
172 {
173 throw std::bad_function_call ();
174 }
175 return _invoker (&_storage, std::forward<Args> (args)...);
176 }
177
182 explicit operator bool () const noexcept
183 {
184 return _invoker != nullptr;
185 }
186
190 void reset () noexcept
191 {
192 clear ();
193 }
194
198 void swap (Function& other) noexcept
199 {
200 Function tmp (std::move (other));
201 other = std::move (*this);
202 *this = std::move (tmp);
203 }
204
205 private:
207 using InvokerFunc = Return (*) (void*, Args&&...);
208
210 using ManagerFunc = void (*) (void*, void*);
211
213 using DestructorFunc = void (*) (void*);
214
218 void clear () noexcept
219 {
220 if (_invoker == nullptr)
221 {
222 return;
223 }
224
225 if (_destructor)
226 {
227 _destructor (&_storage);
228 }
229
230 _invoker = nullptr;
231 _manager = nullptr;
232 _destructor = nullptr;
233 _size = 0;
234 }
235
239 void moveFrom (Function&& other) noexcept
240 {
241 _invoker = other._invoker;
242 _manager = other._manager;
243 _destructor = other._destructor;
244 _size = other._size;
245
246 if (_invoker == nullptr)
247 {
248 return;
249 }
250
251 if (_manager)
252 {
253 _manager (&_storage, &other._storage);
254 }
255 else
256 {
257 std::memcpy (&_storage, &other._storage, _size);
258 }
259
260 other._invoker = nullptr;
261 other._manager = nullptr;
262 other._destructor = nullptr;
263 other._size = 0;
264 }
265
267 alignas (Alignment) mutable unsigned char _storage[Capacity];
268
270 InvokerFunc _invoker = nullptr;
271
273 ManagerFunc _manager = nullptr;
274
276 DestructorFunc _destructor = nullptr;
277
279 std::size_t _size = 0;
280 };
281}
282
283#endif
Function(Func &&callable)
construct with a callable object.
Definition function.hpp:118
void reset() noexcept
clear the stored callable.
Definition function.hpp:190
Function(std::nullptr_t) noexcept
construct from nullptr.
Definition function.hpp:95
void swap(Function &other) noexcept
swap two Function instances.
Definition function.hpp:198
~Function()
destructor.
Definition function.hpp:158
Function() noexcept=default
default constructor.
fixed-capacity move-only allocation-free alternative to std::function.
Definition function.hpp:44
Definition acceptor.hpp:32