jaulib v1.3.0
Jau Support Library (C++, Java, ..)
functional.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020-2022 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef JAU_FUNCTIONAL_HPP_
27#define JAU_FUNCTIONAL_HPP_
28
29#include <cstring>
30#include <string>
31#include <memory>
32#include <cstdint>
33#include <type_traits>
34#include <functional>
35
36#include <jau/basic_types.hpp>
37#include <jau/cpp_lang_util.hpp>
38#include <jau/debug.hpp>
39
40namespace jau {
41
42 /** @defgroup FunctionWrap Function Wrapper
43 * A general-purpose static-polymorphic function wrapper via [jau::function<R(A...)>](@ref function_def).
44 *
45 * @anchor function_overview
46 * ### Function Overview
47 * Similar to std::function, [jau::function<R(A...)>](@ref function_def) stores any callable target function
48 * solely described by its return type `R` and arguments types `A...` from any source,
49 * e.g. free functions, capturing and non-capturing lambda function, member functions.
50 *
51 * [jau::function<R(A...)>](@ref function_def) supports equality operations for all func::target_type source types,
52 * allowing to manage container of [jau::function](@ref function_def)s, see [limitations](@ref function_limitations) below.
53 *
54 * If a [jau::function](@ref function_def) contains no target, see jau::function<R(A...)>::is_null(), it is empty.
55 * Invoking the target of an empty [jau::function](@ref function_def) is a no-operation and has no side effects.
56 *
57 * [jau::function](@ref function_def) satisfies the requirements of CopyConstructible, CopyAssignable, MoveConstructible and MoveAssignable.
58 *
59 * Compared to `std::function<R(A...)>`, `jau::function<R(A...)>`
60 * - exposes the target function signature [jau::type_info](@ref type_info) via jau::function::signature()
61 * - supports equality operations
62 * - supports [Y combinator and deducing this lambda functions](@ref ylambda_target)
63 * - self contained low memory, cache friendly, static polymorphic target function [delegate_t<R, A...>](@ref delegate_class) storage,
64 * see [implementation details](@ref function_impl)
65 * - most operations are `noexcept`, except for the user given function invocation
66 *
67 * Instances of [jau::function](@ref function_def) can store, copy, move and invoke any of its callable targets
68 * - free functions
69 * - factory bind_free()
70 * - includes non-capturing lambda
71 * - constructor [jau::function<R(A...)>::function(R(*func)(A...))](@ref function_ctor_free)
72 * - member functions
73 * - factory bind_member()
74 * - constructor [`function(C *base, R(C::*mfunc)(A...))`](@ref function_ctor_member)
75 * - lambda functions
76 * - capturing and non-capturing lambdas as jau::function using func::lambda_target_t
77 * - constructor [`template<typename L> function(L func)`](@ref function_ctor_lambda)
78 * - see [limitations on their equality operator w/o RTTI on `gcc`](@ref function_limitations).
79 * - [Y combinator and deducing this lambda functions](@ref ylambda_target)
80 * - factory [bind_ylambda()](@ref function_bind_ylambda)
81 * - lambda alike functions using a captured data type by-reference
82 * - factory bind_capref()
83 * - constructor [function(I* data_ptr, R(*func)(I*, A...))](@ref function_ctor_capref)
84 * - lambda alike functions using a captured data type by value
85 * - factory bind_capval()
86 * - constructor copy [function(const I& data, R(*func)(I&, A...))](@ref function_ctor_capval_copy)
87 * - constructor move [function(I&& data, R(*func)(I&, A...))](@ref function_ctor_capval_move)
88 * - std::function
89 * - factory bind_std()
90 * - constructor [function(uint64_t id, std::function<R(A...)> func)](@ref function_ctor_std)
91 *
92 * @anchor function_impl
93 * #### Implementation Details
94 *
95 * `jau::function<R(A...)>` holds the static polymorphic target function [delegate_t<R, A...>](@ref delegate_class),<br />
96 * which itself completely holds up to 24 bytes sized `TriviallyCopyable` target function objects to avoiding cache misses.
97 *
98 * The following table shows the full memory footprint of the target function [delegate_t<R, A...>](@ref delegate_class) storage,<br />
99 * which equals to `jau::function<R(A...)>` memory size as it only contains the instance of delegate_t<R, A...>.
100 *
101 * | Type | Signature | Target Function Size | `%delegate_t<R, A...>` Size | Heap Size | Total Size | `TriviallyCopyable` |
102 * |:---------------|:-----------------------------|------------------------:|----------------------------:|----------:|-----------:|:-------------------:|
103 * | free | function<free, void ()> | 8 | 48 | 0 | 48 | true |
104 * | member | function<member, int (int)> | 16 | 48 | 0 | 48 | true |
105 * | lambda_plain | function<lambda, int (int)> | 24 | 48 | 0 | 48 | true |
106 * | lambda_ref | function<lambda, int (int)> | 24 | 48 | 0 | 48 | true |
107 * | lambda_copy | function<lambda, int (int)> | 24 | 48 | 0 | 48 | true |
108 * | ylambda_plain | function<ylambda, int (int)> | 24 | 48 | 0 | 48 | true |
109 * | capval (small) | function<capval, int (int)> | 16 | 48 | 0 | 48 | true |
110 * | capval (big) | function<capval, int (int)> | 48 | 48 | 48 | 96 | true |
111 * | capref | function<capref, int (int)> | 16 | 48 | 0 | 48 | true |
112 *
113 * Memory sizes are in bytes, data collected on a GNU/Linux arm64 system.
114 *
115 * The detailed memory footprint can queried at runtime, see implementation of [jau::function<R(A...)>::function::toString()](@ref function_toString).
116 *
117 * Static polymorphism is achieved by constructing the delegate_t<R, A...> instance via their func::target_type specific factories, see mapping at func::target_type.
118 *
119 * For example the static func::member_target_t::delegate constructs its specific delegate_t<R, A...> by passing its data and required functions
120 * to func::delegate_t<R, A...>::make.<br />
121 * The latter is an overloaded template for trivial and non-trivial types and decides which memory is being used,
122 * e.g. the internal 24 bytes memory cache or heap if not fitting.
123 *
124 * To support lambda identity for the equality operator, [jau::type_info](@ref type_info) is being used either with *Runtime Type Information* (RTTI) if enabled
125 * or using *Compile time type information* (CTTI), see [limitations](@ref function_limitations) below.
126 *
127 * @anchor function_usage
128 * #### Function Usage
129 *
130 * A detailed API usage is covered within [test_functional.hpp](test_functional_8hpp-example.html)
131 * and [test_functional_perf.hpp](test_functional_perf_8hpp-example.html), see function `test00_usage()`.
132 *
133 * Let's assume we like to bind to the following
134 * function prototype `bool func(int)`, which results to `jau::function<bool(int)>`:
135 *
136 * - Free functions via [constructor](@ref function_ctor_free) and jau::bind_free()
137 * - Prologue
138 * ```
139 * typedef bool(*cfunc)(int); // to force non-capturing lambda into a free function template type deduction
140 *
141 * bool my_func(int v) { return 0 == v; }
142 *
143 * struct MyClass {
144 * static bool func(int v) { return 0 == v; }
145 * };
146 * ```
147 *
148 * - Constructor [function(R(*func)(A...))](@ref function_ctor_free)
149 * ```
150 * jau::function<bool(int)> func0 = my_func;
151 *
152 * jau::function<bool(int)> func1 = &MyClass:func;
153 *
154 * jau::function<bool(int)> func2 = (cfunc) ( [](int v) -> bool { // forced free via cast
155 * return 0 == v;
156 * } );
157 *
158 * ```
159 *
160 * - Factory `jau::bind_free(R(*func)(A...))`
161 * ```
162 * jau::function<bool(int)> func0 = jau::bind_free(&MyClass:func);
163 *
164 * jau::function<bool(int)> func1 = jau::bind_free(my_func);
165 * ```
166 *
167 * - Class member functions via [constructor](@ref function_ctor_member) and jau::bind_member()
168 * - Prologue
169 * ```
170 * struct MyClass {
171 * bool m_func(int v) { return 0 == v; }
172 * };
173 * MyClass i1;
174 * ```
175 *
176 * - Constructor [function(C *base, R(C::*mfunc)(A...))](@ref function_ctor_member)
177 * ```
178 * jau::function<bool(int)> func(&i1, &MyClass::m_func);
179 * ```
180 *
181 * - Factory `jau::bind_member(C *base, R(C::*mfunc)(A...))`
182 * ```
183 * jau::function<bool(int)> func = jau::bind_member(&i1, &MyClass::m_func);
184 * ```
185 *
186 * - Lambda functions via [constructor](@ref function_ctor_lambda)
187 * - Prologue
188 * ```
189 * int sum = 0;
190 * ```
191 *
192 * - Stateless lambda, equivalent to `bool(*)(int)` function
193 * ```
194 * jau::function<bool(int)> func0 = [](int v) -> bool {
195 * return 0 == v;
196 * };
197 * ```
198 *
199 * - Stateless by-value capturing lambda
200 * ```
201 * jau::function<bool(int)> func1 = [sum](int v) -> bool {
202 * return sum == v;
203 * };
204 * ```
205 *
206 * - Stateful by-value capturing lambda mutating captured field
207 * ```
208 * jau::function<bool(int)> func1 = [sum](int v) mutable -> bool {
209 * sum += v;
210 * return 0 == v;
211 * };
212 * ```
213 *
214 * - Stateless by-reference capturing lambda
215 * ```
216 * jau::function<bool(int)> func1 = [&sum](int v) -> bool {
217 * sum += v;
218 * return 0 == v;
219 * };
220 * ```
221 *
222 * - Stateless by-reference capturing lambda assigning an auto lambda
223 * ```
224 * auto lambda_func = [&](int v) -> bool {
225 * sum += v;
226 * return 0 == v;
227 * };
228 *
229 * jau::function<bool(int)> func1 = lambda_func;
230 * jau::function<bool(int)> func2 = lambda_func;
231 * assert( func1 == func2 );
232 * ```
233 *
234 * - [Y combinator and deducing this lambda functions](@ref ylambda_target) via factory [bind_ylambda()](@ref function_bind_ylambda)
235 * - Stateless lambda receiving explicit this object parameter reference used for recursion using `auto`
236 * ```
237 * function<int(int)> f = function<int(int)>::bind_ylambda( [](auto& self, int x) -> int {
238 * if( 0 == x ) {
239 * return 1;
240 * } else {
241 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
242 * }
243 * } );
244 * assert( 24 == f(4) ); // `self` is bound to function<int(int)>::delegate_type `f.target`, `x` is 4
245 * ```
246 *
247 * - or using explicit `function<R(A...)>::delegate_type`
248 * ```
249 * function<int(int)> f = function<int(int)>::bind_ylambda( [](function<int(int)>::delegate_type& self, int x) -> int {
250 * if( 0 == x ) {
251 * return 1;
252 * } else {
253 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
254 * }
255 * } );
256 * assert( 24 == f(4) ); // `self` is bound to function<int(int)>::delegate_type `f.target`, `x` is 4
257 * ```
258 *
259 * - Lambda alike capture by-reference to value via [constructor](@ref function_ctor_capref) and jau::bind_capref()
260 * - Prologue
261 * ```
262 * struct big_data {
263 * int sum;
264 * };
265 * big_data data { 0 };
266 *
267 * typedef bool(*cfunc)(big_data*, int); // to force non-capturing lambda into a free function template type deduction
268 * ```
269 *
270 * - Constructor [function(I* data_ptr, R(*func)(I*, A...))](@ref function_ctor_capref)
271 * ```
272 * function<int(int)> func(&data,
273 * (cfunc) ( [](big_data* data, int v) -> bool {
274 * stats_ptr->sum += v;
275 * return 0 == v;
276 * } ) );
277 * ```
278 *
279 * - Factory `jau::bind_capref(I* data_ptr, R(*func)(I*, A...))`
280 * ```
281 * jau::function<bool(int)> func = jau::bind_capref(&data,
282 * (cfunc) ( [](big_data* data, int v) -> bool {
283 * stats_ptr->sum += v;
284 * return 0 == v;
285 * } ) );
286 * ```
287 *
288 * - Lambda alike capture by-copy of value via constructor and jau::bind_capval()
289 * - Constructor copy [function(const I& data, R(*func)(I&, A...))](@ref function_ctor_capval_copy)
290 * - Constructor move [function(I&& data, R(*func)(I&, A...))](@ref function_ctor_capval_move)
291 * - Factory copy `jau::bind_capval(const I& data, R(*func)(I&, A...))`
292 * - Factory move `jau::bind_capval(I&& data, R(*func)(I&, A...))` <br />
293 * See example of *Capture by-reference to value* above.
294 *
295 * - std::function function via [constructor](@ref function_ctor_std) and jau::bind_std()
296 * - Prologue
297 * ```
298 * std::function<bool(int)> func_stdlambda = [](int i)->bool {
299 * return 0 == i;
300 * };
301 * ```
302 *
303 * - Constructor [function(uint64_t id, std::function<R(A...)> func)](@ref function_ctor_std)
304 * ```
305 * jau::function<bool(int)> func(100, func_stdlambda);
306 * ```
307 *
308 * - Factory `jau::bind_std(uint64_t id, std::function<R(A...)> func)`
309 * ```
310 * jau::function<bool(int)> func = jau::bind_std(100, func_stdlambda);
311 * ```
312 * @anchor function_limitations
313 * #### Function Limitations
314 *
315 * ##### Non unique lambda type names without RTTI using `gcc` or non `clang` compiler
316 *
317 * Due to [limitations of jau::make_ctti<R, L, A...>()](@ref ctti_name_lambda_limitations),
318 * *not using RTTI on `gcc` or non `clang` compiler* will *erroneously mistake* different lambda
319 * *functions defined within one function and using same function prototype `R<A...>`* to be the same.
320 *
321 * jau::type_info::limited_lambda_id will expose the potential limitation.
322 *
323 * See [CTTI lambda name limitations](@ref ctti_name_lambda_limitations) and [limitations of jau::type_info](@ref type_info_limitations).
324 *
325 * @{
326 */
327
328 namespace func {
329
330 /** \addtogroup FunctionWrap
331 *
332 * @{
333 */
334
335 /**
336 * func::target_type identifier for the target function [delegate_t<R, A...>](@ref delegate_class) object,
337 * exposed by jau::function<R(A...)>::type().
338 *
339 * @see @ref function_overview "Function Overview"
340 */
341 enum class target_type : uint32_t {
342 /** Denotes a func::null_target_t */
343 null = 0,
344 /** Denotes a func::member_target_t */
345 member = 1,
346 /** Denotes a func::free_target_t */
347 free = 2,
348 /** Denotes a func::lambda_target_t */
349 lambda = 3,
350 /** Denotes a func::ylambda_target_t */
351 ylambda = 4,
352 /** Denotes a func::capval_target_t */
353 capval = 5,
354 /** Denotes a func::capref_target_t */
355 capref = 6,
356 /** Denotes a func::std_target_t */
357 std = 7
358 };
359
360 /**
361 * Delegated target function object, providing a fast path target function invocation.
362 *
363 * @anchor delegate_class This static polymorphic target function delegate_t<R, A...> is contained by [function<R(A...)>](@ref function_def)
364 * and completely holds up to 24 bytes sized `TriviallyCopyable` target function objects to avoiding cache misses.
365 * - contained within [function<R(A...)>](@ref function_def) instance as a member
366 * - avoiding need for dynamic polymorphism, i.e. heap allocated specialization referenced by base type
367 * - using non-heap cache for up to 24 bytes sized `TriviallyCopyable` target function objects
368 * - enhancing performance on most target function types by avoiding cache misses
369 * - not using virtual function table indirection
370 * - utilize constexpr inline for function invocation (callbacks)
371 *
372 * @tparam R function return type
373 * @tparam A function arguments
374 * @see @ref function_overview "Function Overview"
375 */
376 template<typename R, typename... A>
377 class delegate_t final { // 48 [ + vsize ]
378 public:
379 /**
380 * Utilize a reduced size type of int32_t.
381 * Negative sign indicates limited 24 bytes cache usage, otherwise heap is being used.
382 */
383 typedef int32_t size_type;
384
385 protected:
386 typedef R(*invocation_t)(delegate_t* __restrict_cxx__ const data, A... args);
387 typedef bool(*equal_op_t)(const delegate_t& data_lhs, const delegate_t& data_rhs) noexcept;
388
389 private:
390 struct non_trivial_t final { // 3 * 8 = 24
391 typedef void(*dtor_t) (delegate_t*);
392 typedef void(*copy_ctor_t) (delegate_t*, const delegate_t*);
393 typedef void(*move_ctor_t) (delegate_t*, delegate_t*);
394 dtor_t dtor;
395 copy_ctor_t copy_ctor;
396 move_ctor_t move_ctor;
397
398 constexpr non_trivial_t() noexcept
399 : dtor(nullptr), copy_ctor(nullptr), move_ctor(nullptr)
400 { }
401 };
402
403 struct heap_t final { // 16 [ + vsize ] [ + 24 ]
404 void* memory;
405 non_trivial_t* non_trivial;
406 };
407
408 /**
409 * Cases
410 * - trivial + sdata (fast path)
411 * - trivial + vdata
412 * - !trivial + vdata
413 */
414 union target_data_t { // 24
415 uint8_t cache[24]; // size <= 0, 24 bytes local high perf cached chunk
416 heap_t heap; // size > 0, 32
417 };
418
419 target_data_t udata;
420
421 /** Delegated specialization callback. (local) */
422 invocation_t m_cb; // 8
423 /** Delegated specialization equality operator. (local) */
424 equal_op_t m_eqop; // 8
425
426 size_type m_size; // 4
427 target_type m_type; // 4
428
429 /**
430 * For `TriviallyCopyable` only, using sdata or vdata.
431 */
432 delegate_t(target_type type_, size_type size_, invocation_t cb_, equal_op_t eqop_) noexcept
433 : m_cb(cb_), m_eqop(eqop_), m_size( size_ ), m_type(type_)
434 {
435 if( static_cast<size_type>( sizeof(udata.cache) ) >= m_size ) {
436 // using sdata
437 m_size *= -1;
438 } else {
439 // using vdata
440 udata.heap.memory = ::malloc(m_size);
441 udata.heap.non_trivial = nullptr;
442 }
443 }
444
445 /**
446 * Non `TriviallyCopyable` only, using vdata.
447 */
448 delegate_t(target_type type_, size_type size_, const non_trivial_t& nt, invocation_t cb_, equal_op_t eqop_) noexcept
449 : m_cb(cb_), m_eqop(eqop_), m_size( size_ ), m_type(type_)
450 {
451 try {
452 udata.heap.non_trivial = new non_trivial_t(nt);
453 } catch (const std::bad_alloc &e) {
454 ABORT("Error: bad_alloc: non_trivial allocation failed");
455 return; // unreachable
456 }
457 udata.heap.memory = ::malloc(m_size);
458 }
459
460 void clear() noexcept {
461 if( m_size > 0 ) {
462 if( nullptr != udata.heap.non_trivial ) {
463 udata.heap.non_trivial->dtor(this);
464 delete udata.heap.non_trivial;
465 udata.heap.non_trivial = nullptr;
466 }
467 ::free(udata.heap.memory);
468 udata.heap.memory = nullptr;
469 }
470 m_size = 0;
471 }
472
473 public:
474 // null type
475 static delegate_t make(invocation_t cb_, equal_op_t eqop_) noexcept
476 {
477 return delegate_t(target_type::null, 0, cb_, eqop_);
478 }
479
480 // `TriviallyCopyable` using cache or heap
481 template<typename T, typename... P,
482 std::enable_if_t<std::is_trivially_copyable_v<T> &&
484 bool> = true>
485 static delegate_t make(target_type type_, invocation_t cb_, equal_op_t eqop_, P... params) noexcept
486 {
487 delegate_t target(type_, static_cast<size_type>( sizeof(T) ), cb_, eqop_);
488 new( target.template data<T>() ) T(params...); // placement new
489 return target;
490 }
491
492 // Non `TriviallyCopyable` using heap
493 template<typename T, typename... P,
494 std::enable_if_t<!std::is_trivially_copyable_v<T> &&
496 std::is_destructible_v<T> &&
497 std::is_copy_constructible_v<T> &&
498 std::is_move_constructible_v<T>,
499 bool> = true>
500 static delegate_t make(target_type type_, invocation_t cb_, equal_op_t eqop_, P... params) noexcept
501 {
502 non_trivial_t nt;
503 nt.dtor = [](delegate_t* i) -> void {
504 T* t = i->template data<T>();
505 if( nullptr != t ) {
506 t->T::~T(); // placement new -> manual destruction!
507 }
508 };
509 nt.copy_ctor = [](delegate_t* i, const delegate_t* o) -> void {
510 new( i->template data<T>() ) T( *( o->template data<T>() ) ); // placement new copy-ctor
511 };
512 nt.move_ctor = [](delegate_t* i, delegate_t* o) -> void {
513 new( i->template data<T>() ) T( std::move( *( o->template data<T>() ) ) ); // placement new move-ctor
514 };
515 delegate_t target(type_, static_cast<size_type>( sizeof(T) ), nt, cb_, eqop_);
516 new( target.template data<T>() ) T(params...); // placement new
517 return target;
518 }
519
520 ~delegate_t() noexcept { clear(); }
521
522 delegate_t(const delegate_t& o) noexcept
523 : m_cb( o.m_cb ), m_eqop( o.m_eqop ),
524 m_size(o.m_size), m_type( o.m_type )
525 {
526 if( m_size > 0 ) {
527 udata.heap.memory = ::malloc(m_size);
528 if( nullptr == udata.heap.memory ) {
529 ABORT("Error: bad_alloc: heap.memory allocation failed");
530 return; // unreachable
531 }
532 if( nullptr != o.udata.heap.non_trivial ) {
533 try {
534 udata.heap.non_trivial = new non_trivial_t( *o.udata.heap.non_trivial );
535 } catch (const std::bad_alloc &e) {
536 ABORT("Error: bad_alloc: non_trivial allocation failed");
537 return; // unreachable
538 }
539 udata.heap.non_trivial->copy_ctor(this, &o);
540 } else {
541 udata.heap.non_trivial = nullptr;
542 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
543 }
544 } else {
545 ::memcpy(udata.cache, o.udata.cache, std::abs(m_size));
546 }
547 }
548
549 delegate_t(delegate_t&& o) noexcept
550 : m_cb( std::move( o.m_cb ) ), m_eqop( std::move( o.m_eqop ) ),
551 m_size( std::move( o.m_size ) ), m_type( std::move( o.m_type ) )
552 {
553 if( m_size > 0 ) {
554 udata.heap.non_trivial = std::move( o.udata.heap.non_trivial );
555 o.udata.heap.non_trivial = nullptr;
556 if( nullptr != udata.heap.non_trivial ) {
557 udata.heap.memory = ::malloc(o.m_size);
558 if( nullptr == udata.heap.memory ) {
559 ABORT("Error: bad_alloc: heap.memory allocation failed");
560 return; // unreachable
561 }
562 udata.heap.non_trivial->move_ctor(this, &o);
563 udata.heap.non_trivial->dtor(&o);
564 ::free(o.udata.heap.memory);
565 } else {
566 udata.heap.memory = std::move( o.udata.heap.memory );
567 }
568 o.udata.heap.memory = nullptr;
569 } else {
570 ::memcpy(udata.cache, o.udata.cache, std::abs(m_size));
571 }
572 o.m_size = 0;
573 }
574
575 delegate_t& operator=(const delegate_t &o) noexcept
576 {
577 if( this == &o ) {
578 return *this;
579 }
580 m_cb = o.m_cb;
581 m_eqop = o.m_eqop;
582 m_type = o.m_type;
583
584 if( 0 >= m_size && 0 >= o.m_size ) {
585 // sdata: copy
586 m_size = o.m_size;
587
588 ::memcpy(udata.cache, o.udata.cache, std::abs(m_size));
589 } else if( m_size > 0 && o.m_size > 0 && m_size <= o.m_size ) {
590 // vdata: reuse memory
591 m_size = o.m_size;
592
593 if( nullptr != udata.heap.non_trivial ) {
594 udata.heap.non_trivial->dtor(this);
595 if( nullptr != o.udata.heap.non_trivial ) {
596 *udata.heap.non_trivial = *o.udata.heap.non_trivial;
597 } else {
598 delete udata.heap.non_trivial;
599 udata.heap.non_trivial = nullptr;
600 }
601 }
602 if( nullptr != udata.heap.non_trivial ) {
603 udata.heap.non_trivial->copy_ctor(this, &o);
604 } else {
605 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
606 }
607 } else {
608 // reset
609 clear();
610 m_size = o.m_size;
611
612 if( m_size > 0 ) {
613 udata.heap.memory = ::malloc(m_size);
614 if( nullptr == udata.heap.memory ) {
615 ABORT("Error: bad_alloc: heap.memory allocation failed");
616 return *this; // unreachable
617 }
618 if( nullptr != o.udata.heap.non_trivial ) {
619 try {
620 udata.heap.non_trivial = new non_trivial_t( *o.udata.heap.non_trivial );
621 } catch (const std::bad_alloc &e) {
622 ABORT("Error: bad_alloc: non_trivial allocation failed");
623 return *this; // unreachable
624 }
625 udata.heap.non_trivial->copy_ctor(this, &o);
626 } else {
627 udata.heap.non_trivial = nullptr;
628 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
629 }
630 } else {
631 ::memcpy(udata.cache, o.udata.cache, std::abs(m_size));
632 }
633 }
634 return *this;
635 }
636
638 {
639 if( this == &o ) {
640 return *this;
641 }
642 clear();
643
644 m_cb = std::move( o.m_cb );
645 m_eqop = std::move( o.m_eqop );
646 m_size = std::move( o.m_size );
647 m_type = std::move( o.m_type );
648
649 if( m_size > 0 ) {
650 udata.heap.non_trivial = std::move( o.udata.heap.non_trivial );
651 o.udata.heap.non_trivial = nullptr;
652 if( nullptr != udata.heap.non_trivial ) {
653 udata.heap.memory = ::malloc(o.m_size);
654 if( nullptr == udata.heap.memory ) {
655 ABORT("Error: bad_alloc: heap.memory allocation failed");
656 return *this; // unreachable
657 }
658 udata.heap.non_trivial->move_ctor(this, &o);
659 udata.heap.non_trivial->dtor(&o);
660 ::free(o.udata.heap.memory);
661 } else {
662 udata.heap.memory = std::move( o.udata.heap.memory );
663 }
664 o.udata.heap.memory = nullptr;
665 } else {
666 ::memcpy(udata.cache, o.udata.cache, std::abs(m_size));
667 }
668 o.m_size = 0;
669 return *this;
670 }
671
672 template<typename T,
673 std::enable_if_t<std::is_trivially_copyable_v<T> &&
674 sizeof(udata.cache) >= sizeof(T),
675 bool> = true>
676 constexpr const T* data() const noexcept {
677 return static_cast<const T*>( static_cast<const void*>( udata.cache ) );
678 }
679
680 template<typename T,
681 std::enable_if_t<!std::is_trivially_copyable_v<T> ||
682 sizeof(udata.cache) < sizeof(T),
683 bool> = true>
684 constexpr const T* data() const noexcept {
685 return static_cast<const T*>( udata.heap.memory );
686 }
687
688 template<typename T,
689 std::enable_if_t<std::is_trivially_copyable_v<T> &&
690 sizeof(udata.cache) >= sizeof(T),
691 bool> = true>
692 constexpr T* data() noexcept {
693 return static_cast<T*>( static_cast<void*>( udata.cache ) );
694 }
695
696 template<typename T,
697 std::enable_if_t<!std::is_trivially_copyable_v<T> ||
698 sizeof(udata.cache) < sizeof(T),
699 bool> = true>
700 constexpr T* data() noexcept {
701 return static_cast<T*>( udata.heap.memory );
702 }
703
704 /**
705 * \brief Delegated fast path target function invocation, [see above](@ref delegate_class)
706 *
707 * @param args target function arguments
708 * @return target function result
709 */
710 constexpr R operator()(A... args) const {
711 return m_cb(const_cast<delegate_t*>(this), args...);
712 }
713
714 /**
715 * \brief Delegated fast path target function equality operator
716 *
717 * @param rhs
718 * @return
719 */
720 constexpr bool operator==(const delegate_t<R, A...>& rhs) const noexcept {
721 return m_eqop(*this, rhs);
722 }
723
724 /** Returns true if the underlying target function is `TriviallyCopyable`. */
725 constexpr bool is_trivially_copyable() const noexcept { return 0 >= m_size || nullptr == udata.heap.non_trivial; }
726
727 constexpr size_t heap_size() const noexcept { return 0 >= m_size ? 0 : ( m_size + ( nullptr != udata.heap.non_trivial ? sizeof(*udata.heap.non_trivial) : 0 ) ); }
728 constexpr size_t cached_size() const noexcept { return 0 >= m_size ? std::abs(m_size) : 0; }
729
730 /** Returns the size of underlying target function */
731 constexpr size_t target_size() const noexcept { return std::abs(m_size); }
732
733 /** Return the func::target_type of this invocation function wrapper */
734 constexpr target_type type() const noexcept { return m_type; }
735 };
736
737 /**
738 * func::null_target_t implementation for no function.
739 * identifiable as jau::func::target_type::null via jau::function<R(A...)>::type().
740 *
741 * This special type is used for an empty [jau::function](@ref function_def) instance w/o holding a function,
742 * e.g. when created with the default constructor.
743 *
744 * @tparam R function return type
745 * @tparam A function arguments
746 * @see @ref function_overview "Function Overview"
747 */
748 template<typename R, typename... A>
749 class null_target_t final {
750 public:
751 typedef delegate_t<R, A...> delegate_type;
752
753 private:
754 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const, A...) {
755 return R();
756 }
757
758 constexpr static bool equal_op_impl(const delegate_type& lhs, const delegate_type& rhs) noexcept {
759 return lhs.type() == rhs.type();
760 }
761
762 constexpr static void dtor(delegate_type* target) noexcept {
763 (void)target;
764 }
765
766 public:
767 static delegate_type delegate() noexcept {
768 return delegate_type::make(invoke_impl, equal_op_impl);
769 }
770 };
771
772 /**
773 * func::member_target_t implementation for class member functions,
774 * identifiable as func::target_type::member via jau::function<R(A...)>::type().
775 *
776 * @tparam R function return type
777 * @tparam C0 class type holding the member-function
778 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
779 * @tparam A function arguments
780 * @see @ref function_overview "Function Overview"
781 */
782 template<typename R, typename C0, typename C1, typename... A>
783 class member_target_t final {
784 public:
785 typedef delegate_t<R, A...> delegate_type;
786
787 private:
788
789#if defined(__GNUC__) && !defined(__clang__)
790 /**
791 * Utilizing GCC C++ Extension: Pointer to Member Function (PMF) Conversion to function pointer
792 * - Reduces function pointer size, i.e. PMF 16 (total 24) -> function 8 (total 16)
793 * - Removes vtable lookup at invocation (performance)
794 * - Pass object this pointer to function as 1st argument
795 * - See [GCC PMF Conversion](https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html#Bound-member-functions)
796 */
797 typedef R(*function_t)(C0*, A...);
798
799 struct data_type final {
800 function_t function;
801 C1* base;
802
803 constexpr data_type(C1 *_base, R(C0::*_method)(A...)) noexcept
804 : base(_base)
805 {
808 function = (function_t)(_base->*_method);
810 }
811 };
812
813 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
814 data_type * __restrict_cxx__ const d = data->template data<data_type>();
815 return ( *(d->function) )(d->base, args...);
816 }
817
818 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
819 const data_type* lhs = lhs_.template data<const data_type>();
820 const data_type* rhs = rhs_.template data<const data_type>();
821 return lhs == rhs ||
822 ( lhs_.type() == rhs_.type() &&
823 lhs->base == rhs->base &&
824 lhs->function== rhs->function
825 );
826 }
827#else
828 /**
829 * C++ conform Pointer to Member Function (PMF)
830 */
831 struct data_type final {
832 C1* base;
833 R(C0::*method)(A...);
834
835 constexpr data_type(C1 *_base, R(C0::*_method)(A...)) noexcept
836 : base(_base), method(_method) { }
837 };
838
839 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
840 data_type * __restrict_cxx__ const d = data->template data<data_type>();
841 return (d->base->*d->method)(args...);
842 }
843
844 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
845 const data_type* lhs = lhs_.template data<const data_type>();
846 const data_type* rhs = rhs_.template data<const data_type>();
847 return lhs == rhs ||
848 ( lhs_.type() == rhs_.type() &&
849 lhs->base == rhs->base &&
850 lhs->method == rhs->method
851 );
852 }
853#endif
854
855 public:
856 /**
857 * Construct a delegate_t<R, A...> instance from given this base-pointer and member-function.
858 *
859 * This factory function is only enabled if C0 is base of C1.
860 *
861 * @param base this base-pointer of class C1 derived from C0 or C0 used to invoke the member-function
862 * @param method member-function of class C0
863 * @return delegate_t<R, A...> instance holding the target-function object.
864 */
865 static delegate_type delegate(C1 *base, R(C0::*method)(A...),
866 std::enable_if_t<std::is_base_of_v<C0, C1>, bool> = true) noexcept
867 {
868 return delegate_type::template make<data_type>( target_type::member, invoke_impl, equal_op_impl, base, method );
869 }
870 };
871
872 /**
873 * func::free_target_t implementation for free functions,
874 * identifiable as func::target_type::free via jau::function<R(A...)>::type().
875 *
876 * @tparam R function return type
877 * @tparam A function arguments
878 * @see @ref function_overview "Function Overview"
879 */
880 template<typename R, typename... A>
881 class free_target_t final {
882 public:
883 typedef delegate_t<R, A...> delegate_type;
884
885 private:
886 struct data_type final {
887 R(*function)(A...);
888
889 data_type(R(*_function)(A...)) noexcept
890 : function(_function) { }
891 };
892
893 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
894 return ( *(data->template data<data_type>()->function) )(args...);
895 }
896
897 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
898 const data_type* lhs = lhs_.template data<const data_type>();
899 const data_type* rhs = rhs_.template data<const data_type>();
900 return lhs == rhs ||
901 ( lhs_.type() == rhs_.type() &&
902 lhs->function== rhs->function
903 );
904 }
905
906 public:
907 static delegate_type delegate(R(*function)(A...)) noexcept {
908 return delegate_type::template make<data_type>( target_type::free, invoke_impl, equal_op_impl, function );
909 }
910 };
911
912 /**
913 * func::lambda_target_t implementation for lambda closures,
914 * identifiable as func::target_type::lambda via jau::function<R(A...)>::type().
915 *
916 * @tparam R function return type
917 * @tparam L typename holding the lambda closure
918 * @tparam A function arguments
919 * @see @ref function_overview "Function Overview"
920 */
921 template<typename R, typename L, typename...A>
922 class lambda_target_t final {
923 public:
924 typedef delegate_t<R, A...> delegate_type;
925
926 private:
927 struct data_type final {
928 L function;
929 jau::type_info sig;
930
931 data_type(L _function) noexcept
932 : function( _function ), sig( jau::make_ctti<R, L, A...>() ) {}
933
934 constexpr size_t detail_size() const noexcept { return sizeof(function); }
935 };
936
937 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
938 return ( data->template data<data_type>()->function )(args...);
939 }
940
941 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
942 const data_type* lhs = lhs_.template data<const data_type>();
943 const data_type* rhs = rhs_.template data<const data_type>();
944 return lhs == rhs ||
945 ( lhs_.type() == rhs_.type() &&
946 lhs->detail_size() == rhs->detail_size() && // fast: wrong size -> false, otherwise ...
947 lhs->sig == rhs->sig && // mixed: wrong jau::type_info -> false, otherwise ...
948 0 == ::memcmp((void*)&lhs->function, (void*)&rhs->function, sizeof(lhs->function)) // slow: compare the anonymous data chunk of the lambda
949 );
950 }
951
952 public:
953 static delegate_type delegate(L function) noexcept {
954 return delegate_type::template make<data_type>( target_type::lambda, invoke_impl, equal_op_impl, function );
955 }
956 };
957
958 /**
959 * func::ylambda_target_t is a [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
960 * and [deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html) implementation for lambda closures
961 * usable for recursive algorithms.
962 *
963 * @anchor ylambda_target The [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
964 * allows passing the unnamed lambda instance itself, enabling recursive invocation from within the lambda. <br />
965 * In other words, a `this` reference of the unnamed lambda is passed to the lambda, similar to [`Deducing this`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html).
966 *
967 * The ylambda [function<R(A...)>](@ref function_def) is invoked w/o explicitly passing the object parameter,
968 * as it is implicitly passed down to the user's lambda implementation.
969 *
970 * Example implementing a recursive lambda factorial function
971 *
972 * ```
973 * function<int(int)> f1 = function<int(int)>::bind_ylambda( [](auto& self, int x) -> int {
974 * if( 0 == x ) {
975 * return 1;
976 * } else {
977 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
978 * }
979 * } );
980 * assert( 24 == f1(4) ); // `self` is bound to delegate<R(A...)> `f.target`, `x` is 4
981 *
982 * // or using explicit function<R(A...)>::delegate_type
983 *
984 * function<int(int)> f2 = function<int(int)>::bind_ylambda( [](function<int(int)>::delegate_type& self, int x) -> int {
985 * if( 0 == x ) {
986 * return 1;
987 * } else {
988 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
989 * }
990 * } );
991 * assert( 24 == f2(4) ); // `self` is bound to function<int(int)>::delegate_type `f.target`, `x` is 4
992 * ```
993 *
994 * An instance is identifiable as func::target_type::ylambda via jau::function<R(A...)>::type().
995 *
996 * @tparam R function return type
997 * @tparam L typename holding the lambda closure
998 * @tparam A function arguments
999 * @see @ref function_overview "Function Overview"
1000 * @see [Deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html)
1001 * @see [Explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
1002 * @see [Curiously Recurring Template Pattern](https://en.cppreference.com/w/cpp/language/crtp)
1003 */
1004 template<typename R, typename L, typename...A>
1005 class ylambda_target_t final {
1006 public:
1007 typedef delegate_t<R, A...> delegate_type;
1008
1009 private:
1010 struct data_type final {
1011 L function;
1012 jau::type_info sig;
1013
1014 data_type(L _function) noexcept
1015 : function( _function ), sig( jau::make_ctti<R, L, A...>() ) {
1016 // jau::type_cue<L>::print("ylambda_target_t.lambda", TypeTraitGroup::ALL);
1017 // jau::type_cue<data_type>::print("ylambda_target_t.data_type", TypeTraitGroup::ALL);
1018 // fprintf(stderr, "ylambda_target: %s\n\t\tsize %zu, %p: %s\n",
1019 // sig.name(), sizeof(L), &function, jau::bytesHexString(&function, 0, sizeof(L), true).c_str());
1020 }
1021
1022 constexpr size_t detail_size() const noexcept { return sizeof(function); }
1023 };
1024
1025 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1026 return ( data->template data<data_type>()->function )(*data, args...);
1027 }
1028
1029 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1030 const data_type* lhs = lhs_.template data<const data_type>();
1031 const data_type* rhs = rhs_.template data<const data_type>();
1032 return lhs == rhs ||
1033 ( lhs_.type() == rhs_.type() &&
1034 lhs->detail_size() == rhs->detail_size() && // fast: wrong size -> false, otherwise ...
1035 lhs->sig == rhs->sig && // mixed: wrong jau::type_info -> false, otherwise ...
1036 0 == ::memcmp((void*)&lhs->function, (void*)&rhs->function, sizeof(lhs->function)) // slow: compare the anonymous data chunk of the lambda
1037 );
1038 }
1039
1040 public:
1041 static delegate_type delegate(L function) noexcept {
1042 return delegate_type::template make<data_type>( target_type::ylambda, invoke_impl, equal_op_impl, function );
1043 }
1044 };
1045
1046 /**
1047 * func::capval_target_t implementation for functions using a copy of a captured value,
1048 * identifiable as func::target_type::capval via jau::function<R(A...)>::type().
1049 *
1050 * @tparam R function return type
1051 * @tparam I typename holding the captured data used by the function
1052 * @tparam A function arguments
1053 * @see @ref function_overview "Function Overview"
1054 */
1055 template<typename R, typename I, typename... A>
1056 class capval_target_t final {
1057 public:
1058 typedef delegate_t<R, A...> delegate_type;
1059
1060 private:
1061 struct data_type final {
1062 R(*function)(I&, A...);
1063 I data;
1064
1065 data_type(const I& _data, R(*_function)(I&, A...)) noexcept
1066 : function(_function), data(_data) {}
1067
1068 data_type(I&& _data, R(*_function)(I&, A...)) noexcept
1069 : function(_function), data(std::move(_data)) {}
1070 };
1071
1072 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1073 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1074 return (*d->function)(d->data, args...);
1075 }
1076
1077 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1078 const data_type* lhs = lhs_.template data<const data_type>();
1079 const data_type* rhs = rhs_.template data<const data_type>();
1080 return lhs == rhs ||
1081 ( lhs_.type() == rhs_.type() &&
1082 lhs->function == rhs->function &&
1083 lhs->data == rhs->data
1084 );
1085 }
1086
1087 public:
1088 static delegate_type delegate(const I& data, R(*function)(I&, A...)) noexcept {
1089 return delegate_type::template make<data_type>( target_type::capval, invoke_impl, equal_op_impl, data, function );
1090 }
1091
1092 static delegate_type delegate(I&& data, R(*function)(I&, A...)) noexcept {
1093 return delegate_type::template make<data_type>( target_type::capval, invoke_impl, equal_op_impl, std::move(data), function );
1094 }
1095 };
1096
1097 /**
1098 * func::capref_target_t implementation for functions using a reference to a captured value,
1099 * identifiable as func::target_type::capref via jau::function<R(A...)>::type().
1100 *
1101 * @tparam R function return type
1102 * @tparam I typename holding the captured data used by the function
1103 * @tparam A function arguments
1104 * @see @ref function_overview "Function Overview"
1105 */
1106 template<typename R, typename I, typename... A>
1107 class capref_target_t final {
1108 public:
1109 typedef delegate_t<R, A...> delegate_type;
1110
1111 private:
1112 struct data_type final {
1113 R(*function)(I*, A...);
1114 I* data_ptr;
1115
1116 data_type(I* _data_ptr, R(*_function)(I*, A...)) noexcept
1117 : function(_function), data_ptr(_data_ptr) {}
1118 };
1119
1120 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1121 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1122 return (*d->function)(d->data_ptr, args...);
1123 }
1124
1125 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1126 const data_type* lhs = lhs_.template data<const data_type>();
1127 const data_type* rhs = rhs_.template data<const data_type>();
1128 return lhs == rhs ||
1129 ( lhs_.type() == rhs_.type() &&
1130 lhs->function == rhs->function &&
1131 lhs->data_ptr == rhs->data_ptr
1132 );
1133 }
1134
1135 public:
1136 static delegate_type delegate(I* data_ptr, R(*function)(I*, A...)) noexcept {
1137 return delegate_type::template make<data_type>( target_type::capref, invoke_impl, equal_op_impl, data_ptr, function );
1138 }
1139 };
1140
1141 /**
1142 * func::std_target_t implementation for std::function instances,
1143 * identifiable as func::target_type::std via jau::function<R(A...)>::type().
1144 *
1145 * Notable, instance is holding a unique uint64_t identifier
1146 * to allow implementing the equality operator, not supported by std::function.
1147 *
1148 * @tparam R function return type
1149 * @tparam A function arguments
1150 * @see @ref function_overview "Function Overview"
1151 */
1152 template<typename R, typename... A>
1153 class std_target_t final {
1154 public:
1155 typedef delegate_t<R, A...> delegate_type;
1156
1157 private:
1158 struct data_type final {
1159 std::function<R(A...)> function;
1160 uint64_t id;
1161
1162 data_type(uint64_t id_, std::function<R(A...)> function_) noexcept
1163 : function(std::move(function_)), id(id_) {}
1164
1165 constexpr size_t detail_size() const noexcept { return sizeof(id)+sizeof(function); }
1166 };
1167
1168 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1169 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1170 if( d->function ) {
1171 return d->function(args...);
1172 } else {
1173 return R();
1174 }
1175 }
1176
1177 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1178 const data_type* lhs = lhs_.template data<const data_type>();
1179 const data_type* rhs = rhs_.template data<const data_type>();
1180 return lhs == rhs ||
1181 ( lhs_.type() == rhs_.type() &&
1182 lhs->id == rhs->id &&
1183 lhs->detail_size() && rhs->detail_size()
1184 );
1185 }
1186
1187 public:
1188 static delegate_type delegate(uint64_t id, std::function<R(A...)> function) noexcept {
1189 return delegate_type::template make<data_type>( target_type::std, invoke_impl, equal_op_impl, id, function );
1190 }
1191 };
1192 /**@}*/
1193
1194 } /* namespace func */
1195
1196 constexpr uint32_t number(const func::target_type rhs) noexcept {
1197 return static_cast<uint32_t>(rhs);
1198 }
1199 std::string to_string(const func::target_type v) noexcept;
1200
1201 /**
1202 * Class template [jau::function](@ref function_def) is a general-purpose static-polymorphic function wrapper.
1203 *
1204 * See @ref function_overview "Function Overview".
1205 *
1206 * This is the dummy template variant, allowing the void- and non-void return type target specializations.
1207 *
1208 * @see @ref function_def "Function template definition"
1209 */
1210 template<typename Signature>
1212
1213 /**
1214 * @anchor function_def Class template [jau::function](@ref function_def) is a general-purpose static-polymorphic function wrapper.
1215 *
1216 * See @ref function_overview "Function Overview".
1217 *
1218 * @tparam R function return type
1219 * @tparam A function arguments
1220 * @see @ref function_overview "Function Overview"
1221 * @see @ref function_usage "Function Usage"
1222 */
1223 template<typename R, typename... A>
1224 class function<R(A...)> final {
1225 public:
1226 /** The delegated target function type, i.e. func::delegate_t<R, A...> */
1228
1229 private:
1230 delegate_type target;
1231
1232 public:
1233 /** The target function return type R */
1234 typedef R result_type;
1235
1236 /**
1237 * \brief Null function constructor
1238 *
1239 * @anchor function_ctor_def
1240 * Constructs an instance with a null target function.
1241 * @see @ref function_overview "function Overview"
1242 * @see @ref function_usage "function Usage"
1243 */
1244 function() noexcept
1245 : target( func::null_target_t<R, A...>::delegate() )
1246 { }
1247
1248 /**
1249 * \brief Null function constructor
1250 *
1251 * @anchor function_ctor_nullptr
1252 * Constructs an instance with a null target function.
1253 * @see @ref function_overview "function Overview"
1254 * @see @ref function_usage "function Usage"
1255 */
1256 function(std::nullptr_t ) noexcept
1258 { }
1259
1260 /**
1261 * \brief Internally used delegate_t<R(A...)> constructor
1262 *
1263 * May utilize [copy elision](https://en.cppreference.com/w/cpp/language/copy_elision)
1264 * and/or named return value optimization (NRVO).
1265 *
1266 * @see @ref function_overview "function Overview"
1267 * @see @ref function_usage "function Usage"
1268 */
1269 explicit function(delegate_type _delegate, int dummy ) noexcept
1270 : target( std::move(_delegate) )
1271 { (void) dummy; }
1272
1273 /**
1274 * \brief Free function constructor
1275 *
1276 * @anchor function_ctor_free
1277 * Constructs an instance by taking a free target function, which may also be a non-capturing lambda if explicitly bind_free().
1278 * @see @ref function_overview "function Overview"
1279 * @see @ref function_usage "function Usage"
1280 */
1281 function(R(*func)(A...)) noexcept
1282 : target( func::free_target_t<R, A...>::delegate(func) )
1283 { }
1284
1285 /**
1286 * \brief Lambda function constructor
1287 *
1288 * @anchor function_ctor_lambda
1289 * Constructs an instance by taking a lambda function.
1290 *
1291 * @tparam L typename holding the lambda closure
1292 * @param func the lambda reference
1293 * @see @ref function_overview "function Overview"
1294 * @see @ref function_usage "function Usage"
1295 */
1296 template<typename L,
1297 std::enable_if_t<!std::is_same_v<L, std::shared_ptr<delegate_type>> &&
1298 !std::is_pointer_v<L> &&
1299 !std::is_same_v<L, R(A...)> &&
1300 !std::is_same_v<L, function<R(A...)>>
1301 , bool> = true>
1302 function(L func) noexcept
1304 { }
1305
1306 /**
1307 * \brief Lambda function bind factory
1308 *
1309 * @anchor function_bind_lambda
1310 * Constructs an instance by taking a lambda function.
1311 *
1312 * @tparam L typename holding the lambda closure
1313 * @param func the lambda reference
1314 * @see @ref function_overview "function Overview"
1315 * @see @ref function_usage "function Usage"
1316 */
1317 template<typename L>
1318 static function<R(A...)> bind_lambda(L func) noexcept
1319 {
1321 }
1322
1323 /**
1324 * \brief Y combinator Lambda function bind factory
1325 *
1326 * @anchor function_bind_ylambda
1327 * Constructs an instance by taking a lambda function,
1328 * implementing a [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
1329 * and [deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html) lambda closure,
1330 * see [ylambda_target_t](@ref ylambda_target).
1331 *
1332 * @tparam L typename holding the lambda closure
1333 * @param func the lambda reference
1334 * @see @ref ylambda_target "ylambda_target_t"
1335 * @see @ref function_overview "function Overview"
1336 * @see @ref function_usage "function Usage"
1337 */
1338 template<typename L>
1339 static function<R(A...)> bind_ylambda(L func) noexcept
1340 {
1342 }
1343
1344 /**
1345 * \brief Member function constructor
1346 *
1347 * \anchor function_ctor_member
1348 * Constructs an instance by taking a member target function.
1349 * @tparam C0 class type holding the member-function
1350 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1351 * @param base pointer to the class instance of the member function
1352 * @param mfunc member function of class
1353 * @see @ref function_overview "function Overview"
1354 * @see @ref function_usage "function Usage"
1355 */
1356 template<typename C0, typename C1>
1357 function(C1 *base, R(C0::*mfunc)(A...)) noexcept
1358 : target( func::member_target_t<R, C0, C1, A...>::delegate(base, mfunc) )
1359 { }
1360
1361 /**
1362 * \brief Capture by value (copy) function constructor
1363 *
1364 * @anchor function_ctor_capval_copy
1365 * Constructs an instance by copying the captured value and the given non-void function to
1366 * an anonymous function using func::capval_target_t.
1367 *
1368 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1369 *
1370 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1371 *
1372 * @tparam I typename holding the captured data used by the function
1373 * @param data data type instance holding the captured data
1374 * @param func function with `R` return value and `A...` arguments.
1375 * @see @ref function_overview "function Overview"
1376 * @see @ref function_usage "function Usage"
1377 */
1378 template<typename I>
1379 function(const I& data, R(*func)(I&, A...)) noexcept
1380 : target( func::capval_target_t<R, I, A...>::delegate(data, func) )
1381 { }
1382
1383 /**
1384 * \brief Capture by value (move) function constructor
1385 *
1386 * @anchor function_ctor_capval_move
1387 * Constructs an instance by moving the captured value and copying the given non-void function to
1388 * an anonymous function using func::capval_target_t.
1389 *
1390 * `I&& data` will be moved into func::capval_target_t.
1391 *
1392 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1393 *
1394 * @tparam I typename holding the captured data used by the function
1395 * @param data data type instance holding the captured data
1396 * @param func function with `R` return value and `A...` arguments.
1397 * @see @ref function_overview "function Overview"
1398 * @see @ref function_usage "function Usage"
1399 */
1400 template<typename I>
1401 function(I&& data, R(*func)(I&, A...)) noexcept
1402 : target( func::capval_target_t<R, I, A...>::delegate(std::forward<I>(data), func) )
1403 { }
1404
1405 /**
1406 * \brief Capture by-reference function constructor
1407 *
1408 * @anchor function_ctor_capref
1409 * Constructs an instance by passing the captured reference (pointer) to the value and non-void function to
1410 * an anonymous function using func::capref_target_t.
1411 *
1412 * The function invocation will have the reference of the data being passed to the target function.
1413 *
1414 * @tparam I typename holding the captured data used by the function
1415 * @param data_ptr data type reference to instance holding the captured data
1416 * @param func function with `R` return value and `A...` arguments.
1417 * @see @ref function_overview "function Overview"
1418 * @see @ref function_usage "function Usage"
1419 */
1420 template<typename I>
1421 function(I* data_ptr, R(*func)(I*, A...)) noexcept
1422 : target( func::capref_target_t<R, I, A...>::delegate(data_ptr, func) )
1423 { }
1424
1425 /**
1426 * \brief std::function constructor
1427 *
1428 * @anchor function_ctor_std
1429 * Constructs an instance by copying the std::function to
1430 * an anonymous function using func::std_target_t.
1431 *
1432 * Notable, instance is holding the given unique uint64_t identifier
1433 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1434 *
1435 * @param func free-function with `R` return value and `A...` arguments.
1436 * @see @ref function_overview "function Overview"
1437 * @see @ref function_usage "function Usage"
1438 */
1439 function(uint64_t id, std::function<R(A...)> func) noexcept
1440 : target( func::std_target_t<R, A...>::delegate(id, func) )
1441 { }
1442
1443 function(const function &o) noexcept = default;
1444 function(function &&o) noexcept = default;
1445 function& operator=(const function &o) noexcept = default;
1446 function& operator=(function &&o) noexcept = default;
1447
1448 /** Return the jau::func::type of this instance */
1449 constexpr func::target_type type() const noexcept { return target.type(); }
1450
1451 /** Returns true if this instance does not hold a callable target function, i.e. is of func::target_type::null. */
1452 constexpr bool is_null() const noexcept { return func::target_type::null == target.type(); }
1453
1454 /** Returns true if this instance holds a callable target function, i.e. is not of func::target_type::null. */
1455 explicit constexpr operator bool() const noexcept { return !is_null(); }
1456
1457 /** Returns signature of this function prototype R(A...) w/o underlying target function object. */
1458 jau::type_info signature() const noexcept {
1459 return jau::make_ctti<R(A...)>();
1460 }
1461
1462 /** Returns true if the underlying target function is `TriviallyCopyable`. */
1463 constexpr bool is_target_trivially_copyable() const noexcept { return target.is_trivially_copyable(); }
1464
1465 /** Return the total size of this instance, may include heap allocated by delegate for bigger target functions. */
1466 constexpr size_t size() const noexcept { return target.heap_size() + sizeof(*this); }
1467
1468 /** Returns the size of underlying target function */
1469 constexpr size_t target_size() const noexcept { return target.target_size(); }
1470
1471 /**
1472 * Return a string representation of this instance.
1473 * @anchor function_toString The string representation contains the complete signature and detailed memory footprint.
1474 */
1475 std::string toString() const {
1476 return "function<" + to_string( type() ) + ", " + signature().demangled_name() + ">( sz net " +
1477 std::to_string( target_size() ) + " / ( delegate_t " +
1478 std::to_string( sizeof( target ) ) + " + target_vdata " +
1479 std::to_string( target.heap_size() ) + " -> "+
1480 std::to_string( size() ) + " ), trivial_cpy "+
1481 std::to_string( target.is_trivially_copyable() ) + " ) ";
1482 }
1483
1484 constexpr R operator()(A... args) const {
1485 return target(args...);
1486 }
1487 constexpr R operator()(A... args) {
1488 return target(args...);
1489 }
1490
1491 constexpr bool operator==(const function<R(A...)>& rhs) const noexcept {
1492 return target.operator==(rhs.target);
1493 }
1494 constexpr bool operator!=(const function<R(A...)>& rhs) const noexcept {
1495 return !operator==(rhs);
1496 }
1497 };
1498
1499 /**
1500 * Equal operator using different jau::function<R(A...)> return and argument types for both arguments,
1501 * always returns false.
1502 * @tparam Rl left function return type
1503 * @tparam Al left function arguments
1504 * @tparam Fl left function Fl<Rl(<Al...)>
1505 * @tparam Rr right function return type
1506 * @tparam Ar right function arguments
1507 * @tparam Fr right function Fr<Rr(<Ar...)>
1508 * @param lhs left function Fl<Rl(<Al...)>
1509 * @param rhs right function Fr<Rr(<Ar...)>
1510 * @return false
1511 * @see @ref function_overview "function Overview"
1512 * @see @ref function_usage "function Usage"
1513 */
1514 template<typename Rl, typename... Al, template <typename...> class Fl = function,
1515 typename Rr, typename... Ar, template <typename...> class Fr = function,
1516 std::enable_if_t< !std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1517 , bool> = true>
1518 bool operator==(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1519 {
1520 (void)lhs;
1521 (void)rhs;
1522 return false;
1523 }
1524
1525 /**
1526 * Equal operator using same jau::function<R(A...)> return and argument types for both arguments,
1527 * returning actual result of equality operation.
1528 * @tparam Rl left function return type
1529 * @tparam Al left function arguments
1530 * @tparam Fl left function Fl<Rl(<Al...)>
1531 * @tparam Rr right function return type
1532 * @tparam Ar right function arguments
1533 * @tparam Fr right function Fr<Rr(<Ar...)>
1534 * @param lhs left function Fl<Rl(<Al...)>
1535 * @param rhs right function Fr<Rr(<Ar...)>
1536 * @return equality result of same type functions
1537 * @see @ref function_overview "function Overview"
1538 * @see @ref function_usage "function Usage"
1539 */
1540 template<typename Rl, typename... Al, template <typename...> class Fl = function,
1541 typename Rr, typename... Ar, template <typename...> class Fr = function,
1542 std::enable_if_t< std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1543 , bool> = true>
1544 bool operator==(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1545 { return lhs.operator==( rhs ); }
1546
1547 /**
1548 * Unequal operator using two jau::function<R(A...)> types for both arguments.
1549 * @tparam Rl left function return type
1550 * @tparam Al left function arguments
1551 * @tparam Fl left function Fl<Rl(<Al...)>
1552 * @tparam Rr right function return type
1553 * @tparam Ar right function arguments
1554 * @tparam Fr right function Fr<Rr(<Ar...)>
1555 * @param lhs left function Fl<Rl(<Al...)>
1556 * @param rhs right function Fr<Rr(<Ar...)>
1557 * @return unequality result of same type functions
1558 * @see @ref function_overview "function Overview"
1559 * @see @ref function_usage "function Usage"
1560 */
1561 template<typename Rl, typename... Al, template <typename...> typename Fl = function,
1562 typename Rr, typename... Ar, template <typename...> typename Fr = function>
1563 bool operator!=(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1564 { return !( lhs == rhs ); }
1565
1566 /**
1567 * Equal operator of jau::function<R(A...)> with a right-hand-side nullptr
1568 * @tparam R left function return type
1569 * @tparam A left function arguments
1570 * @param lhs left function
1571 * @return true if function instance contains no function, i.e. `!lhs` negated function bool operator.
1572 */
1573 template< class R, class... A>
1574 bool operator==(const function<R(A...)>& lhs, std::nullptr_t) noexcept
1575 { return !lhs; }
1576
1577 /**
1578 * Unequal operator of jau::function<R(A...)> with a right-hand-side nullptr
1579 * @tparam R left function return type
1580 * @tparam A left function arguments
1581 * @param lhs left function
1582 * @return true if function instance contains a function, i.e. `lhs` function bool operator.
1583 */
1584 template< class R, class... A>
1585 bool operator!=(const function<R(A...)>& lhs, std::nullptr_t) noexcept
1586 { return !( lhs == nullptr ); }
1587
1588 /**
1589 * Equal operator of jau::function<R(A...)> with a left-hand-side nullptr
1590 * @tparam R right function return type
1591 * @tparam A right function arguments
1592 * @param rhs right function
1593 * @return true if function instance contains no function, i.e. `!lhs` negated function bool operator.
1594 */
1595 template< class R, class... A>
1596 bool operator==(std::nullptr_t, const function<R(A...)>& rhs) noexcept
1597 { return !rhs; }
1598
1599 /**
1600 * Unequal operator of jau::function<R(A...)> with a left-hand-side nullptr
1601 * @tparam R right function return type
1602 * @tparam A right function arguments
1603 * @param rhs right function
1604 * @return true if function instance contains a function, i.e. `lhs` function bool operator.
1605 */
1606 template< class R, class... A>
1607 bool operator!=(std::nullptr_t, const function<R(A...)>& rhs) noexcept
1608 { return !( nullptr == rhs ); }
1609
1610 /**
1611 * Bind given class instance and non-void member function to
1612 * an anonymous function using func_member_targer_t.
1613 *
1614 * @tparam R function return type
1615 * @tparam C0 class type holding the member-function
1616 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1617 * @tparam A function arguments
1618 * @param base class instance `this` pointer
1619 * @param mfunc member-function with `R` return value and `A...` arguments.
1620 * @return anonymous function
1621 * @see @ref function_ctor_member "function constructor for member function"
1622 * @see @ref function_overview "function Overview"
1623 * @see @ref function_usage "function Usage"
1624 */
1625 template<typename R, typename C0, typename C1, typename... A>
1626 inline jau::function<R(A...)>
1627 bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept {
1628 return function<R(A...)>( func::member_target_t<R, C0, C1, A...>::delegate(base, mfunc), 0 );
1629 }
1630
1631 /**
1632 * Bind given class instance and non-void member function to
1633 * an anonymous function using func_member_targer_t.
1634 *
1635 * @tparam R function return type
1636 * @tparam C class type holding the member-function and of this base pointer
1637 * @tparam A function arguments
1638 * @param base class instance `this` pointer
1639 * @param mfunc member-function with `R` return value and `A...` arguments.
1640 * @return anonymous function
1641 * @see @ref function_ctor_member "function constructor for member function"
1642 * @see @ref function_overview "function Overview"
1643 * @see @ref function_usage "function Usage"
1644 */
1645 template<typename R, typename C, typename... A>
1646 inline jau::function<R(A...)>
1647 bind_member(C *base, R(C::*mfunc)(A...)) noexcept {
1648 return function<R(A...)>( func::member_target_t<R, C, C, A...>::delegate(base, mfunc), 0 );
1649 }
1650
1651 /**
1652 * Bind given class instance and void member function to
1653 * an anonymous function using func_member_targer_t.
1654 *
1655 * @tparam C0 class type holding the member-function
1656 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1657 * @tparam A function arguments
1658 * @param base class instance `this` pointer
1659 * @param mfunc member-function with `A...` arguments.
1660 * @return anonymous function
1661 * @see @ref function_ctor_member "function constructor for member function"
1662 * @see @ref function_overview "function Overview"
1663 * @see @ref function_usage "function Usage"
1664 */
1665 template<typename C0, typename C1, typename... A>
1666 inline jau::function<void(A...)>
1667 bind_member(C1 *base, void(C0::*mfunc)(A...)) noexcept {
1668 return function<void(A...)>( func::member_target_t<void, C0, C1, A...>::delegate(base, mfunc), 0 );
1669 }
1670
1671 /**
1672 * Bind given class instance and void member function to
1673 * an anonymous function using func_member_targer_t.
1674 *
1675 * @tparam C class type holding the member-function and of this base pointer
1676 * @tparam A function arguments
1677 * @param base class instance `this` pointer
1678 * @param mfunc member-function with `A...` arguments.
1679 * @return anonymous function
1680 * @see @ref function_ctor_member "function constructor for member function"
1681 * @see @ref function_overview "function Overview"
1682 * @see @ref function_usage "function Usage"
1683 */
1684 template<typename C, typename... A>
1685 inline jau::function<void(A...)>
1686 bind_member(C *base, void(C::*mfunc)(A...)) noexcept {
1687 return function<void(A...)>( func::member_target_t<void, C, C, A...>::delegate(base, mfunc), 0 );
1688 }
1689
1690 /**
1691 * Bind given non-void free-function to
1692 * an anonymous function using func::free_target_t.
1693 *
1694 * @tparam R function return type
1695 * @tparam A function arguments
1696 * @param func free-function with `R` return value and `A...` arguments.
1697 * @return anonymous function
1698 * @see @ref function_ctor_free "function constructor for free function"
1699 * @see @ref function_overview "function Overview"
1700 * @see @ref function_usage "function Usage"
1701 */
1702 template<typename R, typename... A>
1703 inline jau::function<R(A...)>
1704 bind_free(R(*func)(A...)) noexcept {
1705 return function<R(A...)>( func::free_target_t<R, A...>::delegate(func), 0 );
1706 }
1707
1708 /**
1709 * Bind given void free-function to
1710 * an anonymous function using func::free_target_t.
1711 *
1712 * @tparam A function arguments
1713 * @param func free-function with `A...` arguments.
1714 * @return anonymous function
1715 * @see @ref function_ctor_free "function constructor for free function"
1716 * @see @ref function_overview "function Overview"
1717 * @see @ref function_usage "function Usage"
1718 */
1719 template<typename... A>
1720 inline jau::function<void(A...)>
1721 bind_free(void(*func)(A...)) noexcept {
1722 return function<void(A...)>( func::free_target_t<void, A...>::delegate(func), 0 );
1723 }
1724
1725 /**
1726 * Bind given data by copying the captured value and the given non-void function to
1727 * an anonymous function using func::capval_target_t.
1728 *
1729 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1730 *
1731 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1732 *
1733 * @tparam R function return type
1734 * @tparam I typename holding the captured data used by the function
1735 * @tparam A function arguments
1736 * @param data data type instance holding the captured data
1737 * @param func function with `R` return value and `A...` arguments.
1738 * @return anonymous function
1739 * @see @ref function_ctor_capval_copy "function constructor for copying capturing value"
1740 * @see @ref function_overview "function Overview"
1741 * @see @ref function_usage "function Usage"
1742 */
1743 template<typename R, typename I, typename... A>
1744 inline jau::function<R(A...)>
1745 bind_capval(const I& data, R(*func)(I&, A...)) noexcept {
1746 return function<R(A...)>( func::capval_target_t<R, I, A...>::delegate(data, func), 0 );
1747 }
1748
1749 /**
1750 * Bind given data by copying the captured value and the given void function to
1751 * an anonymous function using func::capval_target_t.
1752 *
1753 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1754 *
1755 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1756 *
1757 * @tparam I typename holding the captured data used by the function
1758 * @tparam A function arguments
1759 * @param data data type instance holding the captured data
1760 * @param func function with `A...` arguments.
1761 * @return anonymous function
1762 * @see @ref function_ctor_capval_copy "function constructor for copying capturing value"
1763 * @see @ref function_overview "function Overview"
1764 * @see @ref function_usage "function Usage"
1765 */
1766 template<typename I, typename... A>
1767 inline jau::function<void(A...)>
1768 bind_capval(const I& data, void(*func)(I&, A...)) noexcept {
1769 return function<void(A...)>( func::capval_target_t<void, I, A...>::delegate(data, func), 0 );
1770 }
1771
1772 /**
1773 * Bind given data by moving the captured value and copying the given non-void function to
1774 * an anonymous function using func::capval_target_t.
1775 *
1776 * `I&& data` will be moved into func::capval_target_t.
1777 *
1778 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1779 *
1780 * @tparam R function return type
1781 * @tparam I typename holding the captured data used by the function
1782 * @tparam A function arguments
1783 * @param data data type instance holding the captured data
1784 * @param func function with `R` return value and `A...` arguments.
1785 * @return anonymous function
1786 * @see @ref function_ctor_capval_move "function constructor for moving capturing value"
1787 * @see @ref function_overview "function Overview"
1788 * @see @ref function_usage "function Usage"
1789 */
1790 template<typename R, typename I, typename... A>
1791 inline jau::function<R(A...)>
1792 bind_capval(I&& data, R(*func)(I&, A...)) noexcept {
1793 return function<R(A...)>( func::capval_target_t<R, I, A...>::delegate(std::forward<I>(data), func), 0 );
1794 }
1795
1796 /**
1797 * Bind given data by moving the captured value and copying the given void function to
1798 * an anonymous function using func::capval_target_t.
1799 *
1800 * `I&& data` will be moved into func::capval_target_t.
1801 *
1802 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1803 *
1804 * @tparam I typename holding the captured data used by the function
1805 * @tparam A function arguments
1806 * @param data data type instance holding the captured data
1807 * @param func function with `A...` arguments.
1808 * @return anonymous function
1809 * @see @ref function_ctor_capval_move "function constructor for moving capturing value"
1810 * @see @ref function_overview "function Overview"
1811 * @see @ref function_usage "function Usage"
1812 */
1813 template<typename I, typename... A>
1814 inline jau::function<void(A...)>
1815 bind_capval(I&& data, void(*func)(I&, A...)) noexcept {
1816 return function<void(A...)>( func::capval_target_t<void, I, A...>::delegate(std::forward<I>(data), func), 0 );
1817 }
1818
1819 /**
1820 * Bind given data by passing the captured reference (pointer) to the value and non-void function to
1821 * an anonymous function using func::capref_target_t.
1822 *
1823 * The function invocation will have the reference of the data being passed to the target function.
1824 *
1825 * @tparam R function return type
1826 * @tparam I typename holding the captured data used by the function
1827 * @tparam A function arguments
1828 * @param data_ptr data type reference to instance holding the captured data
1829 * @param func function with `R` return value and `A...` arguments.
1830 * @return anonymous function
1831 * @see @ref function_ctor_capref "function constructor for capturing reference"
1832 * @see @ref function_overview "function Overview"
1833 * @see @ref function_usage "function Usage"
1834 */
1835 template<typename R, typename I, typename... A>
1836 inline jau::function<R(A...)>
1837 bind_capref(I* data_ptr, R(*func)(I*, A...)) noexcept {
1838 return function<R(A...)>( func::capref_target_t<R, I, A...>::delegate(data_ptr, func), 0 );
1839 }
1840
1841 /**
1842 * Bind given data by passing the captured reference (pointer) to the value and void function to
1843 * an anonymous function using func::capref_target_t.
1844 *
1845 * The function invocation will have the reference of the data being passed to the target function.
1846 *
1847 * @tparam I typename holding the captured data used by the function
1848 * @tparam A function arguments
1849 * @param data_ptr data type reference to instance holding the captured data
1850 * @param func function with `A...` arguments.
1851 * @return anonymous function
1852 * @see @ref function_ctor_capref "function constructor for capturing reference"
1853 * @see @ref function_overview "function Overview"
1854 * @see @ref function_usage "function Usage"
1855 */
1856 template<typename I, typename... A>
1857 inline jau::function<void(A...)>
1858 bind_capref(I* data_ptr, void(*func)(I*, A...)) noexcept {
1859 return function<void(A...)>( func::capref_target_t<void, I, A...>::delegate(data_ptr, func), 0 );
1860 }
1861
1862 /**
1863 * Bind given non-void std::function to
1864 * an anonymous function using func::std_target_t.
1865 *
1866 * Notable, instance is holding the given unique uint64_t identifier
1867 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1868 *
1869 * @tparam R function return type
1870 * @tparam A function arguments
1871 * @param func free-function with `R` return value and `A...` arguments.
1872 * @return anonymous function
1873 * @see @ref function_ctor_std "function constructor for std::function"
1874 * @see @ref function_overview "function Overview"
1875 * @see @ref function_usage "function Usage"
1876 */
1877 template<typename R, typename... A>
1878 inline jau::function<R(A...)>
1879 bind_std(uint64_t id, std::function<R(A...)> func) noexcept {
1880 return function<R(A...)>( func::std_target_t<R, A...>::delegate(id, func), 0 );
1881 }
1882
1883 /**
1884 * Bind given void std::function to
1885 * an anonymous function using func::std_target_t.
1886 *
1887 * Notable, instance is holding the given unique uint64_t identifier
1888 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1889 *
1890 * @tparam A function arguments
1891 * @param func free-function with `A...` arguments.
1892 * @return anonymous function
1893 * @see @ref function_ctor_std "function constructor for std::function"
1894 * @see @ref function_overview "function Overview"
1895 * @see @ref function_usage "function Usage"
1896 */
1897 template<typename... A>
1898 inline jau::function<void(A...)>
1899 bind_std(uint64_t id, std::function<void(A...)> func) noexcept {
1900 return function<void(A...)>( func::std_target_t<void, A...>::delegate(id, func), 0 );
1901 }
1902
1903 /**@}*/
1904
1905} // namespace jau
1906
1907/** \example test_functional.hpp
1908 * This C++ unit test validates the jau::function<R(A...)> and all its jau::func::target_t specializations.
1909 */
1910
1911/** \example test_functional_perf.hpp
1912 * This C++ unit test benchmarks the jau::function<R(A...)> and all its jau::func::target_t specializations.
1913 */
1914
1915#endif /* JAU_FUNCTIONAL_HPP_ */
func::capref_target_t implementation for functions using a reference to a captured value,...
static delegate_type delegate(I *data_ptr, R(*function)(I *, A...)) noexcept
delegate_t< R, A... > delegate_type
func::capval_target_t implementation for functions using a copy of a captured value,...
static delegate_type delegate(const I &data, R(*function)(I &, A...)) noexcept
delegate_t< R, A... > delegate_type
static delegate_type delegate(I &&data, R(*function)(I &, A...)) noexcept
Delegated target function object, providing a fast path target function invocation.
Definition: functional.hpp:377
std::enable_if_t<!std::is_trivially_copyable_v< T >||sizeof(udata.cache)< sizeof(T), bool >=true > constexpr const T * data() const noexcept
Definition: functional.hpp:684
constexpr size_t heap_size() const noexcept
Definition: functional.hpp:727
delegate_t(delegate_t &&o) noexcept
Definition: functional.hpp:549
delegate_t target(type_, static_cast< size_type >(sizeof(T)), nt, cb_, eqop_)
constexpr R operator()(A... args) const
Delegated fast path target function invocation, see above.
Definition: functional.hpp:710
constexpr bool operator==(const delegate_t< R, A... > &rhs) const noexcept
Delegated fast path target function equality operator.
Definition: functional.hpp:720
int32_t size_type
Utilize a reduced size type of int32_t.
Definition: functional.hpp:383
std::enable_if_t<!std::is_trivially_copyable_v< T >||sizeof(udata.cache)< sizeof(T), bool >=true > constexpr T * data() noexcept
Definition: functional.hpp:700
constexpr bool is_trivially_copyable() const noexcept
Returns true if the underlying target function is TriviallyCopyable.
Definition: functional.hpp:725
delegate_t & operator=(delegate_t &&o) noexcept
Definition: functional.hpp:637
delegate_t(const delegate_t &o) noexcept
Definition: functional.hpp:522
delegate_t & operator=(const delegate_t &o) noexcept
Definition: functional.hpp:575
static delegate_t make(invocation_t cb_, equal_op_t eqop_) noexcept
Definition: functional.hpp:475
constexpr size_t cached_size() const noexcept
Definition: functional.hpp:728
bool(* equal_op_t)(const delegate_t &data_lhs, const delegate_t &data_rhs) noexcept
Definition: functional.hpp:387
constexpr size_t target_size() const noexcept
Returns the size of underlying target function.
Definition: functional.hpp:731
R(* invocation_t)(delegate_t *__restrict_cxx__ const data, A... args)
Definition: functional.hpp:386
constexpr target_type type() const noexcept
Return the func::target_type of this invocation function wrapper.
Definition: functional.hpp:734
func::free_target_t implementation for free functions, identifiable as func::target_type::free via ja...
Definition: functional.hpp:881
static delegate_type delegate(R(*function)(A...)) noexcept
Definition: functional.hpp:907
delegate_t< R, A... > delegate_type
Definition: functional.hpp:883
func::lambda_target_t implementation for lambda closures, identifiable as func::target_type::lambda v...
Definition: functional.hpp:922
static delegate_type delegate(L function) noexcept
Definition: functional.hpp:953
delegate_t< R, A... > delegate_type
Definition: functional.hpp:924
func::member_target_t implementation for class member functions, identifiable as func::target_type::m...
Definition: functional.hpp:783
static delegate_type delegate(C1 *base, R(C0::*method)(A...), std::enable_if_t< std::is_base_of_v< C0, C1 >, bool >=true) noexcept
Construct a delegate_t<R, A...> instance from given this base-pointer and member-function.
Definition: functional.hpp:865
delegate_t< R, A... > delegate_type
Definition: functional.hpp:785
func::null_target_t implementation for no function.
Definition: functional.hpp:749
delegate_t< R, A... > delegate_type
Definition: functional.hpp:751
static delegate_type delegate() noexcept
Definition: functional.hpp:767
func::std_target_t implementation for std::function instances, identifiable as func::target_type::std...
delegate_t< R, A... > delegate_type
static delegate_type delegate(uint64_t id, std::function< R(A...)> function) noexcept
func::ylambda_target_t is a Y combinator and deducing this implementation for lambda closures usable ...
delegate_t< R, A... > delegate_type
static delegate_type delegate(L function) noexcept
function(C1 *base, R(C0::*mfunc)(A...)) noexcept
Member function constructor.
function & operator=(function &&o) noexcept=default
constexpr bool operator!=(const function< R(A...)> &rhs) const noexcept
constexpr size_t target_size() const noexcept
Returns the size of underlying target function.
constexpr func::target_type type() const noexcept
Return the jau::func::type of this instance.
function(L func) noexcept
Lambda function constructor.
std::string toString() const
Return a string representation of this instance.
constexpr bool operator==(const function< R(A...)> &rhs) const noexcept
func::delegate_t< R, A... > delegate_type
The delegated target function type, i.e.
function(uint64_t id, std::function< R(A...)> func) noexcept
std::function constructor
function(I &&data, R(*func)(I &, A...)) noexcept
Capture by value (move) function constructor.
function(const I &data, R(*func)(I &, A...)) noexcept
Capture by value (copy) function constructor.
function(R(*func)(A...)) noexcept
Free function constructor.
constexpr bool is_null() const noexcept
Returns true if this instance does not hold a callable target function, i.e.
function() noexcept
Null function constructor.
R result_type
The target function return type R.
constexpr size_t size() const noexcept
Return the total size of this instance, may include heap allocated by delegate for bigger target func...
static function< R(A...)> bind_lambda(L func) noexcept
Lambda function bind factory.
function & operator=(const function &o) noexcept=default
function(delegate_type _delegate, int dummy) noexcept
Internally used delegate_t<R(A...)> constructor.
constexpr R operator()(A... args) const
function(function &&o) noexcept=default
jau::type_info signature() const noexcept
Returns signature of this function prototype R(A...) w/o underlying target function object.
static function< R(A...)> bind_ylambda(L func) noexcept
Y combinator Lambda function bind factory.
function(const function &o) noexcept=default
function(I *data_ptr, R(*func)(I *, A...)) noexcept
Capture by-reference function constructor.
function(std::nullptr_t) noexcept
Null function constructor.
constexpr bool is_target_trivially_copyable() const noexcept
Returns true if the underlying target function is TriviallyCopyable.
constexpr R operator()(A... args)
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Generic type information using either Runtime type information (RTTI) or Compile time type informatio...
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line fu...
Definition: debug.hpp:101
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
jau::type_info make_ctti() noexcept
Constructs a jau::type_info instance based on given type T using template Compile Time Type Informati...
#define PRAGMA_DISABLE_WARNING_PMF_CONVERSIONS
Definition: cpp_pragma.hpp:85
#define PRAGMA_DISABLE_WARNING_PUSH
Definition: cpp_pragma.hpp:76
#define __restrict_cxx__
Wrap C++ extension __restrict__ covering C99's restrict feature keyword.
#define PRAGMA_DISABLE_WARNING_POP
Definition: cpp_pragma.hpp:77
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
target_type
func::target_type identifier for the target function delegate_t<R, A...> object, exposed by jau::func...
Definition: functional.hpp:341
jau::function< R(A...)> bind_free(R(*func)(A...)) noexcept
Bind given non-void free-function to an anonymous function using func::free_target_t.
jau::function< R(A...)> bind_std(uint64_t id, std::function< R(A...)> func) noexcept
Bind given non-void std::function to an anonymous function using func::std_target_t.
jau::function< R(A...)> bind_capval(const I &data, R(*func)(I &, A...)) noexcept
Bind given data by copying the captured value and the given non-void function to an anonymous functio...
std::string to_string(const func::target_type v) noexcept
jau::function< R(A...)> bind_capref(I *data_ptr, R(*func)(I *, A...)) noexcept
Bind given data by passing the captured reference (pointer) to the value and non-void function to an ...
constexpr uint32_t number(const func::target_type rhs) noexcept
@ null
Denotes a func::null_target_t.
@ lambda
Denotes a func::lambda_target_t.
@ capval
Denotes a func::capval_target_t.
@ capref
Denotes a func::capref_target_t.
@ member
Denotes a func::member_target_t.
@ free
Denotes a func::free_target_t.
@ std
Denotes a func::std_target_t.
@ ylambda
Denotes a func::ylambda_target_t.
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
Definition: base_math.hpp:191
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
Definition: base_math.hpp:155
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:150
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:163
STL namespace.