26#ifndef JAU_FUNCTIONAL_HPP_
27#define JAU_FUNCTIONAL_HPP_
376 template<
typename R,
typename... A>
390 struct non_trivial_t final {
398 constexpr non_trivial_t() noexcept
403 struct heap_t final {
405 non_trivial_t* non_trivial;
414 union target_data_t {
433 : m_cb(cb_), m_eqop(eqop_), m_size( size_ ), m_type(type_)
435 if(
static_cast<size_type>(
sizeof(udata.cache) ) >= m_size ) {
440 udata.heap.memory = ::malloc(m_size);
441 udata.heap.non_trivial =
nullptr;
449 : m_cb(cb_), m_eqop(eqop_), m_size( size_ ), m_type(type_)
452 udata.heap.non_trivial =
new non_trivial_t(nt);
453 }
catch (
const std::bad_alloc &e) {
454 ABORT(
"Error: bad_alloc: non_trivial allocation failed");
457 udata.heap.memory = ::malloc(m_size);
460 void clear() noexcept {
462 if(
nullptr != udata.heap.non_trivial ) {
463 udata.heap.non_trivial->dtor(
this);
464 delete udata.heap.non_trivial;
465 udata.heap.non_trivial =
nullptr;
467 ::free(udata.heap.memory);
468 udata.heap.memory =
nullptr;
481 template<
typename T,
typename... P,
482 std::enable_if_t<std::is_trivially_copyable_v<T> &&
488 new(
target.template data<T>() ) T(params...);
493 template<
typename T,
typename... P,
494 std::enable_if_t<!std::is_trivially_copyable_v<T> &&
496 std::is_destructible_v<T> &&
497 std::is_copy_constructible_v<T> &&
498 std::is_move_constructible_v<T>,
503 nt.dtor = [](delegate_t* i) ->
void {
504 T* t = i->template data<T>();
510 new( i->template data<T>() ) T( *( o->template data<T>() ) );
513 new( i->template data<T>() ) T( std::move( *( o->template data<T>() ) ) );
516 new(
target.template data<T>() ) T(params...);
523 : m_cb( o.m_cb ), m_eqop( o.m_eqop ),
524 m_size(o.m_size), m_type( o.m_type )
527 udata.heap.memory = ::malloc(m_size);
528 if(
nullptr == udata.heap.memory ) {
529 ABORT(
"Error: bad_alloc: heap.memory allocation failed");
532 if(
nullptr != o.udata.heap.non_trivial ) {
534 udata.heap.non_trivial =
new non_trivial_t( *o.udata.heap.non_trivial );
535 }
catch (
const std::bad_alloc &e) {
536 ABORT(
"Error: bad_alloc: non_trivial allocation failed");
539 udata.heap.non_trivial->copy_ctor(
this, &o);
541 udata.heap.non_trivial =
nullptr;
542 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
545 ::memcpy(udata.cache, o.udata.cache,
std::abs(m_size));
550 : m_cb( std::move( o.m_cb ) ), m_eqop( std::move( o.m_eqop ) ),
551 m_size( std::move( o.m_size ) ), m_type( std::move( o.m_type ) )
554 udata.heap.non_trivial = std::move( o.udata.heap.non_trivial );
555 o.udata.heap.non_trivial =
nullptr;
556 if(
nullptr != udata.heap.non_trivial ) {
557 udata.heap.memory = ::malloc(o.m_size);
558 if(
nullptr == udata.heap.memory ) {
559 ABORT(
"Error: bad_alloc: heap.memory allocation failed");
562 udata.heap.non_trivial->move_ctor(
this, &o);
563 udata.heap.non_trivial->dtor(&o);
564 ::free(o.udata.heap.memory);
566 udata.heap.memory = std::move( o.udata.heap.memory );
568 o.udata.heap.memory =
nullptr;
570 ::memcpy(udata.cache, o.udata.cache,
std::abs(m_size));
584 if( 0 >= m_size && 0 >= o.m_size ) {
588 ::memcpy(udata.cache, o.udata.cache,
std::abs(m_size));
589 }
else if( m_size > 0 && o.m_size > 0 && m_size <= o.m_size ) {
593 if(
nullptr != udata.heap.non_trivial ) {
594 udata.heap.non_trivial->dtor(
this);
595 if(
nullptr != o.udata.heap.non_trivial ) {
596 *udata.heap.non_trivial = *o.udata.heap.non_trivial;
598 delete udata.heap.non_trivial;
599 udata.heap.non_trivial =
nullptr;
602 if(
nullptr != udata.heap.non_trivial ) {
603 udata.heap.non_trivial->copy_ctor(
this, &o);
605 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
613 udata.heap.memory = ::malloc(m_size);
614 if(
nullptr == udata.heap.memory ) {
615 ABORT(
"Error: bad_alloc: heap.memory allocation failed");
618 if(
nullptr != o.udata.heap.non_trivial ) {
620 udata.heap.non_trivial =
new non_trivial_t( *o.udata.heap.non_trivial );
621 }
catch (
const std::bad_alloc &e) {
622 ABORT(
"Error: bad_alloc: non_trivial allocation failed");
625 udata.heap.non_trivial->copy_ctor(
this, &o);
627 udata.heap.non_trivial =
nullptr;
628 ::memcpy(udata.heap.memory, o.udata.heap.memory, m_size);
631 ::memcpy(udata.cache, o.udata.cache,
std::abs(m_size));
644 m_cb = std::move( o.m_cb );
645 m_eqop = std::move( o.m_eqop );
646 m_size = std::move( o.m_size );
647 m_type = std::move( o.m_type );
650 udata.heap.non_trivial = std::move( o.udata.heap.non_trivial );
651 o.udata.heap.non_trivial =
nullptr;
652 if(
nullptr != udata.heap.non_trivial ) {
653 udata.heap.memory = ::malloc(o.m_size);
654 if(
nullptr == udata.heap.memory ) {
655 ABORT(
"Error: bad_alloc: heap.memory allocation failed");
658 udata.heap.non_trivial->move_ctor(
this, &o);
659 udata.heap.non_trivial->dtor(&o);
660 ::free(o.udata.heap.memory);
662 udata.heap.memory = std::move( o.udata.heap.memory );
664 o.udata.heap.memory =
nullptr;
666 ::memcpy(udata.cache, o.udata.cache,
std::abs(m_size));
673 std::enable_if_t<std::is_trivially_copyable_v<T> &&
674 sizeof(udata.cache) >=
sizeof(T),
676 constexpr const T*
data() const noexcept {
677 return static_cast<const T*
>(
static_cast<const void*
>( udata.cache ) );
681 std::enable_if_t<!std::is_trivially_copyable_v<T> ||
682 sizeof(udata.cache) <
sizeof(T),
684 constexpr const T*
data() const noexcept {
685 return static_cast<const T*
>( udata.heap.memory );
689 std::enable_if_t<std::is_trivially_copyable_v<T> &&
690 sizeof(udata.cache) >=
sizeof(T),
692 constexpr T*
data() noexcept {
693 return static_cast<T*
>(
static_cast<void*
>( udata.cache ) );
697 std::enable_if_t<!std::is_trivially_copyable_v<T> ||
698 sizeof(udata.cache) <
sizeof(T),
701 return static_cast<T*
>( udata.heap.memory );
711 return m_cb(
const_cast<delegate_t*
>(
this), args...);
721 return m_eqop(*
this, rhs);
727 constexpr size_t heap_size() const noexcept {
return 0 >= m_size ? 0 : ( m_size + (
nullptr != udata.heap.non_trivial ?
sizeof(*udata.heap.non_trivial) : 0 ) ); }
748 template<
typename R,
typename... A>
759 return lhs.type() == rhs.type();
782 template<
typename R,
typename C0,
typename C1,
typename... A>
789#if defined(__GNUC__) && !defined(__clang__)
797 typedef R(*function_t)(C0*, A...);
799 struct data_type final {
803 constexpr data_type(
C1 *_base, R(C0::*_method)(A...)) noexcept
808 function = (function_t)(_base->*_method);
815 return ( *(d->function) )(d->base, args...);
819 const data_type* lhs = lhs_.template data<const data_type>();
820 const data_type* rhs = rhs_.template data<const data_type>();
822 ( lhs_.type() == rhs_.type() &&
823 lhs->base == rhs->base &&
824 lhs->function== rhs->function
831 struct data_type final {
833 R(C0::*method)(A...);
835 constexpr data_type(
C1 *_base, R(C0::*_method)(A...)) noexcept
836 : base(_base), method(_method) { }
841 return (d->base->*d->method)(args...);
845 const data_type* lhs = lhs_.template data<const data_type>();
846 const data_type* rhs = rhs_.template data<const data_type>();
848 ( lhs_.type() == rhs_.type() &&
849 lhs->base == rhs->base &&
850 lhs->method == rhs->method
866 std::enable_if_t<std::is_base_of_v<C0, C1>,
bool> =
true) noexcept
868 return delegate_type::template make<data_type>(
target_type::member, invoke_impl, equal_op_impl, base, method );
880 template<
typename R,
typename... A>
886 struct data_type final {
889 data_type(R(*_function)(A...)) noexcept
894 return ( *(data->template data<data_type>()->function) )(args...);
898 const data_type* lhs = lhs_.template data<const data_type>();
899 const data_type* rhs = rhs_.template data<const data_type>();
901 ( lhs_.type() == rhs_.type() &&
902 lhs->function== rhs->function
921 template<
typename R,
typename L,
typename...A>
927 struct data_type final {
931 data_type(L _function) noexcept
932 :
function( _function ), sig( jau::make_ctti<R, L, A...>() ) {}
934 constexpr size_t detail_size()
const noexcept {
return sizeof(
function); }
938 return ( data->template data<data_type>()->function )(args...);
942 const data_type* lhs = lhs_.template data<const data_type>();
943 const data_type* rhs = rhs_.template data<const data_type>();
945 ( lhs_.type() == rhs_.type() &&
946 lhs->detail_size() == rhs->detail_size() &&
947 lhs->sig == rhs->sig &&
948 0 == ::memcmp((
void*)&lhs->function, (
void*)&rhs->function,
sizeof(lhs->function))
1004 template<
typename R,
typename L,
typename...A>
1010 struct data_type final {
1014 data_type(L _function) noexcept
1015 :
function( _function ), sig( jau::make_ctti<R, L, A...>() ) {
1022 constexpr size_t detail_size()
const noexcept {
return sizeof(
function); }
1026 return ( data->template data<data_type>()->function )(*data, args...);
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() &&
1035 lhs->sig == rhs->sig &&
1036 0 == ::memcmp((
void*)&lhs->function, (
void*)&rhs->function,
sizeof(lhs->function))
1055 template<
typename R,
typename I,
typename... A>
1061 struct data_type final {
1065 data_type(
const I& _data, R(*_function)(I&, A...)) noexcept
1066 :
function(_function), data(_data) {}
1068 data_type(I&& _data, R(*_function)(I&, A...)) noexcept
1069 :
function(_function), data(std::move(_data)) {}
1074 return (*d->function)(d->data, args...);
1078 const data_type* lhs = lhs_.template data<const data_type>();
1079 const data_type* rhs = rhs_.template data<const data_type>();
1080 return lhs == rhs ||
1081 ( lhs_.type() == rhs_.type() &&
1082 lhs->function == rhs->function &&
1083 lhs->data == rhs->data
1106 template<
typename R,
typename I,
typename... A>
1112 struct data_type final {
1116 data_type(I* _data_ptr, R(*_function)(I*, A...)) noexcept
1117 :
function(_function), data_ptr(_data_ptr) {}
1122 return (*d->function)(d->data_ptr, args...);
1126 const data_type* lhs = lhs_.template data<const data_type>();
1127 const data_type* rhs = rhs_.template data<const data_type>();
1128 return lhs == rhs ||
1129 ( lhs_.type() == rhs_.type() &&
1130 lhs->function == rhs->function &&
1131 lhs->data_ptr == rhs->data_ptr
1152 template<
typename R,
typename... A>
1158 struct data_type final {
1162 data_type(uint64_t id_, std::function<R(A...)> function_) noexcept
1163 :
function(std::move(function_)), id(id_) {}
1165 constexpr size_t detail_size()
const noexcept {
return sizeof(id)+
sizeof(
function); }
1171 return d->function(args...);
1178 const data_type* lhs = lhs_.template data<const data_type>();
1179 const data_type* rhs = rhs_.template data<const data_type>();
1180 return lhs == rhs ||
1181 ( lhs_.type() == rhs_.type() &&
1182 lhs->id == rhs->id &&
1183 lhs->detail_size() && rhs->detail_size()
1197 return static_cast<uint32_t
>(rhs);
1210 template<
typename Signature>
1223 template<
typename R,
typename... A>
1245 : target( func::null_target_t<R, A...>::delegate() )
1270 : target( std::move(_delegate) )
1282 : target( func::free_target_t<R, A...>::delegate(func) )
1296 template<
typename L,
1297 std::enable_if_t<!std::is_same_v<L, std::shared_ptr<delegate_type>> &&
1298 !std::is_pointer_v<L> &&
1299 !std::is_same_v<L, R(A...)> &&
1300 !std::is_same_v<L,
function<R(A...)>>
1317 template<
typename L>
1338 template<
typename L>
1356 template<
typename C0,
typename C1>
1358 : target( func::member_target_t<R, C0,
C1, A...>::delegate(base, mfunc) )
1378 template<
typename I>
1380 : target( func::capval_target_t<R, I, A...>::delegate(data, func) )
1400 template<
typename I>
1402 : target( func::capval_target_t<R, I, A...>::delegate(
std::forward<I>(data), func) )
1420 template<
typename I>
1422 : target( func::capref_target_t<R, I, A...>::delegate(data_ptr, func) )
1439 function(uint64_t
id, std::function<R(A...)> func) noexcept
1455 explicit constexpr operator bool() const noexcept {
return !is_null(); }
1466 constexpr size_t size() const noexcept {
return target.
heap_size() +
sizeof(*this); }
1476 return "function<" +
to_string( type() ) +
", " + signature().demangled_name() +
">( sz net " +
1485 return target(args...);
1488 return target(args...);
1492 return target.operator==(rhs.target);
1514 template<
typename Rl,
typename... Al,
template <
typename...>
class Fl = function,
1515 typename Rr,
typename... Ar,
template <
typename...>
class Fr = function,
1516 std::enable_if_t< !std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1540 template<
typename Rl,
typename... Al,
template <
typename...>
class Fl = function,
1541 typename Rr,
typename... Ar,
template <
typename...>
class Fr = function,
1542 std::enable_if_t< std::is_same_v< Fl<Rl(Al...)>, Fr<Rr(Ar...)> >
1544 bool operator==(
const function<Rl(Al...)>& lhs,
const function<Rr(Ar...)>& rhs)
noexcept
1545 {
return lhs.operator==( rhs ); }
1561 template<
typename Rl,
typename... Al,
template <
typename...>
typename Fl = function,
1562 typename Rr,
typename... Ar,
template <
typename...>
typename Fr = function>
1564 {
return !( lhs == rhs ); }
1573 template<
class R,
class... A>
1584 template<
class R,
class... A>
1586 {
return !( lhs == nullptr ); }
1595 template<
class R,
class... A>
1606 template<
class R,
class... A>
1608 {
return !(
nullptr == rhs ); }
1625 template<
typename R,
typename C0,
typename C1,
typename... A>
1645 template<
typename R,
typename C,
typename... A>
1665 template<
typename C0,
typename C1,
typename... A>
1684 template<
typename C,
typename... A>
1702 template<
typename R,
typename... A>
1719 template<
typename... A>
1743 template<
typename R,
typename I,
typename... A>
1766 template<
typename I,
typename... A>
1790 template<
typename R,
typename I,
typename... A>
1813 template<
typename I,
typename... A>
1835 template<
typename R,
typename I,
typename... A>
1856 template<
typename I,
typename... A>
1877 template<
typename R,
typename... A>
1879 bind_std(uint64_t
id, std::function<R(A...)> func)
noexcept {
1897 template<
typename... A>
1899 bind_std(uint64_t
id, std::function<
void(A...)> func)
noexcept {
func::capref_target_t implementation for functions using a reference to a captured value,...
static delegate_type delegate(I *data_ptr, R(*function)(I *, A...)) noexcept
delegate_t< R, A... > delegate_type
func::capval_target_t implementation for functions using a copy of a captured value,...
static delegate_type delegate(const I &data, R(*function)(I &, A...)) noexcept
delegate_t< R, A... > delegate_type
static delegate_type delegate(I &&data, R(*function)(I &, A...)) noexcept
Delegated target function object, providing a fast path target function invocation.
std::enable_if_t<!std::is_trivially_copyable_v< T >||sizeof(udata.cache)< sizeof(T), bool >=true > constexpr const T * data() const noexcept
constexpr size_t heap_size() const noexcept
delegate_t(delegate_t &&o) noexcept
delegate_t target(type_, static_cast< size_type >(sizeof(T)), nt, cb_, eqop_)
constexpr R operator()(A... args) const
Delegated fast path target function invocation, see above.
constexpr bool operator==(const delegate_t< R, A... > &rhs) const noexcept
Delegated fast path target function equality operator.
int32_t size_type
Utilize a reduced size type of int32_t.
std::enable_if_t<!std::is_trivially_copyable_v< T >||sizeof(udata.cache)< sizeof(T), bool >=true > constexpr T * data() noexcept
constexpr bool is_trivially_copyable() const noexcept
Returns true if the underlying target function is TriviallyCopyable.
delegate_t & operator=(delegate_t &&o) noexcept
delegate_t(const delegate_t &o) noexcept
delegate_t & operator=(const delegate_t &o) noexcept
static delegate_t make(invocation_t cb_, equal_op_t eqop_) noexcept
constexpr size_t cached_size() const noexcept
bool(* equal_op_t)(const delegate_t &data_lhs, const delegate_t &data_rhs) noexcept
constexpr size_t target_size() const noexcept
Returns the size of underlying target function.
R(* invocation_t)(delegate_t *__restrict_cxx__ const data, A... args)
constexpr target_type type() const noexcept
Return the func::target_type of this invocation function wrapper.
func::free_target_t implementation for free functions, identifiable as func::target_type::free via ja...
static delegate_type delegate(R(*function)(A...)) noexcept
delegate_t< R, A... > delegate_type
func::lambda_target_t implementation for lambda closures, identifiable as func::target_type::lambda v...
static delegate_type delegate(L function) noexcept
delegate_t< R, A... > delegate_type
func::member_target_t implementation for class member functions, identifiable as func::target_type::m...
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< R, A... > delegate_type
func::null_target_t implementation for no function.
delegate_t< R, A... > delegate_type
static delegate_type delegate() noexcept
func::std_target_t implementation for std::function instances, identifiable as func::target_type::std...
delegate_t< R, A... > delegate_type
static delegate_type delegate(uint64_t id, std::function< R(A...)> function) noexcept
func::ylambda_target_t is a Y combinator and deducing this implementation for lambda closures usable ...
delegate_t< R, A... > delegate_type
static delegate_type delegate(L function) noexcept
function(C1 *base, R(C0::*mfunc)(A...)) noexcept
Member function constructor.
function & operator=(function &&o) noexcept=default
constexpr bool operator!=(const function< R(A...)> &rhs) const noexcept
constexpr size_t target_size() const noexcept
Returns the size of underlying target function.
constexpr func::target_type type() const noexcept
Return the jau::func::type of this instance.
function(L func) noexcept
Lambda function constructor.
std::string toString() const
Return a string representation of this instance.
constexpr bool operator==(const function< R(A...)> &rhs) const noexcept
func::delegate_t< R, A... > delegate_type
The delegated target function type, i.e.
function(uint64_t id, std::function< R(A...)> func) noexcept
std::function constructor
function(I &&data, R(*func)(I &, A...)) noexcept
Capture by value (move) function constructor.
function(const I &data, R(*func)(I &, A...)) noexcept
Capture by value (copy) function constructor.
function(R(*func)(A...)) noexcept
Free function constructor.
constexpr bool is_null() const noexcept
Returns true if this instance does not hold a callable target function, i.e.
function() noexcept
Null function constructor.
R result_type
The target function return type R.
constexpr size_t size() const noexcept
Return the total size of this instance, may include heap allocated by delegate for bigger target func...
static function< R(A...)> bind_lambda(L func) noexcept
Lambda function bind factory.
function & operator=(const function &o) noexcept=default
function(delegate_type _delegate, int dummy) noexcept
Internally used delegate_t<R(A...)> constructor.
constexpr R operator()(A... args) const
function(function &&o) noexcept=default
jau::type_info signature() const noexcept
Returns signature of this function prototype R(A...) w/o underlying target function object.
static function< R(A...)> bind_ylambda(L func) noexcept
Y combinator Lambda function bind factory.
function(const function &o) noexcept=default
function(I *data_ptr, R(*func)(I *, A...)) noexcept
Capture by-reference function constructor.
function(std::nullptr_t) noexcept
Null function constructor.
constexpr bool is_target_trivially_copyable() const noexcept
Returns true if the underlying target function is TriviallyCopyable.
constexpr R operator()(A... args)
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Generic type information using either Runtime type information (RTTI) or Compile time type informatio...
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line fu...
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
jau::type_info make_ctti() noexcept
Constructs a jau::type_info instance based on given type T using template Compile Time Type Informati...
#define PRAGMA_DISABLE_WARNING_PMF_CONVERSIONS
#define PRAGMA_DISABLE_WARNING_PUSH
#define __restrict_cxx__
Wrap C++ extension __restrict__ covering C99's restrict feature keyword.
#define PRAGMA_DISABLE_WARNING_POP
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
target_type
func::target_type identifier for the target function delegate_t<R, A...> object, exposed by jau::func...
jau::function< R(A...)> bind_free(R(*func)(A...)) noexcept
Bind given non-void free-function to an anonymous function using func::free_target_t.
jau::function< R(A...)> bind_std(uint64_t id, std::function< R(A...)> func) noexcept
Bind given non-void std::function to an anonymous function using func::std_target_t.
jau::function< R(A...)> bind_capval(const I &data, R(*func)(I &, A...)) noexcept
Bind given data by copying the captured value and the given non-void function to an anonymous functio...
std::string to_string(const func::target_type v) noexcept
jau::function< R(A...)> bind_capref(I *data_ptr, R(*func)(I *, A...)) noexcept
Bind given data by passing the captured reference (pointer) to the value and non-void function to an ...
constexpr uint32_t number(const func::target_type rhs) noexcept
@ null
Denotes a func::null_target_t.
@ lambda
Denotes a func::lambda_target_t.
@ capval
Denotes a func::capval_target_t.
@ capref
Denotes a func::capref_target_t.
@ member
Denotes a func::member_target_t.
@ free
Denotes a func::free_target_t.
@ std
Denotes a func::std_target_t.
@ ylambda
Denotes a func::ylambda_target_t.
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept