jaulib v1.3.6
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 ) {
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
474 static delegate_t make(const target_func_t& tfunc) noexcept
475 {
476 return delegate_t(tfunc);
477 }
478
479 // `TriviallyCopyable` using cache
480 template<typename T, typename... P,
481 std::enable_if_t<use_trivial_cache<T>(), bool> = true>
482 static delegate_t make(const target_func_t& tfunc, P... params) noexcept
483 {
484 delegate_t target(tfunc);
485 new( target.template data<T>() ) T(params...); // placement new
486 return target;
487 }
488
489 // `TriviallyCopyable` using heap
490 template<typename T, typename... P,
491 std::enable_if_t<use_trivial_heap<T>(), bool> = true>
492 static delegate_t make(const target_func_t& tfunc, P... params) noexcept
493 {
494 delegate_t target(tfunc, true);
495 new( target.template data<T>() ) T(params...); // placement new
496 return target;
497 }
498
499 // Non `TriviallyCopyable` using heap
500 template<typename T, typename... P,
501 std::enable_if_t<use_nontrivial_heap<T>(), bool> = true>
502 static delegate_t make(const target_func_t& tfunc, P... params) noexcept
503 {
504 delegate_t target(tfunc, true);
505 new( target.template data<T>() ) T(params...); // placement new
506 return target;
507 }
508
509 // Return nullptr for `TriviallyCopyable` using cache or heap
510 template<typename T,
511 std::enable_if_t<!use_nontrivial_heap<T>(), bool> = true>
512 static non_trivial_t* getNonTrivialCtor() noexcept { return nullptr; }
513
514 // Return pointer to static non_trivial_nt ctor/dtor's for Non `TriviallyCopyable` using heap
515 template<typename T,
516 std::enable_if_t<use_nontrivial_heap<T>(), bool> = true>
517 static non_trivial_t* getNonTrivialCtor() noexcept
518 {
519 static non_trivial_t nt {
520 .dtor =
521 [](delegate_t* i) -> void {
522 T* t = i->template data<T>();
523 if( nullptr != t ) {
524 t->T::~T(); // placement new -> manual destruction!
525 }
526 },
527 .copy_ctor =
528 [](delegate_t* i, const delegate_t* o) -> void {
529 new( i->template data<T>() ) T( *( o->template data<T>() ) ); // placement new copy-ctor
530 },
531 .move_ctor =
532 [](delegate_t* i, delegate_t* o) -> void {
533 new( i->template data<T>() ) T( std::move( *( o->template data<T>() ) ) ); // placement new move-ctor
534 }
535 };
536 return &nt;
537 }
538
539 ~delegate_t() noexcept { clear(); }
540
541 delegate_t(const delegate_t& o) noexcept
542 : m_tfunc( o.m_tfunc )
543 {
544 if( useHeap() ) {
545 udata.heap = ::malloc(m_tfunc->size);
546 if( !udata.heap ) {
547 ABORT("Error: bad_alloc: heap allocation failed");
548 return; // unreachable
549 }
550 if( m_tfunc->non_trivial ) {
551 m_tfunc->non_trivial->copy_ctor(this, &o);
552 } else {
553 ::memcpy(udata.heap, o.udata.heap, m_tfunc->size);
554 }
555 } else {
556 ::memcpy(udata.cache, o.udata.cache, m_tfunc->size);
557 }
558 }
559
560 delegate_t(delegate_t&& o) noexcept
561 : m_tfunc( std::move(o.m_tfunc) )
562 {
563 if( useHeap() ) {
564 if( m_tfunc->non_trivial ) {
565 udata.heap = ::malloc(m_tfunc->size);
566 if( !udata.heap ) {
567 ABORT("Error: bad_alloc: heap allocation failed");
568 return; // unreachable
569 }
570 m_tfunc->non_trivial->move_ctor(this, &o);
571 m_tfunc->non_trivial->dtor(&o);
572 ::free(o.udata.heap);
573 } else {
574 udata.heap = std::move( o.udata.heap );
575 }
576 o.udata.heap = nullptr;
577 } else {
578 ::memcpy(udata.cache, o.udata.cache, m_tfunc->size);
579 }
580 }
581
582 delegate_t& operator=(const delegate_t &o) noexcept
583 {
584 if( this == &o ) {
585 return *this;
586 }
587
588 if( !useHeap() && !o.useHeap() ) {
589 // sdata: copy
590 m_tfunc = o.m_tfunc;
591
592 ::memcpy(udata.cache, o.udata.cache, m_tfunc->size);
593 } else if( useHeap() && o.useHeap() && m_tfunc->size >= o.m_tfunc->size ) {
594 // vdata: reuse memory
595 if( m_tfunc->non_trivial ) {
596 m_tfunc->non_trivial->dtor(this);
597 }
598 m_tfunc = o.m_tfunc;
599 if( m_tfunc->non_trivial ) {
600 m_tfunc->non_trivial->copy_ctor(this, &o);
601 } else {
602 ::memcpy(udata.heap, o.udata.heap, m_tfunc->size);
603 }
604 } else {
605 // reset
606 clear();
607 m_tfunc = o.m_tfunc;
608
609 if( useHeap() ) {
610 udata.heap = ::malloc(m_tfunc->size);
611 if( !udata.heap ) {
612 ABORT("Error: bad_alloc: heap allocation failed");
613 return *this; // unreachable
614 }
615 if( m_tfunc->non_trivial ) {
616 m_tfunc->non_trivial->copy_ctor(this, &o);
617 } else {
618 ::memcpy(udata.heap, o.udata.heap, m_tfunc->size);
619 }
620 } else {
621 ::memcpy(udata.cache, o.udata.cache, m_tfunc->size);
622 }
623 }
624 return *this;
625 }
626
627 delegate_t& operator=(delegate_t &&o) noexcept
628 {
629 if( this == &o ) {
630 return *this;
631 }
632 clear();
633 m_tfunc = o.m_tfunc;
634
635 if( useHeap() ) {
636 if( m_tfunc->non_trivial ) {
637 udata.heap = ::malloc(m_tfunc->size);
638 if( !udata.heap ) {
639 ABORT("Error: bad_alloc: heap allocation failed");
640 return *this; // unreachable
641 }
642 m_tfunc->non_trivial->move_ctor(this, &o);
643 m_tfunc->non_trivial->dtor(&o);
644 ::free(o.udata.heap);
645 } else {
646 udata.heap = std::move( o.udata.heap );
647 }
648 o.udata.heap = nullptr;
649 } else {
650 ::memcpy(udata.cache, o.udata.cache, m_tfunc->size);
651 }
652 return *this;
653 }
654
655 template<typename T,
656 std::enable_if_t<use_trivial_cache<T>(), bool> = true>
657 constexpr const T* data() const noexcept {
658 return pointer_cast<T*>( &udata.cache[0] ); // aligned to delegate_t start + sizeof(pointer)
659 }
660 template<typename T,
661 std::enable_if_t<use_trivial_cache<T>(), bool> = true>
662 constexpr T* data() noexcept {
663 return pointer_cast<T*>( &udata.cache[0] ); // aligned to delegate_t start + sizeof(pointer)
664 }
665
666 template<typename T,
667 std::enable_if_t<use_any_heap<T>(), bool> = true>
668 constexpr const T* data() const noexcept {
669 return pointer_cast<const T*>( udata.heap );
670 }
671 template<typename T,
672 std::enable_if_t<use_any_heap<T>(), bool> = true>
673 constexpr T* data() noexcept {
674 return pointer_cast<T*>( udata.heap );
675 }
676
677 /**
678 * \brief Delegated fast path target function invocation, [see above](@ref delegate_class)
679 *
680 * @param args target function arguments
681 * @return target function result
682 */
683 constexpr R operator()(A... args) const {
684 return m_tfunc->cb(const_cast<delegate_t*>(this), args...);
685 }
686
687 /**
688 * \brief Delegated fast path target function equality operator
689 *
690 * @param rhs
691 * @return
692 */
693 constexpr bool operator==(const delegate_t<R, A...>& rhs) const noexcept {
694 return m_tfunc->eqop(*this, rhs);
695 }
696
697 /** Returns true if the underlying target function is `TriviallyCopyable`. */
698 constexpr bool is_trivially_copyable() const noexcept { return !useHeap() || !m_tfunc->non_trivial; }
699
700 constexpr size_t heap_size() const noexcept { return useHeap() ? m_tfunc->size : 0; }
701 constexpr size_t cached_size() const noexcept { return !useHeap() ? m_tfunc->size : 0; }
702
703 /** Returns the size of underlying target function */
704 constexpr size_t target_size() const noexcept { return m_tfunc->size; }
705
706 /** Return the func::target_type of this invocation function wrapper */
707 constexpr target_type type() const noexcept { return m_tfunc->type; }
708 };
709
710 /**
711 * func::null_target_t implementation for no function.
712 * identifiable as jau::func::target_type::null via jau::function<R(A...)>::type().
713 *
714 * This special type is used for an empty [jau::function](@ref function_def) instance w/o holding a function,
715 * e.g. when created with the default constructor.
716 *
717 * @tparam R function return type
718 * @tparam A function arguments
719 * @see @ref function_overview "Function Overview"
720 */
721 template<typename R, typename... A>
722 class null_target_t final_opt {
723 public:
724 typedef delegate_t<R, A...> delegate_type;
725
726 private:
727 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const, A...) {
728 return R();
729 }
730
731 constexpr static bool equal_op_impl(const delegate_type& lhs, const delegate_type& rhs) noexcept {
732 return lhs.type() == rhs.type();
733 }
734
735 constexpr static void dtor(delegate_type* target) noexcept {
736 (void)target;
737 }
738 static const delegate_type::target_func_t& get() {
739 static typename delegate_type::target_func_t tf { invoke_impl, equal_op_impl, nullptr, 0, target_type::null };
740 return tf;
741 };
742
743 public:
744 static delegate_type delegate() noexcept {
745 return delegate_type::make(get());
746 }
747 };
748
749 /**
750 * func::member_target_t implementation for class member functions,
751 * identifiable as func::target_type::member via jau::function<R(A...)>::type().
752 *
753 * @tparam R function return type
754 * @tparam C0 class type holding the member-function
755 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
756 * @tparam A function arguments
757 * @see @ref function_overview "Function Overview"
758 */
759 template<typename R, typename C0, typename C1, typename... A>
760 class member_target_t final_opt {
761 public:
762 typedef delegate_t<R, A...> delegate_type;
763
764 private:
765
766#if defined(__GNUC__) && !defined(__clang__)
767 /**
768 * Utilizing GCC C++ Extension: Pointer to Member Function (PMF) Conversion to function pointer
769 * - Reduces function pointer size, i.e. PMF 16 (total 24) -> function 8 (total 16)
770 * - Removes vtable lookup at invocation (performance)
771 * - Pass object this pointer to function as 1st argument
772 * - See [GCC PMF Conversion](https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html#Bound-member-functions)
773 */
774 typedef R(*function_t)(C0*, A...);
775
776 struct data_type final_opt {
777 function_t function;
778 C1* base;
779
780 constexpr data_type(C1 *_base, R(C0::*_method)(A...)) noexcept
781 : base(_base)
782 {
786 function = (function_t)(_base->*_method);
788 }
789 };
790
791 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
792 data_type * __restrict_cxx__ const d = data->template data<data_type>();
793 return ( *(d->function) )(d->base, args...);
794 }
795
796 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
797 const data_type* lhs = lhs_.template data<const data_type>();
798 const data_type* rhs = rhs_.template data<const data_type>();
799 return lhs == rhs ||
800 ( lhs_.type() == rhs_.type() &&
801 lhs->base == rhs->base &&
802 lhs->function== rhs->function
803 );
804 }
805#else
806 /**
807 * C++ conform Pointer to Member Function (PMF)
808 */
809 struct data_type final_opt {
811 R(C0::*method)(A...);
812
813 constexpr data_type(C1 *_base, R(C0::*_method)(A...)) noexcept
814 : base(_base), method(_method)
815 { }
816 };
817
818 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
819 data_type * __restrict_cxx__ const d = data->template data<data_type>();
820 return (d->base->*d->method)(args...);
821 }
822
823 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
824 const data_type* lhs = lhs_.template data<const data_type>();
825 const data_type* rhs = rhs_.template data<const data_type>();
826 return lhs == rhs ||
827 ( lhs_.type() == rhs_.type() &&
828 lhs->base == rhs->base &&
829 lhs->method == rhs->method
830 );
831 }
832#endif
833 static const delegate_type::target_func_t& get() {
834 static typename delegate_type::target_func_t tf {
835 invoke_impl, equal_op_impl,
836 delegate_type::template getNonTrivialCtor<data_type>(),
837 sizeof(data_type), target_type::member };
838 return tf;
839 };
840
841 public:
842 /**
843 * Construct a delegate_t<R, A...> instance from given this base-pointer and member-function.
844 *
845 * This factory function is only enabled if C0 is base of C1.
846 *
847 * @param base this base-pointer of class C1 derived from C0 or C0 used to invoke the member-function
848 * @param method member-function of class C0
849 * @return delegate_t<R, A...> instance holding the target-function object.
850 */
851 static delegate_type delegate(C1 *base, R(C0::*method)(A...),
852 std::enable_if_t<std::is_base_of_v<C0, C1>, bool> = true) noexcept
853 {
854 return delegate_type::template make<data_type>( get(), base, method );
855 }
856 };
857
858 /**
859 * func::free_target_t implementation for free functions,
860 * identifiable as func::target_type::free via jau::function<R(A...)>::type().
861 *
862 * @tparam R function return type
863 * @tparam A function arguments
864 * @see @ref function_overview "Function Overview"
865 */
866 template<typename R, typename... A>
867 class free_target_t final_opt {
868 public:
869 typedef delegate_t<R, A...> delegate_type;
870
871 private:
872 struct data_type final_opt {
873 R(*function)(A...);
874
875 data_type(R(*_function)(A...)) noexcept
876 : function(_function) { }
877 };
878
879 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
880 return ( *(data->template data<data_type>()->function) )(args...);
881 }
882
883 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
884 const data_type* lhs = lhs_.template data<const data_type>();
885 const data_type* rhs = rhs_.template data<const data_type>();
886 return lhs == rhs ||
887 ( lhs_.type() == rhs_.type() &&
888 lhs->function== rhs->function
889 );
890 }
891 static const delegate_type::target_func_t& get() {
892 static typename delegate_type::target_func_t tf {
893 invoke_impl, equal_op_impl,
894 delegate_type::template getNonTrivialCtor<data_type>(),
895 sizeof(data_type), target_type::free };
896 return tf;
897 };
898
899 public:
900 static delegate_type delegate(R(*function)(A...)) noexcept {
901 return delegate_type::template make<data_type>( get(), function );
902 }
903 };
904
905 /**
906 * func::lambda_target_t implementation for lambda closures,
907 * identifiable as func::target_type::lambda via jau::function<R(A...)>::type().
908 *
909 * @tparam R function return type
910 * @tparam L typename holding the lambda closure
911 * @tparam A function arguments
912 * @see @ref function_overview "Function Overview"
913 */
914 template<typename R, typename L, typename...A>
915 class lambda_target_t final_opt {
916 public:
917 typedef delegate_t<R, A...> delegate_type;
918
919 private:
920 struct data_type final_opt {
923
924 data_type(L _function) noexcept
925 : function( _function ), sig( jau::make_ctti<R, L, A...>() ) {}
926
927 constexpr size_t detail_size() const noexcept { return sizeof(function); }
928 };
929
930 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
931 return ( data->template data<data_type>()->function )(args...);
932 }
933
934 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
935 const data_type* lhs = lhs_.template data<const data_type>();
936 const data_type* rhs = rhs_.template data<const data_type>();
937 return lhs == rhs ||
938 ( lhs_.type() == rhs_.type() &&
939 lhs->detail_size() == rhs->detail_size() && // fast: wrong size -> false, otherwise ...
940 lhs->sig == rhs->sig && // mixed: wrong jau::type_info -> false, otherwise ...
941 0 == ::memcmp((void*)&lhs->function, (void*)&rhs->function, sizeof(lhs->function)) // slow: compare the anonymous data chunk of the lambda
942 );
943 }
944 static const delegate_type::target_func_t& get() {
945 static typename delegate_type::target_func_t tf {
946 invoke_impl, equal_op_impl,
947 delegate_type::template getNonTrivialCtor<data_type>(),
948 sizeof(data_type), target_type::lambda };
949 return tf;
950 };
951
952 public:
953 static delegate_type delegate(L function) noexcept {
954 return delegate_type::template make<data_type>( get(), function );
955 }
956 };
957
958 /**
959 * func::ylambda_target_t is a [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
960 * and [deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html) implementation for lambda closures
961 * usable for recursive algorithms.
962 *
963 * @anchor ylambda_target The [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
964 * allows passing the unnamed lambda instance itself, enabling recursive invocation from within the lambda. <br />
965 * In other words, a `this` reference of the unnamed lambda is passed to the lambda, similar to [`Deducing this`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html).
966 *
967 * The ylambda [function<R(A...)>](@ref function_def) is invoked w/o explicitly passing the object parameter,
968 * as it is implicitly passed down to the user's lambda implementation.
969 *
970 * Example implementing a recursive lambda factorial function
971 *
972 * ```
973 * function<int(int)> f1 = function<int(int)>::bind_ylambda( [](auto& self, int x) -> int {
974 * if( 0 == x ) {
975 * return 1;
976 * } else {
977 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
978 * }
979 * } );
980 * assert( 24 == f1(4) ); // `self` is bound to delegate<R(A...)> `f.target`, `x` is 4
981 *
982 * // or using explicit function<R(A...)>::delegate_type
983 *
984 * function<int(int)> f2 = function<int(int)>::bind_ylambda( [](function<int(int)>::delegate_type& self, int x) -> int {
985 * if( 0 == x ) {
986 * return 1;
987 * } else {
988 * return x * self(x-1); // recursion, calling itself w/o explicitly passing `self`
989 * }
990 * } );
991 * assert( 24 == f2(4) ); // `self` is bound to function<int(int)>::delegate_type `f.target`, `x` is 4
992 * ```
993 *
994 * An instance is identifiable as func::target_type::ylambda via jau::function<R(A...)>::type().
995 *
996 * @tparam R function return type
997 * @tparam L typename holding the lambda closure
998 * @tparam A function arguments
999 * @see @ref function_overview "Function Overview"
1000 * @see [Deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html)
1001 * @see [Explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
1002 * @see [Curiously Recurring Template Pattern](https://en.cppreference.com/w/cpp/language/crtp)
1003 */
1004 template<typename R, typename L, typename...A>
1005 class ylambda_target_t final_opt {
1006 public:
1007 typedef delegate_t<R, A...> delegate_type;
1008
1009 private:
1010 struct data_type final_opt {
1011 L function;
1013
1014 data_type(L _function) noexcept
1015 : function( _function ), sig( jau::make_ctti<R, L, A...>() ) {
1016 // jau::type_cue<L>::print("ylambda_target_t.lambda", TypeTraitGroup::ALL);
1017 // jau::type_cue<data_type>::print("ylambda_target_t.data_type", TypeTraitGroup::ALL);
1018 // fprintf(stderr, "ylambda_target: %s\n\t\tsize %zu, %p: %s\n",
1019 // sig.name(), sizeof(L), &function, jau::bytesHexString(&function, 0, sizeof(L), true).c_str());
1020 }
1021
1022 constexpr size_t detail_size() const noexcept { return sizeof(function); }
1023 };
1024
1025 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1026 return ( data->template data<data_type>()->function )(*data, args...);
1027 }
1028
1029 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1030 const data_type* lhs = lhs_.template data<const data_type>();
1031 const data_type* rhs = rhs_.template data<const data_type>();
1032 return lhs == rhs ||
1033 ( lhs_.type() == rhs_.type() &&
1034 lhs->detail_size() == rhs->detail_size() && // fast: wrong size -> false, otherwise ...
1035 lhs->sig == rhs->sig && // mixed: wrong jau::type_info -> false, otherwise ...
1036 0 == ::memcmp((void*)&lhs->function, (void*)&rhs->function, sizeof(lhs->function)) // slow: compare the anonymous data chunk of the lambda
1037 );
1038 }
1039 static const delegate_type::target_func_t& get() {
1040 static typename delegate_type::target_func_t tf {
1041 invoke_impl, equal_op_impl,
1042 delegate_type::template getNonTrivialCtor<data_type>(),
1043 sizeof(data_type), target_type::ylambda };
1044 return tf;
1045 };
1046
1047 public:
1048 static delegate_type delegate(L function) noexcept {
1049 return delegate_type::template make<data_type>( get(), function );
1050 }
1051 };
1052
1053 /**
1054 * func::capval_target_t implementation for functions using a copy of a captured value,
1055 * identifiable as func::target_type::capval via jau::function<R(A...)>::type().
1056 *
1057 * @tparam R function return type
1058 * @tparam I typename holding the captured data used by the function
1059 * @tparam A function arguments
1060 * @see @ref function_overview "Function Overview"
1061 */
1062 template<typename R, typename I, typename... A>
1063 class capval_target_t final_opt {
1064 public:
1065 typedef delegate_t<R, A...> delegate_type;
1066
1067 private:
1068 struct data_type final_opt {
1069 R(*function)(I&, A...);
1071
1072 data_type(const I& _data, R(*_function)(I&, A...)) noexcept
1073 : function(_function), data(_data) {}
1074
1075 data_type(I&& _data, R(*_function)(I&, A...)) noexcept
1076 : function(_function), data(std::move(_data)) {}
1077 };
1078
1079 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1080 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1081 return (*d->function)(d->data, args...);
1082 }
1083
1084 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1085 const data_type* lhs = lhs_.template data<const data_type>();
1086 const data_type* rhs = rhs_.template data<const data_type>();
1087 return lhs == rhs ||
1088 ( lhs_.type() == rhs_.type() &&
1089 lhs->function == rhs->function &&
1090 lhs->data == rhs->data
1091 );
1092 }
1093 static const delegate_type::target_func_t& get() {
1094 static typename delegate_type::target_func_t tf {
1095 invoke_impl, equal_op_impl,
1096 delegate_type::template getNonTrivialCtor<data_type>(),
1097 sizeof(data_type), target_type::capval };
1098 return tf;
1099 };
1100
1101 public:
1102 static delegate_type delegate(const I& data, R(*function)(I&, A...)) noexcept {
1103 return delegate_type::template make<data_type>( get(), data, function );
1104 }
1105
1106 static delegate_type delegate(I&& data, R(*function)(I&, A...)) noexcept {
1107 return delegate_type::template make<data_type>( get(), std::move(data), function );
1108 }
1109 };
1110
1111 /**
1112 * func::capref_target_t implementation for functions using a reference to a captured value,
1113 * identifiable as func::target_type::capref via jau::function<R(A...)>::type().
1114 *
1115 * @tparam R function return type
1116 * @tparam I typename holding the captured data used by the function
1117 * @tparam A function arguments
1118 * @see @ref function_overview "Function Overview"
1119 */
1120 template<typename R, typename I, typename... A>
1121 class capref_target_t final_opt {
1122 public:
1123 typedef delegate_t<R, A...> delegate_type;
1124
1125 private:
1126 struct data_type final_opt {
1127 R(*function)(I*, A...);
1129
1130 data_type(I* _data_ptr, R(*_function)(I*, A...)) noexcept
1131 : function(_function), data_ptr(_data_ptr)
1132 {}
1133 };
1134
1135 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1136 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1137 return (*d->function)(d->data_ptr, args...);
1138 }
1139
1140 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1141 const data_type* lhs = lhs_.template data<const data_type>();
1142 const data_type* rhs = rhs_.template data<const data_type>();
1143 return lhs == rhs ||
1144 ( lhs_.type() == rhs_.type() &&
1145 lhs->function == rhs->function &&
1146 lhs->data_ptr == rhs->data_ptr
1147 );
1148 }
1149 static const delegate_type::target_func_t& get() {
1150 static typename delegate_type::target_func_t tf {
1151 invoke_impl, equal_op_impl,
1152 delegate_type::template getNonTrivialCtor<data_type>(),
1153 sizeof(data_type), target_type::capref };
1154 return tf;
1155 };
1156
1157 public:
1158 static delegate_type delegate(I* data_ptr, R(*function)(I*, A...)) noexcept {
1159 return delegate_type::template make<data_type>( get(), data_ptr, function );
1160 }
1161 };
1162
1163 /**
1164 * func::std_target_t implementation for std::function instances,
1165 * identifiable as func::target_type::std via jau::function<R(A...)>::type().
1166 *
1167 * Notable, instance is holding a unique uint64_t identifier
1168 * to allow implementing the equality operator, not supported by std::function.
1169 *
1170 * @tparam R function return type
1171 * @tparam A function arguments
1172 * @see @ref function_overview "Function Overview"
1173 */
1174 template<typename R, typename... A>
1175 class std_target_t final_opt {
1176 public:
1177 typedef delegate_t<R, A...> delegate_type;
1178
1179 private:
1180 struct data_type final_opt {
1181 std::function<R(A...)> function;
1182 uint64_t id;
1183
1184 data_type(uint64_t id_, std::function<R(A...)> function_) noexcept
1185 : function(std::move(function_)), id(id_) {}
1186
1187 constexpr size_t detail_size() const noexcept { return sizeof(id)+sizeof(function); }
1188 };
1189
1190 constexpr static R invoke_impl(delegate_type* __restrict_cxx__ const data, A... args) {
1191 data_type* __restrict_cxx__ const d = data->template data<data_type>();
1192 if( d->function ) {
1193 return d->function(args...);
1194 } else {
1195 return R();
1196 }
1197 }
1198
1199 constexpr static bool equal_op_impl(const delegate_type& lhs_, const delegate_type& rhs_) noexcept {
1200 const data_type* lhs = lhs_.template data<const data_type>();
1201 const data_type* rhs = rhs_.template data<const data_type>();
1202 return lhs == rhs ||
1203 ( lhs_.type() == rhs_.type() &&
1204 lhs->id == rhs->id &&
1205 lhs->detail_size() && rhs->detail_size()
1206 );
1207 }
1208 static const delegate_type::target_func_t& get() {
1209 static typename delegate_type::target_func_t tf {
1210 invoke_impl, equal_op_impl,
1211 delegate_type::template getNonTrivialCtor<data_type>(),
1212 sizeof(data_type), target_type::std };
1213 return tf;
1214 };
1215
1216 public:
1217 static delegate_type delegate(uint64_t id, std::function<R(A...)> function) noexcept {
1218 return delegate_type::template make<data_type>( get(), id, function );
1219 }
1220 };
1221 /**@}*/
1222
1223 } /* namespace func */
1224
1225 constexpr uint32_t number(const func::target_type rhs) noexcept {
1226 return static_cast<uint32_t>(rhs);
1227 }
1228 std::string to_string(const func::target_type v) noexcept;
1229
1230 /**
1231 * Class template [jau::function](@ref function_def) is a general-purpose static-polymorphic function wrapper.
1232 *
1233 * See @ref function_overview "Function Overview".
1234 *
1235 * This is the dummy template variant, allowing the void- and non-void return type target specializations.
1236 *
1237 * @see @ref function_def "Function template definition"
1238 */
1239 template<typename Signature>
1241
1242 /**
1243 * @anchor function_def Class template [jau::function](@ref function_def) is a general-purpose static-polymorphic function wrapper.
1244 *
1245 * See @ref function_overview "Function Overview".
1246 *
1247 * @tparam R function return type
1248 * @tparam A function arguments
1249 * @see @ref function_overview "Function Overview"
1250 * @see @ref function_usage "Function Usage"
1251 */
1252 template<typename R, typename... A>
1253 class function<R(A...)> final_opt {
1254 public:
1255 /** The delegated target function type, i.e. func::delegate_t<R, A...> */
1256 typedef func::delegate_t<R, A...> delegate_type;
1257
1258 private:
1259 delegate_type target;
1260
1261 public:
1262 /** The target function return type R */
1263 typedef R result_type;
1264
1265 /**
1266 * \brief Null function constructor
1267 *
1268 * @anchor function_ctor_def
1269 * Constructs an instance with a null target function.
1270 * @see @ref function_overview "function Overview"
1271 * @see @ref function_usage "function Usage"
1272 */
1273 function() noexcept
1274 : target( func::null_target_t<R, A...>::delegate() )
1275 { }
1276
1277 /**
1278 * \brief Null function constructor
1279 *
1280 * @anchor function_ctor_nullptr
1281 * Constructs an instance with a null target function.
1282 * @see @ref function_overview "function Overview"
1283 * @see @ref function_usage "function Usage"
1284 */
1285 function(std::nullptr_t ) noexcept
1287 { }
1288
1289 /**
1290 * \brief Internally used delegate_t<R(A...)> constructor
1291 *
1292 * May utilize [copy elision](https://en.cppreference.com/w/cpp/language/copy_elision)
1293 * and/or named return value optimization (NRVO).
1294 *
1295 * @see @ref function_overview "function Overview"
1296 * @see @ref function_usage "function Usage"
1297 */
1298 explicit function(delegate_type _delegate, int dummy ) noexcept
1299 : target( std::move(_delegate) )
1300 { (void) dummy; }
1301
1302 /**
1303 * \brief Free function constructor
1304 *
1305 * @anchor function_ctor_free
1306 * Constructs an instance by taking a free target function, which may also be a non-capturing lambda if explicitly bind_free().
1307 * @see @ref function_overview "function Overview"
1308 * @see @ref function_usage "function Usage"
1309 */
1310 function(R(*func)(A...)) noexcept
1311 : target( func::free_target_t<R, A...>::delegate(func) )
1312 { }
1313
1314 /**
1315 * \brief Lambda function constructor
1316 *
1317 * @anchor function_ctor_lambda
1318 * Constructs an instance by taking a lambda function.
1319 *
1320 * @tparam L typename holding the lambda closure
1321 * @param func the lambda reference
1322 * @see @ref function_overview "function Overview"
1323 * @see @ref function_usage "function Usage"
1324 */
1325 template<typename L,
1326 std::enable_if_t<!std::is_same_v<L, std::shared_ptr<delegate_type>> &&
1327 !std::is_pointer_v<L> &&
1328 !std::is_same_v<L, R(A...)> &&
1329 !std::is_same_v<L, function<R(A...)>>
1330 , bool> = true>
1331 function(L func) noexcept
1333 { }
1334
1335 /**
1336 * \brief Lambda function bind factory
1337 *
1338 * @anchor function_bind_lambda
1339 * Constructs an instance by taking a lambda function.
1340 *
1341 * @tparam L typename holding the lambda closure
1342 * @param func the lambda reference
1343 * @see @ref function_overview "function Overview"
1344 * @see @ref function_usage "function Usage"
1345 */
1346 template<typename L>
1347 static function<R(A...)> bind_lambda(L func) noexcept
1348 {
1350 }
1351
1352 /**
1353 * \brief Y combinator Lambda function bind factory
1354 *
1355 * @anchor function_bind_ylambda
1356 * Constructs an instance by taking a lambda function,
1357 * implementing a [Y combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_functional_implementation)
1358 * and [deducing this](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html) lambda closure,
1359 * see [ylambda_target_t](@ref ylambda_target).
1360 *
1361 * @tparam L typename holding the lambda closure
1362 * @param func the lambda reference
1363 * @see @ref ylambda_target "ylambda_target_t"
1364 * @see @ref function_overview "function Overview"
1365 * @see @ref function_usage "function Usage"
1366 */
1367 template<typename L>
1368 static function<R(A...)> bind_ylambda(L func) noexcept
1369 {
1370 return function<R(A...)>( jau::func::ylambda_target_t<R, L, A...>::delegate(func), 0 );
1371 }
1372
1373 /**
1374 * \brief Member function constructor
1375 *
1376 * \anchor function_ctor_member
1377 * Constructs an instance by taking a member target function.
1378 * @tparam C0 class type holding the member-function
1379 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1380 * @param base pointer to the class instance of the member function
1381 * @param mfunc member function of class
1382 * @see @ref function_overview "function Overview"
1383 * @see @ref function_usage "function Usage"
1384 */
1385 template<typename C0, typename C1>
1386 function(C1 *base, R(C0::*mfunc)(A...)) noexcept
1387 : target( func::member_target_t<R, C0, C1, A...>::delegate(base, mfunc) )
1388 { }
1389
1390 /**
1391 * \brief Capture by value (copy) function constructor
1392 *
1393 * @anchor function_ctor_capval_copy
1394 * Constructs an instance by copying the captured value and the given non-void function to
1395 * an anonymous function using func::capval_target_t.
1396 *
1397 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1398 *
1399 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1400 *
1401 * @tparam I typename holding the captured data used by the function
1402 * @param data data type instance holding the captured data
1403 * @param func function with `R` return value and `A...` arguments.
1404 * @see @ref function_overview "function Overview"
1405 * @see @ref function_usage "function Usage"
1406 */
1407 template<typename I>
1408 function(const I& data, R(*func)(I&, A...)) noexcept
1409 : target( func::capval_target_t<R, I, A...>::delegate(data, func) )
1410 { }
1411
1412 /**
1413 * \brief Capture by value (move) function constructor
1414 *
1415 * @anchor function_ctor_capval_move
1416 * Constructs an instance by moving the captured value and copying the given non-void function to
1417 * an anonymous function using func::capval_target_t.
1418 *
1419 * `I&& data` will be moved into func::capval_target_t.
1420 *
1421 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1422 *
1423 * @tparam I typename holding the captured data used by the function
1424 * @param data data type instance holding the captured data
1425 * @param func function with `R` return value and `A...` arguments.
1426 * @see @ref function_overview "function Overview"
1427 * @see @ref function_usage "function Usage"
1428 */
1429 template<typename I>
1430 function(I&& data, R(*func)(I&, A...)) noexcept
1431 : target( func::capval_target_t<R, I, A...>::delegate(std::forward<I>(data), func) )
1432 { }
1433
1434 /**
1435 * \brief Capture by-reference function constructor
1436 *
1437 * @anchor function_ctor_capref
1438 * Constructs an instance by passing the captured reference (pointer) to the value and non-void function to
1439 * an anonymous function using func::capref_target_t.
1440 *
1441 * The function invocation will have the reference of the data being passed to the target function.
1442 *
1443 * @tparam I typename holding the captured data used by the function
1444 * @param data_ptr data type reference to instance holding the captured data
1445 * @param func function with `R` return value and `A...` arguments.
1446 * @see @ref function_overview "function Overview"
1447 * @see @ref function_usage "function Usage"
1448 */
1449 template<typename I>
1450 function(I* data_ptr, R(*func)(I*, A...)) noexcept
1451 : target( func::capref_target_t<R, I, A...>::delegate(data_ptr, func) )
1452 { }
1453
1454 /**
1455 * \brief std::function constructor
1456 *
1457 * @anchor function_ctor_std
1458 * Constructs an instance by copying the std::function to
1459 * an anonymous function using func::std_target_t.
1460 *
1461 * Notable, instance is holding the given unique uint64_t identifier
1462 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1463 *
1464 * @param func free-function with `R` return value and `A...` arguments.
1465 * @see @ref function_overview "function Overview"
1466 * @see @ref function_usage "function Usage"
1467 */
1468 function(uint64_t id, std::function<R(A...)> func) noexcept
1470 { }
1471
1472 function(const function &o) noexcept = default;
1473 function(function &&o) noexcept = default;
1474 function& operator=(const function &o) noexcept = default;
1475 function& operator=(function &&o) noexcept = default;
1476
1477 /** Return the jau::func::type of this instance */
1478 constexpr func::target_type type() const noexcept { return target.type(); }
1479
1480 /** Returns true if this instance does not hold a callable target function, i.e. is of func::target_type::null. */
1481 constexpr bool is_null() const noexcept { return func::target_type::null == target.type(); }
1482
1483 /** Returns true if this instance holds a callable target function, i.e. is not of func::target_type::null. */
1484 explicit constexpr operator bool() const noexcept { return !is_null(); }
1485
1486 /** Returns signature of this function prototype R(A...) w/o underlying target function object. */
1487 jau::type_info signature() const noexcept {
1488 return jau::make_ctti<R(A...)>();
1489 }
1490
1491 /** Returns true if the underlying target function is `TriviallyCopyable`. */
1492 constexpr bool is_target_trivially_copyable() const noexcept { return target.is_trivially_copyable(); }
1493
1494 /** Return the total size of this instance, may include heap allocated by delegate for bigger target functions. */
1495 constexpr size_t size() const noexcept { return target.heap_size() + sizeof(*this); }
1496
1497 /** Returns the size of underlying target function */
1498 constexpr size_t target_size() const noexcept { return target.target_size(); }
1499
1500 /**
1501 * Return a string representation of this instance.
1502 * @anchor function_toString The string representation contains the complete signature and detailed memory footprint.
1503 */
1504 std::string toString() const {
1505 return "function<" + to_string( type() ) + ", " + signature().name() + ">( sz net " +
1506 std::to_string( target_size() ) + " / ( delegate_t " +
1507 std::to_string( sizeof( target ) ) + " + target_vdata " +
1508 std::to_string( target.heap_size() ) + " -> "+
1509 std::to_string( size() ) + " ), trivial_cpy "+
1510 std::to_string( target.is_trivially_copyable() ) + " ) ";
1511 }
1512
1513 constexpr R operator()(A... args) const {
1514 return target(args...);
1515 }
1516 constexpr R operator()(A... args) {
1517 return target(args...);
1518 }
1519
1520 constexpr bool operator==(const function<R(A...)>& rhs) const noexcept {
1521 return target.operator==(rhs.target);
1522 }
1523 constexpr bool operator!=(const function<R(A...)>& rhs) const noexcept {
1524 return !operator==(rhs);
1525 }
1526 };
1527
1528 /**
1529 * Equal operator using different jau::function<R(A...)> return and argument types for both arguments,
1530 * always returns false.
1531 * @tparam Rl left function return type
1532 * @tparam Al left function arguments
1533 * @tparam Fl left function Fl<Rl(<Al...)>
1534 * @tparam Rr right function return type
1535 * @tparam Ar right function arguments
1536 * @tparam Fr right function Fr<Rr(<Ar...)>
1537 * @param lhs left function Fl<Rl(<Al...)>
1538 * @param rhs right function Fr<Rr(<Ar...)>
1539 * @return false
1540 * @see @ref function_overview "function Overview"
1541 * @see @ref function_usage "function Usage"
1542 */
1543 template<typename Rl, typename... Al, template <typename...> class Fl = function,
1544 typename Rr, typename... Ar, template <typename...> class Fr = function,
1545 std::enable_if_t< !std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1546 , bool> = true>
1547 bool operator==(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1548 {
1549 (void)lhs;
1550 (void)rhs;
1551 return false;
1552 }
1553
1554 /**
1555 * Equal operator using same jau::function<R(A...)> return and argument types for both arguments,
1556 * returning actual result of equality operation.
1557 * @tparam Rl left function return type
1558 * @tparam Al left function arguments
1559 * @tparam Fl left function Fl<Rl(<Al...)>
1560 * @tparam Rr right function return type
1561 * @tparam Ar right function arguments
1562 * @tparam Fr right function Fr<Rr(<Ar...)>
1563 * @param lhs left function Fl<Rl(<Al...)>
1564 * @param rhs right function Fr<Rr(<Ar...)>
1565 * @return equality result of same type functions
1566 * @see @ref function_overview "function Overview"
1567 * @see @ref function_usage "function Usage"
1568 */
1569 template<typename Rl, typename... Al, template <typename...> class Fl = function,
1570 typename Rr, typename... Ar, template <typename...> class Fr = function,
1571 std::enable_if_t< std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1572 , bool> = true>
1573 bool operator==(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1574 { return lhs.operator==( rhs ); }
1575
1576 /**
1577 * Unequal operator using two jau::function<R(A...)> types for both arguments.
1578 * @tparam Rl left function return type
1579 * @tparam Al left function arguments
1580 * @tparam Fl left function Fl<Rl(<Al...)>
1581 * @tparam Rr right function return type
1582 * @tparam Ar right function arguments
1583 * @tparam Fr right function Fr<Rr(<Ar...)>
1584 * @param lhs left function Fl<Rl(<Al...)>
1585 * @param rhs right function Fr<Rr(<Ar...)>
1586 * @return unequality result of same type functions
1587 * @see @ref function_overview "function Overview"
1588 * @see @ref function_usage "function Usage"
1589 */
1590 template<typename Rl, typename... Al, template <typename...> typename Fl = function,
1591 typename Rr, typename... Ar, template <typename...> typename Fr = function>
1592 bool operator!=(const function<Rl(Al...)>& lhs, const function<Rr(Ar...)>& rhs) noexcept
1593 { return !( lhs == rhs ); }
1594
1595 /**
1596 * Equal operator of jau::function<R(A...)> with a right-hand-side nullptr
1597 * @tparam R left function return type
1598 * @tparam A left function arguments
1599 * @param lhs left function
1600 * @return true if function instance contains no function, i.e. `!lhs` negated function bool operator.
1601 */
1602 template< class R, class... A>
1603 bool operator==(const function<R(A...)>& lhs, std::nullptr_t) noexcept
1604 { return !lhs; }
1605
1606 /**
1607 * Unequal operator of jau::function<R(A...)> with a right-hand-side nullptr
1608 * @tparam R left function return type
1609 * @tparam A left function arguments
1610 * @param lhs left function
1611 * @return true if function instance contains a function, i.e. `lhs` function bool operator.
1612 */
1613 template< class R, class... A>
1614 bool operator!=(const function<R(A...)>& lhs, std::nullptr_t) noexcept
1615 { return !( lhs == nullptr ); }
1616
1617 /**
1618 * Equal operator of jau::function<R(A...)> with a left-hand-side nullptr
1619 * @tparam R right function return type
1620 * @tparam A right function arguments
1621 * @param rhs right function
1622 * @return true if function instance contains no function, i.e. `!lhs` negated function bool operator.
1623 */
1624 template< class R, class... A>
1625 bool operator==(std::nullptr_t, const function<R(A...)>& rhs) noexcept
1626 { return !rhs; }
1627
1628 /**
1629 * Unequal operator of jau::function<R(A...)> with a left-hand-side nullptr
1630 * @tparam R right function return type
1631 * @tparam A right function arguments
1632 * @param rhs right function
1633 * @return true if function instance contains a function, i.e. `lhs` function bool operator.
1634 */
1635 template< class R, class... A>
1636 bool operator!=(std::nullptr_t, const function<R(A...)>& rhs) noexcept
1637 { return !( nullptr == rhs ); }
1638
1639 /**
1640 * Bind given class instance and non-void member function to
1641 * an anonymous function using func_member_targer_t.
1642 *
1643 * @tparam R function return type
1644 * @tparam C0 class type holding the member-function
1645 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1646 * @tparam A function arguments
1647 * @param base class instance `this` pointer
1648 * @param mfunc member-function with `R` return value and `A...` arguments.
1649 * @return anonymous function
1650 * @see @ref function_ctor_member "function constructor for member function"
1651 * @see @ref function_overview "function Overview"
1652 * @see @ref function_usage "function Usage"
1653 */
1654 template<typename R, typename C0, typename C1, typename... A>
1655 inline jau::function<R(A...)>
1656 bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept {
1657 return function<R(A...)>( func::member_target_t<R, C0, C1, A...>::delegate(base, mfunc), 0 );
1658 }
1659
1660 /**
1661 * Bind given class instance and non-void member function to
1662 * an anonymous function using func_member_targer_t.
1663 *
1664 * @tparam R function return type
1665 * @tparam C class type holding the member-function and of this base pointer
1666 * @tparam A function arguments
1667 * @param base class instance `this` pointer
1668 * @param mfunc member-function with `R` return value and `A...` arguments.
1669 * @return anonymous function
1670 * @see @ref function_ctor_member "function constructor for member function"
1671 * @see @ref function_overview "function Overview"
1672 * @see @ref function_usage "function Usage"
1673 */
1674 template<typename R, typename C, typename... A>
1675 inline jau::function<R(A...)>
1676 bind_member(C *base, R(C::*mfunc)(A...)) noexcept {
1677 return function<R(A...)>( func::member_target_t<R, C, C, A...>::delegate(base, mfunc), 0 );
1678 }
1679
1680 /**
1681 * Bind given class instance and void member function to
1682 * an anonymous function using func_member_targer_t.
1683 *
1684 * @tparam C0 class type holding the member-function
1685 * @tparam C1 class derived from C0 or C0 of this base-pointer used to invoke the member-function
1686 * @tparam A function arguments
1687 * @param base class instance `this` pointer
1688 * @param mfunc member-function with `A...` arguments.
1689 * @return anonymous function
1690 * @see @ref function_ctor_member "function constructor for member function"
1691 * @see @ref function_overview "function Overview"
1692 * @see @ref function_usage "function Usage"
1693 */
1694 template<typename C0, typename C1, typename... A>
1695 inline jau::function<void(A...)>
1696 bind_member(C1 *base, void(C0::*mfunc)(A...)) noexcept {
1697 return function<void(A...)>( func::member_target_t<void, C0, C1, A...>::delegate(base, mfunc), 0 );
1698 }
1699
1700 /**
1701 * Bind given class instance and void member function to
1702 * an anonymous function using func_member_targer_t.
1703 *
1704 * @tparam C class type holding the member-function and of this base pointer
1705 * @tparam A function arguments
1706 * @param base class instance `this` pointer
1707 * @param mfunc member-function with `A...` arguments.
1708 * @return anonymous function
1709 * @see @ref function_ctor_member "function constructor for member function"
1710 * @see @ref function_overview "function Overview"
1711 * @see @ref function_usage "function Usage"
1712 */
1713 template<typename C, typename... A>
1714 inline jau::function<void(A...)>
1715 bind_member(C *base, void(C::*mfunc)(A...)) noexcept {
1716 return function<void(A...)>( func::member_target_t<void, C, C, A...>::delegate(base, mfunc), 0 );
1717 }
1718
1719 /**
1720 * Bind given non-void free-function to
1721 * an anonymous function using func::free_target_t.
1722 *
1723 * @tparam R function return type
1724 * @tparam A function arguments
1725 * @param func free-function with `R` return value and `A...` arguments.
1726 * @return anonymous function
1727 * @see @ref function_ctor_free "function constructor for free function"
1728 * @see @ref function_overview "function Overview"
1729 * @see @ref function_usage "function Usage"
1730 */
1731 template<typename R, typename... A>
1732 inline jau::function<R(A...)>
1733 bind_free(R(*func)(A...)) noexcept {
1735 }
1736
1737 /**
1738 * Bind given void free-function to
1739 * an anonymous function using func::free_target_t.
1740 *
1741 * @tparam A function arguments
1742 * @param func free-function with `A...` arguments.
1743 * @return anonymous function
1744 * @see @ref function_ctor_free "function constructor for free function"
1745 * @see @ref function_overview "function Overview"
1746 * @see @ref function_usage "function Usage"
1747 */
1748 template<typename... A>
1749 inline jau::function<void(A...)>
1750 bind_free(void(*func)(A...)) noexcept {
1752 }
1753
1754 /**
1755 * Bind given data by copying the captured value and the given non-void function to
1756 * an anonymous function using func::capval_target_t.
1757 *
1758 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1759 *
1760 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1761 *
1762 * @tparam R function return type
1763 * @tparam I typename holding the captured data used by the function
1764 * @tparam A function arguments
1765 * @param data data type instance holding the captured data
1766 * @param func function with `R` return value and `A...` arguments.
1767 * @return anonymous function
1768 * @see @ref function_ctor_capval_copy "function constructor for copying capturing value"
1769 * @see @ref function_overview "function Overview"
1770 * @see @ref function_usage "function Usage"
1771 */
1772 template<typename R, typename I, typename... A>
1773 inline jau::function<R(A...)>
1774 bind_capval(const I& data, R(*func)(I&, A...)) noexcept {
1775 return function<R(A...)>( func::capval_target_t<R, I, A...>::delegate(data, func), 0 );
1776 }
1777
1778 /**
1779 * Bind given data by copying the captured value and the given void function to
1780 * an anonymous function using func::capval_target_t.
1781 *
1782 * `const I& data` will be copied into func::capval_target_t and hence captured by-copy.
1783 *
1784 * The function invocation will have the reference of the copied data being passed to the target function for efficiency.
1785 *
1786 * @tparam I typename holding the captured data used by the function
1787 * @tparam A function arguments
1788 * @param data data type instance holding the captured data
1789 * @param func function with `A...` arguments.
1790 * @return anonymous function
1791 * @see @ref function_ctor_capval_copy "function constructor for copying capturing value"
1792 * @see @ref function_overview "function Overview"
1793 * @see @ref function_usage "function Usage"
1794 */
1795 template<typename I, typename... A>
1796 inline jau::function<void(A...)>
1797 bind_capval(const I& data, void(*func)(I&, A...)) noexcept {
1798 return function<void(A...)>( func::capval_target_t<void, I, A...>::delegate(data, func), 0 );
1799 }
1800
1801 /**
1802 * Bind given data by moving the captured value and copying the given non-void function to
1803 * an anonymous function using func::capval_target_t.
1804 *
1805 * `I&& data` will be moved into func::capval_target_t.
1806 *
1807 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1808 *
1809 * @tparam R function return type
1810 * @tparam I typename holding the captured data used by the function
1811 * @tparam A function arguments
1812 * @param data data type instance holding the captured data
1813 * @param func function with `R` return value and `A...` arguments.
1814 * @return anonymous function
1815 * @see @ref function_ctor_capval_move "function constructor for moving capturing value"
1816 * @see @ref function_overview "function Overview"
1817 * @see @ref function_usage "function Usage"
1818 */
1819 template<typename R, typename I, typename... A>
1820 inline jau::function<R(A...)>
1821 bind_capval(I&& data, R(*func)(I&, A...)) noexcept {
1822 return function<R(A...)>( func::capval_target_t<R, I, A...>::delegate(std::forward<I>(data), func), 0 );
1823 }
1824
1825 /**
1826 * Bind given data by moving the captured value and copying the given void function to
1827 * an anonymous function using func::capval_target_t.
1828 *
1829 * `I&& data` will be moved into func::capval_target_t.
1830 *
1831 * The function invocation will have the reference of the moved data being passed to the target function for efficiency.
1832 *
1833 * @tparam I typename holding the captured data used by the function
1834 * @tparam A function arguments
1835 * @param data data type instance holding the captured data
1836 * @param func function with `A...` arguments.
1837 * @return anonymous function
1838 * @see @ref function_ctor_capval_move "function constructor for moving capturing value"
1839 * @see @ref function_overview "function Overview"
1840 * @see @ref function_usage "function Usage"
1841 */
1842 template<typename I, typename... A>
1843 inline jau::function<void(A...)>
1844 bind_capval(I&& data, void(*func)(I&, A...)) noexcept {
1845 return function<void(A...)>( func::capval_target_t<void, I, A...>::delegate(std::forward<I>(data), func), 0 );
1846 }
1847
1848 /**
1849 * Bind given data by passing the captured reference (pointer) to the value and non-void function to
1850 * an anonymous function using func::capref_target_t.
1851 *
1852 * The function invocation will have the reference of the data being passed to the target function.
1853 *
1854 * @tparam R function return type
1855 * @tparam I typename holding the captured data used by the function
1856 * @tparam A function arguments
1857 * @param data_ptr data type reference to instance holding the captured data
1858 * @param func function with `R` return value and `A...` arguments.
1859 * @return anonymous function
1860 * @see @ref function_ctor_capref "function constructor for capturing reference"
1861 * @see @ref function_overview "function Overview"
1862 * @see @ref function_usage "function Usage"
1863 */
1864 template<typename R, typename I, typename... A>
1865 inline jau::function<R(A...)>
1866 bind_capref(I* data_ptr, R(*func)(I*, A...)) noexcept {
1867 return function<R(A...)>( func::capref_target_t<R, I, A...>::delegate(data_ptr, func), 0 );
1868 }
1869
1870 /**
1871 * Bind given data by passing the captured reference (pointer) to the value and void function to
1872 * an anonymous function using func::capref_target_t.
1873 *
1874 * The function invocation will have the reference of the data being passed to the target function.
1875 *
1876 * @tparam I typename holding the captured data used by the function
1877 * @tparam A function arguments
1878 * @param data_ptr data type reference to instance holding the captured data
1879 * @param func function with `A...` arguments.
1880 * @return anonymous function
1881 * @see @ref function_ctor_capref "function constructor for capturing reference"
1882 * @see @ref function_overview "function Overview"
1883 * @see @ref function_usage "function Usage"
1884 */
1885 template<typename I, typename... A>
1886 inline jau::function<void(A...)>
1887 bind_capref(I* data_ptr, void(*func)(I*, A...)) noexcept {
1888 return function<void(A...)>( func::capref_target_t<void, I, A...>::delegate(data_ptr, func), 0 );
1889 }
1890
1891 /**
1892 * Bind given non-void std::function to
1893 * an anonymous function using func::std_target_t.
1894 *
1895 * Notable, instance is holding the given unique uint64_t identifier
1896 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1897 *
1898 * @tparam R function return type
1899 * @tparam A function arguments
1900 * @param func free-function with `R` return value and `A...` arguments.
1901 * @return anonymous function
1902 * @see @ref function_ctor_std "function constructor for std::function"
1903 * @see @ref function_overview "function Overview"
1904 * @see @ref function_usage "function Usage"
1905 */
1906 template<typename R, typename... A>
1907 inline jau::function<R(A...)>
1908 bind_std(uint64_t id, std::function<R(A...)> func) noexcept {
1909 return function<R(A...)>( func::std_target_t<R, A...>::delegate(id, func), 0 );
1910 }
1911
1912 /**
1913 * Bind given void std::function to
1914 * an anonymous function using func::std_target_t.
1915 *
1916 * Notable, instance is holding the given unique uint64_t identifier
1917 * to allow implementing the equality operator w/o RTTI, not supported by std::function.
1918 *
1919 * @tparam A function arguments
1920 * @param func free-function with `A...` arguments.
1921 * @return anonymous function
1922 * @see @ref function_ctor_std "function constructor for std::function"
1923 * @see @ref function_overview "function Overview"
1924 * @see @ref function_usage "function Usage"
1925 */
1926 template<typename... A>
1927 inline jau::function<void(A...)>
1928 bind_std(uint64_t id, std::function<void(A...)> func) noexcept {
1929 return function<void(A...)>( func::std_target_t<void, A...>::delegate(id, func), 0 );
1930 }
1931
1932 /**@}*/
1933
1934} // namespace jau
1935
1936/** \example test_functional.hpp
1937 * This C++ unit test validates the jau::function<R(A...)> and all its jau::func::target_t specializations.
1938 */
1939
1940/** \example test_functional_perf.hpp
1941 * This C++ unit test benchmarks the jau::function<R(A...)> and all its jau::func::target_t specializations.
1942 */
1943
1944#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.
func::capref_target_t implementation for functions using a reference to a captured value,...
func::capval_target_t implementation for functions using a copy of a captured value,...
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.
func::free_target_t implementation for free functions, identifiable as func::target_type::free via ja...
func::lambda_target_t implementation for lambda closures, identifiable as func::target_type::lambda v...
func::member_target_t implementation for class member functions, identifiable as func::target_type::m...
func::null_target_t implementation for no function.
func::std_target_t implementation for std::function instances, identifiable as func::target_type::std...
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Generic type information using either Runtime type information (RTTI) or Compile time type informatio...
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line fu...
Definition debug.hpp:101
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
#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.
@ std
Denotes a func::std_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 *)