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