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