2021-06-27 21:25:29 +00:00
/***
Copyright ( C ) 2021 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : Async . hpp
2021-09-06 10:58:08 +00:00
Date : 2021 - 7 - 14
2021-06-27 21:25:29 +00:00
Author : Reece
* * */
# pragma once
2021-10-01 16:26:27 +00:00
namespace Aurora : : Loop
{
class ILoopSource ;
}
2021-06-27 21:25:29 +00:00
namespace Aurora : : Async
{
class IWorkItem ;
class IAsyncApp ;
using AVoid = AuUInt8 ;
AUKN_SYM IAsyncApp * GetAsyncApp ( ) ;
2021-09-29 14:31:40 +00:00
/// ThreadGroup_t:
/// 0 = system main thread
/// 1+ = user defined
2021-10-08 19:51:34 +00:00
using ThreadGroup_t = AuUInt8 ;
2021-09-29 14:31:40 +00:00
/// ThreadId_t:
2021-09-30 09:19:04 +00:00
/// -1 = invalid
/// index = tid/runner id
2021-10-08 19:51:34 +00:00
using ThreadId_t = AuUInt16 ;
2021-09-30 09:19:04 +00:00
static const ThreadId_t kThreadIdAny = - 1 ;
2021-10-08 19:51:34 +00:00
struct WorkerId_t : AuPair < ThreadGroup_t , ThreadId_t >
{
WorkerId_t ( ) : AuPair < ThreadGroup_t , ThreadId_t > ( 0 , 0 )
{ }
WorkerId_t ( ThreadGroup_t group ) : AuPair < ThreadGroup_t , ThreadId_t > ( group , kThreadIdAny )
{ }
WorkerId_t ( ThreadGroup_t group , ThreadId_t id ) : AuPair < ThreadGroup_t , ThreadId_t > ( group , id )
{ }
WorkerId_t ( const WorkerId_t & cpy ) : AuPair < ThreadGroup_t , ThreadId_t > ( cpy . first , cpy . second )
{ }
} ;
2021-06-27 21:25:29 +00:00
2021-09-29 10:47:54 +00:00
struct WorkPriv
{
AuUInt32 magic ;
} ;
2021-06-27 21:33:58 +00:00
struct IWorkItemHandler
{
enum class EProcessNext
{
eInvalid = - 1 ,
eFinished = 0 ,
eRerun ,
eSchedule ,
2021-06-27 21:25:29 +00:00
eFailed
2021-06-27 21:33:58 +00:00
} ;
2021-06-27 21:25:29 +00:00
2021-06-27 21:33:58 +00:00
struct ProcessInfo
{
ProcessInfo ( bool finished ) : type ( finished ? EProcessNext : : eFinished : EProcessNext : : eFailed ) { }
ProcessInfo ( EProcessNext type ) : type ( type ) { }
ProcessInfo ( const AuList < AuSPtr < IWorkItem > > & blockedBy ) : type ( EProcessNext : : eSchedule ) , waitFor ( blockedBy ) { }
// ...
2021-06-27 21:25:29 +00:00
2021-06-27 21:33:58 +00:00
EProcessNext type ;
AuList < AuSPtr < IWorkItem > > waitFor ;
AuUInt32 reschedMs ;
2021-06-30 12:00:32 +00:00
AuUInt64 reschedNs ;
2021-06-27 21:33:58 +00:00
} ;
2021-06-27 21:25:29 +00:00
2021-06-27 21:33:58 +00:00
virtual void DispatchFrame ( ProcessInfo & info ) = 0 ;
2021-10-18 12:53:47 +00:00
/// A really terrible name for the overloadable method that serves as the critical failure callback
/// You have a 'shutdown'/free function you can overload, it's called the dtor
/// Don't moan about the shitty naming of this, im not refactoring it
2021-06-27 21:33:58 +00:00
virtual void Shutdown ( ) = 0 ;
2021-09-29 10:47:54 +00:00
virtual void * GetPrivateData ( ) { return nullptr ; }
2021-06-27 21:33:58 +00:00
} ;
2021-07-05 13:35:13 +00:00
template < class Info_t = AVoid , class Result_t = AVoid >
2021-06-27 21:25:29 +00:00
struct FJob
{
std : : function < void ( const Info_t & , const Result_t & ) > onSuccess = 0 ;
2021-10-18 12:53:47 +00:00
std : : function < void ( const Info_t & ) > onFailure = 0 ;
2021-06-27 21:25:29 +00:00
} ;
2021-09-29 14:31:40 +00:00
2021-09-29 12:36:25 +00:00
template < class Info_t = AVoid , class Result_t = AVoid >
2021-09-29 14:31:40 +00:00
static inline FJob < Info_t , Result_t > JobFromConsumer ( const AuConsumer < const Info_t & , const Result_t & > & onSuccess )
2021-09-29 12:36:25 +00:00
{
FJob < Info_t , Result_t > ret ;
ret . onSuccess = [ = ] ( const Info_t & in , const Result_t & a )
{
2021-09-29 14:31:40 +00:00
onSuccess ( in , a ) ;
2021-09-29 12:36:25 +00:00
} ;
return ret ;
}
template < class Info_t = AVoid , class Result_t = AVoid >
2021-09-29 14:31:40 +00:00
static inline FJob < Info_t , Result_t > JobFromConsumer ( const AuConsumer < const Info_t & , const Result_t & > & onSuccess , const AuConsumer < const Info_t & , bool /*neverDispatched*/ > & onFailure )
2021-09-29 12:36:25 +00:00
{
FJob < Info_t , Result_t > ret ;
ret . onSuccess = [ = ] ( const Info_t & in , const Result_t & a )
{
2021-09-29 14:31:40 +00:00
onSuccess ( in , a ) ;
2021-09-29 12:36:25 +00:00
} ;
2021-10-18 12:53:47 +00:00
ret . onFailure = [ = ] ( const Info_t & a )
2021-09-29 12:36:25 +00:00
{
2021-10-18 12:53:47 +00:00
onFailure ( a , true ) ;
2021-09-29 12:36:25 +00:00
} ;
return ret ;
}
template < class Info_t = AVoid , class Result_t = AVoid >
2021-09-29 14:31:40 +00:00
static inline FJob < Info_t , Result_t > JobFromConsumer ( const AuConsumer < const Info_t & , const Result_t & > & onSuccess , const AuConsumer < const Info_t & > & onFailure )
2021-09-29 12:36:25 +00:00
{
FJob < Info_t , Result_t > ret ;
ret . onSuccess = [ = ] ( const Info_t & in , const Result_t & a )
{
2021-09-29 14:31:40 +00:00
onSuccess ( in , a ) ;
2021-09-29 12:36:25 +00:00
} ;
2021-10-18 12:53:47 +00:00
ret . onFailure = [ = ] ( const Info_t & a )
2021-09-29 12:36:25 +00:00
{
onFailure ( a ) ;
} ;
return ret ;
}
2021-09-29 14:31:40 +00:00
2021-09-29 12:36:25 +00:00
using FVoidJob = FJob < AVoid , AVoid > ;
2021-07-05 13:35:13 +00:00
template < class Info_t = AVoid , class Result_t = AVoid >
2021-06-27 21:25:29 +00:00
struct CJob
{
2021-10-18 12:53:47 +00:00
void ( * onSuccess ) ( const Info_t & , const Result_t & ) ;
void ( * onFailure ) ( const Info_t & ) ;
2021-06-27 21:25:29 +00:00
} ;
2021-06-27 21:33:58 +00:00
2021-07-05 13:35:13 +00:00
template < class Info_t = AVoid , class Result_t = AVoid >
2021-06-27 21:25:29 +00:00
struct FTask
{
2021-10-18 12:53:47 +00:00
std : : function < Result_t ( const Info_t & ) > onFrame = 0 ;
2021-06-27 21:25:29 +00:00
} ;
2021-09-29 10:47:54 +00:00
2021-09-29 08:02:27 +00:00
using FVoidTask = FTask < AVoid , AVoid > ;
2021-09-29 12:36:25 +00:00
2021-10-18 12:53:47 +00:00
template < class In_t = Async : : AVoid , class Out_t = Async : : AVoid , typename Functional_t = AuConsumer < const In_t & > >
static inline FTask < In_t , Out_t > TaskFromConsumerRefT ( const Functional_t & func )
2021-09-29 12:36:25 +00:00
{
FTask < In_t , Out_t > ret ;
2021-10-18 12:53:47 +00:00
ret . onFrame = [ = ] ( const In_t & a ) - > Out_t
2021-09-29 12:36:25 +00:00
{
2021-10-18 12:53:47 +00:00
if constexpr ( std : : is_same_v < Functional_t , AuConsumer < const In_t & > > )
{
func ( a ) ;
return Out_t { } ;
}
else if constexpr ( std : : is_same_v < Functional_t , AuConsumer < const In_t * > > )
{
func ( & a ) ;
return Out_t { } ;
}
else if constexpr ( std : : is_same_v < Functional_t , AuVoidFunc > )
{
func ( ) ;
return Out_t { } ;
}
else if constexpr ( std : : is_same_v < Functional_t , AuSupplierConsumer < Out_t , const In_t & > > )
{
return func ( a ) ;
}
else if constexpr ( std : : is_same_v < Functional_t , AuConsumer < const In_t & > > )
{
func ( a ) ;
return Out_t { } ;
}
return Out_t { } ;
2021-09-29 12:36:25 +00:00
} ;
return ret ;
}
2021-07-05 13:35:13 +00:00
template < class Info_t = AVoid , class Result_t = AVoid >
2021-06-27 21:25:29 +00:00
struct CTask
{
2021-10-18 12:53:47 +00:00
Result_t ( * onFrame ) ( const Info_t & ) ;
2021-06-27 21:25:29 +00:00
} ;
2021-06-27 21:33:58 +00:00
2021-06-27 21:25:29 +00:00
class IWorkItem
{
public :
2021-07-07 20:32:59 +00:00
virtual AuSPtr < IWorkItem > WaitFor ( const AuSPtr < IWorkItem > & workItem ) = 0 ;
virtual AuSPtr < IWorkItem > WaitFor ( const AuList < AuSPtr < IWorkItem > > & workItem ) = 0 ;
2021-09-30 09:19:04 +00:00
// ms = time relative to the current time
2021-07-07 20:32:59 +00:00
virtual AuSPtr < IWorkItem > SetSchedTime ( AuUInt32 ms ) = 0 ;
2021-09-30 09:19:04 +00:00
// ns = time relative to the current time
2021-07-07 20:32:59 +00:00
virtual AuSPtr < IWorkItem > SetSchedTimeNs ( AuUInt64 ns ) = 0 ;
2021-09-30 09:19:04 +00:00
// ms = time relative to the time at which the work item would otherwise dispatch
2021-07-15 16:16:23 +00:00
virtual AuSPtr < IWorkItem > AddDelayTime ( AuUInt32 ms ) = 0 ;
2021-09-30 09:19:04 +00:00
// ns = time relative to the time at which the work item would otherwise dispatch
2021-07-15 16:16:23 +00:00
virtual AuSPtr < IWorkItem > AddDelayTimeNs ( AuUInt64 ns ) = 0 ;
2021-06-27 21:25:29 +00:00
2021-07-12 14:37:05 +00:00
virtual AuSPtr < IWorkItem > Then ( const AuSPtr < IWorkItem > & next ) = 0 ;
2021-07-07 20:32:59 +00:00
virtual AuSPtr < IWorkItem > Dispatch ( ) = 0 ;
2021-06-27 21:25:29 +00:00
2021-07-07 20:32:59 +00:00
virtual bool BlockUntilComplete ( ) = 0 ;
virtual bool HasFinished ( ) = 0 ;
virtual bool HasFailed ( ) = 0 ;
2021-09-29 08:02:27 +00:00
virtual void Cancel ( ) = 0 ;
2021-09-29 10:47:54 +00:00
virtual void * GetPrivateData ( ) = 0 ;
virtual AuOptional < void * > ToWorkResultT ( ) = 0 ;
2021-06-27 21:25:29 +00:00
} ;
2021-09-30 09:19:04 +00:00
AUKN_SYM AuSPtr < IWorkItem > NewWorkItem ( const WorkerId_t & worker , const AuSPtr < IWorkItemHandler > & task , bool supportsBlocking = false ) ;
2021-10-06 13:48:28 +00:00
AUKN_SYM AuSPtr < IWorkItem > NewFence ( ) ;
2021-06-27 21:25:29 +00:00
2021-10-02 14:00:52 +00:00
class IAsyncApp
{
public :
// Main thread logic
virtual void Start ( ) = 0 ;
virtual void Main ( ) = 0 ;
virtual void Shutdown ( ) = 0 ;
virtual bool Exiting ( ) = 0 ;
virtual void SetConsoleCommandDispatcher ( WorkerId_t id ) = 0 ;
// Spawning
2021-10-15 23:01:49 +00:00
virtual bool Spawn ( WorkerId_t workerId ) = 0 ;
// Event runner threads release upon encountering a zero work condition allowing for a clean exit of event driven apps without the headache of carefully chaining together exit callbacks
// Applications that aren't designed around an event driven model should set callerOwns to true to keep the around during global work exhaustion
virtual void SetWorkerIdIsThreadRunner ( WorkerId_t , bool runner ) = 0 ;
2021-10-02 14:00:52 +00:00
virtual Threading : : Threads : : ThreadShared_t ResolveHandle ( WorkerId_t ) = 0 ;
virtual AuBST < ThreadGroup_t , AuList < ThreadId_t > > GetThreads ( ) = 0 ;
virtual WorkerId_t GetCurrentThread ( ) = 0 ;
// Synchronization
// Note: syncing to yourself will nullify requireSignal to prevent deadlock
virtual bool Sync ( WorkerId_t group , AuUInt32 timeoutMs = 0 , bool requireSignal = false ) = 0 ;
virtual void Signal ( WorkerId_t group ) = 0 ;
virtual void SyncAllSafe ( ) = 0 ;
// Features
virtual void AddFeature ( WorkerId_t id , AuSPtr < Threading : : Threads : : IThreadFeature > feature , bool async = false ) = 0 ;
// Debug
virtual void AssertInThreadGroup ( ThreadGroup_t thread ) = 0 ;
virtual void AssertWorker ( WorkerId_t id ) = 0 ;
virtual bool Poll ( bool block ) = 0 ;
2021-10-03 12:43:58 +00:00
virtual bool ScheduleLoopSource ( const AuSPtr < Loop : : ILoopSource > & loopSource , WorkerId_t workerId , AuUInt32 timeout , const AuConsumer < AuSPtr < Loop : : ILoopSource > , bool > & callback ) = 0 ;
2021-10-02 14:00:52 +00:00
} ;
2021-09-29 14:31:40 +00:00
# pragma region EASE_OF_READING
2021-06-27 21:25:29 +00:00
struct BasicWorkStdFunc : IWorkItemHandler
{
std : : function < void ( ) > callback ;
2021-10-18 12:53:47 +00:00
std : : function < void ( ) > shutdown ; // error
2021-06-27 21:33:58 +00:00
2021-10-18 12:53:47 +00:00
BasicWorkStdFunc ( std : : function < void ( ) > & & callback , std : : function < void ( ) > & & shutdown ) : callback ( std : : move ( callback ) ) , shutdown ( std : : move ( shutdown ) )
2021-06-27 21:25:29 +00:00
{ }
BasicWorkStdFunc ( std : : function < void ( ) > & & callback ) : callback ( std : : move ( callback ) )
{ }
BasicWorkStdFunc ( const std : : function < void ( ) > & callback ) : callback ( callback )
{ }
2021-06-30 09:35:53 +00:00
BasicWorkStdFunc ( const std : : function < void ( ) > & callback , const std : : function < void ( ) > & shutdown ) : callback ( callback ) , shutdown ( shutdown )
2021-06-27 21:25:29 +00:00
{ }
private :
2021-09-06 10:58:08 +00:00
# if !defined(_CPPSHARP)
2021-06-27 21:33:58 +00:00
void DispatchFrame ( ProcessInfo & info ) override
{
2021-06-27 21:25:29 +00:00
try
{
2021-06-27 21:33:58 +00:00
callback ( ) ;
2021-06-27 21:25:29 +00:00
}
catch ( . . . )
{
Debug : : PrintError ( ) ;
}
2021-06-27 21:33:58 +00:00
}
void Shutdown ( ) override
2021-06-27 21:25:29 +00:00
{
try
{
2021-06-30 09:35:53 +00:00
if ( shutdown )
{
shutdown ( ) ;
}
2021-06-27 21:25:29 +00:00
}
catch ( . . . )
{
Debug : : PrintError ( ) ;
}
}
2021-09-06 10:58:08 +00:00
# endif
2021-06-27 21:25:29 +00:00
} ;
2021-09-06 10:58:08 +00:00
2021-09-29 10:47:54 +00:00
2021-09-06 10:58:08 +00:00
# if !defined(_CPPSHARP)
2021-09-29 10:47:54 +00:00
/// @hideinitializer
struct BasicWorkCtx : WorkPriv
{
BasicWorkCtx ( )
{
magic = AuConvertMagicTag32 ( " BWOT " ) ;
opt = nullptr ;
}
void * opt ;
} ;
/// @hideinitializer
2021-10-06 13:48:28 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
2021-06-27 21:25:29 +00:00
struct BasicWorkCallback : IWorkItemHandler , std : : enable_shared_from_this < IWorkItemHandler >
{
BasicWorkCallback ( )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-09-29 12:36:25 +00:00
2021-09-29 08:02:27 +00:00
BasicWorkCallback ( Task_t & & task ) : task ( std : : move ( task ) )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-09-29 12:36:25 +00:00
BasicWorkCallback ( Task_t & & task , Job_t & & callback ) : task ( std : : move ( task ) ) , callback ( std : : move ( callback ) )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
BasicWorkCallback ( const Task_t & task ) : task ( task )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
BasicWorkCallback ( const Task_t & task , const Job_t & callback ) : task ( task ) , callback ( callback )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
BasicWorkCallback ( const Task_t & task , const Job_t & callback , const Info_t & info ) : task ( task ) , callback ( callback ) , input ( info )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-10-18 12:53:47 +00:00
BasicWorkCallback ( Task_t & & task , const Job_t & callback , const Info_t & info ) : task ( std : : move ( task ) ) , callback ( callback ) , input ( info )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
BasicWorkCallback ( Task_t & & task , Job_t & & callback , const Info_t & info ) : task ( std : : move ( task ) ) , callback ( std : : move ( callback ) ) , input ( info )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-09-29 12:36:25 +00:00
BasicWorkCallback ( Task_t & & task , Job_t & & callback , Info_t & & info ) : task ( std : : move ( task ) ) , callback ( std : : move ( callback ) ) , input ( std : : move ( info ) )
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-10-18 12:53:47 +00:00
BasicWorkCallback ( const Task_t & task , const Job_t & callback , Info_t & & info ) : task ( task ) , callback ( callback ) , input ( info )
2021-09-29 12:36:25 +00:00
{
caller = GetAsyncApp ( ) - > GetCurrentThread ( ) ;
}
2021-09-29 08:02:27 +00:00
2021-09-29 10:47:54 +00:00
Info_t input ;
2021-06-27 21:25:29 +00:00
Task_t task ;
Job_t callback ;
2021-09-06 10:58:08 +00:00
BasicWorkCallback < Info_t , Result_t , Task_t , Job_t > & SetTask ( const Task_t & task )
{
this - > task = task ;
return * this ;
}
BasicWorkCallback < Info_t , Result_t , Task_t , Job_t > & SetTask ( const Job_t & callback )
{
this - > callback = callback ;
return * this ;
}
2021-09-29 10:47:54 +00:00
2021-06-27 21:33:58 +00:00
private :
2021-06-27 21:25:29 +00:00
2021-09-06 10:58:08 +00:00
static constexpr bool IsCallbackPtr = std : : is_pointer_v < Job_t > | | AuIsBaseOfTemplate < std : : shared_ptr , Job_t > : : value ;
static constexpr bool IsTaskPtr = std : : is_pointer_v < Task_t > | | AuIsBaseOfTemplate < std : : shared_ptr , Task_t > : : value ;
2021-06-27 21:25:29 +00:00
WorkerId_t caller ;
2021-09-29 10:47:54 +00:00
BasicWorkCtx secretContext_ ;
2021-10-18 12:53:47 +00:00
Result_t resultValue_ ;
2021-09-29 10:47:54 +00:00
virtual void * GetPrivateData ( ) override { return & secretContext_ ; }
2021-06-27 21:25:29 +00:00
2021-06-27 21:33:58 +00:00
void DispatchFrame ( ProcessInfo & info ) override
{
2021-09-06 10:58:08 +00:00
try
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
if constexpr ( IsTaskPtr )
{
2021-09-29 10:47:54 +00:00
resultValue_ = task - > onFrame ( input ) ;
2021-09-06 10:58:08 +00:00
}
else
{
2021-09-29 10:47:54 +00:00
resultValue_ = task . onFrame ( input ) ;
2021-09-06 10:58:08 +00:00
}
2021-06-27 21:25:29 +00:00
}
2021-09-06 10:58:08 +00:00
catch ( . . . )
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
Debug : : PrintError ( ) ;
Shutdown ( ) ;
2021-10-18 12:55:58 +00:00
return ;
2021-06-27 21:25:29 +00:00
}
2021-06-30 09:28:52 +00:00
auto pin = std : : static_pointer_cast < std : : remove_pointer_t < decltype ( this ) > > ( this - > shared_from_this ( ) ) ;
2021-06-27 21:25:29 +00:00
2021-09-29 12:36:25 +00:00
std : : function < void ( ) > func = [ pin ] ( )
2021-06-27 21:25:29 +00:00
{
try
{
2021-10-18 12:53:47 +00:00
pin - > secretContext_ . opt = & pin - > resultValue_ ;
if constexpr ( IsCallbackPtr )
2021-06-27 21:25:29 +00:00
{
2021-10-18 12:53:47 +00:00
pin - > callback - > onSuccess ( pin - > input , pin - > resultValue_ ) ;
2021-06-27 21:25:29 +00:00
}
else
{
2021-10-18 12:53:47 +00:00
if ( pin - > callback . onSuccess )
{
pin - > callback . onSuccess ( pin - > input , pin - > resultValue_ ) ;
}
2021-06-27 21:25:29 +00:00
}
}
catch ( . . . )
{
Debug : : PrintError ( ) ;
}
} ;
try
{
if ( caller = = GetAsyncApp ( ) - > GetCurrentThread ( ) )
{
func ( ) ;
}
else
{
2021-06-30 09:28:52 +00:00
std : : function < void ( ) > err = [ pin ] ( )
2021-06-27 21:25:29 +00:00
{
2021-10-18 12:53:47 +00:00
pin - > CallOnFailure ( ) ;
2021-06-27 21:25:29 +00:00
} ;
// TODO: this is somewhat evil. double alloc when we could reuse this
2021-10-15 23:01:49 +00:00
if ( ! NewWorkItem ( caller , AuMakeShared < BasicWorkStdFunc > ( func , err ) ) - > Dispatch ( ) )
{
2021-10-18 12:53:47 +00:00
pin - > CallOnFailure ( ) ;
2021-10-15 23:01:49 +00:00
}
2021-06-27 21:25:29 +00:00
}
}
catch ( . . . )
{
Debug : : PrintError ( ) ;
Shutdown ( ) ;
}
2021-06-27 21:33:58 +00:00
}
void Shutdown ( ) override
{
2021-06-27 21:25:29 +00:00
try
{
2021-10-18 12:53:47 +00:00
CallOnFailure ( ) ;
2021-06-27 21:25:29 +00:00
}
catch ( . . . )
{
Debug : : PrintError ( ) ;
}
2021-06-27 21:33:58 +00:00
}
2021-06-30 09:28:52 +00:00
2021-10-18 12:53:47 +00:00
void CallOnFailure ( )
2021-06-30 09:28:52 +00:00
{
if constexpr ( IsCallbackPtr )
{
2021-09-06 10:58:08 +00:00
if constexpr ( AuIsBaseOfTemplate < std : : function , decltype ( callback - > onFailure ) > : : value )
2021-06-30 09:28:52 +00:00
{
if ( ! callback - > onFailure )
{
return ;
}
}
2021-10-18 12:53:47 +00:00
callback - > onFailure ( input ) ;
2021-06-30 09:28:52 +00:00
}
else
{
2021-09-06 10:58:08 +00:00
if constexpr ( AuIsBaseOfTemplate < std : : function , decltype ( callback . onFailure ) > : : value )
2021-06-30 09:28:52 +00:00
{
if ( ! callback . onFailure )
{
return ;
}
}
2021-10-18 12:53:47 +00:00
callback . onFailure ( input ) ;
2021-06-30 09:28:52 +00:00
}
}
2021-06-27 21:25:29 +00:00
} ;
2021-09-29 10:47:54 +00:00
/// @hideinitializer
2021-06-27 21:33:58 +00:00
template < typename Frame_t = std : : function < void ( ) > , typename Cleanup_t = std : : function < void ( ) > >
2021-09-29 10:47:54 +00:00
struct WorkItemCallable : IWorkItemHandler
2021-06-27 21:25:29 +00:00
{
Frame_t frame ;
Cleanup_t cleanup ;
private :
void DispatchFrame ( ProcessInfo & info ) override
{
2021-10-15 23:01:49 +00:00
if constexpr ( AuIsBaseOfTemplate < Frame_t , decltype ( frame ) > : : value )
{
if ( ! frame )
{
info . type = IWorkItemHandler : : EProcessNext : : eFinished ;
return ;
}
}
2021-06-27 21:25:29 +00:00
frame ( ) ;
info . type = IWorkItemHandler : : EProcessNext : : eFinished ;
}
void Shutdown ( ) override
{
2021-10-15 23:01:49 +00:00
if constexpr ( AuIsBaseOfTemplate < Cleanup_t , decltype ( cleanup ) > : : value )
{
if ( ! cleanup )
{
return ;
}
}
2021-06-27 21:25:29 +00:00
cleanup ( ) ;
}
} ;
2021-07-05 13:35:13 +00:00
2021-10-02 16:07:33 +00:00
# define ASYNC_ERROR(exp) { if constexpr (std::is_same_v<T, bool>) { SysPushErrorGen(exp); return {}; } else { throw std::string(exp); } }
# define ASYNC_FINISH { if constexpr (std::is_same_v<T, bool>) { return true; } }
2021-09-29 08:02:27 +00:00
template < typename T = void , typename . . . Args , AU_TEMPLATE_ENABLE_WHEN ( std : : is_same_v < T , bool > | | std : : is_void < T > : : value ) >
2021-09-29 10:47:54 +00:00
static std : : function < T ( Args & & . . . ) > TranslateAsyncFunctionToDispatcherWithThread ( WorkerId_t id , std : : function < void ( Args . . . ) > func )
2021-06-27 21:25:29 +00:00
{
2021-10-15 23:01:49 +00:00
if ( ! func ) return { } ;
2021-09-29 10:47:54 +00:00
return [ = ] ( Args & & . . . in ) - > T
2021-07-05 13:35:13 +00:00
{
2021-09-06 10:58:08 +00:00
auto work = AuMakeShared < BasicWorkStdFunc > ( [ = ] ( ) - > void {
2021-07-05 13:35:13 +00:00
func ( in . . . ) ;
} ) ;
2021-09-29 08:02:27 +00:00
if ( ! work ) ASYNC_ERROR ( " can't dispatch async call; out of memory " ) ;
auto workItem = NewWorkItem ( id , work ) ;
if ( ! workItem ) ASYNC_ERROR ( " can't dispatch async call; out of memory " ) ;
2021-07-05 13:35:13 +00:00
workItem - > Dispatch ( ) ;
2021-09-29 08:02:27 +00:00
ASYNC_FINISH ;
2021-07-05 13:35:13 +00:00
} ;
}
2021-09-29 08:02:27 +00:00
template < typename T = void , typename . . . Args , AU_TEMPLATE_ENABLE_WHEN ( std : : is_same_v < T , bool > | | std : : is_void < T > : : value ) >
2021-09-29 10:47:54 +00:00
static std : : function < T ( Args & & . . . ) > TranslateAsyncFunctionToDispatcher ( std : : function < void ( Args . . . ) > func )
2021-07-05 13:35:13 +00:00
{
2021-09-29 10:47:54 +00:00
return TranslateAsyncFunctionToDispatcherWithThread ( GetAsyncApp ( ) - > GetCurrentThread ( ) , func ) ;
2021-09-29 08:02:27 +00:00
}
template < typename B = void , typename T , typename . . . Args , AU_TEMPLATE_ENABLE_WHEN ( std : : is_same_v < T , bool > | | std : : is_void < T > : : value ) >
2021-10-18 12:53:47 +00:00
static std : : function < T ( std : : function < void ( const B & ) > , Args . . . ) > TranslateAsyncReturnableFunctionToDispatcherWithThread ( WorkerId_t id , std : : function < B ( Args . . . ) > func )
2021-09-29 08:02:27 +00:00
{
return [ = ] ( std : : function < T ( const B & ) > callback , Args . . . in ) - > T
2021-07-05 13:35:13 +00:00
{
2021-09-06 10:58:08 +00:00
auto work = AuMakeShared < BasicWorkCallback < AVoid , B > > ( ) ;
2021-09-29 08:02:27 +00:00
if ( ! work ) ASYNC_ERROR ( " can't dispatch async call; out of memory " ) ;
2021-10-18 12:53:47 +00:00
work . task . onProcess = [ = ] ( const AVoid & ) - > B
2021-07-05 13:35:13 +00:00
{
2021-10-15 23:01:49 +00:00
if ( ! func ) return B { } ;
2021-07-05 13:35:13 +00:00
return func ( in . . . ) ;
} ;
work . callback . onSuccess = [ = ] ( const AVoid & , const B & ret )
{
callback ( ret ) ;
} ;
2021-09-29 08:02:27 +00:00
auto workItem = NewWorkItem ( id , work ) ;
if ( ! workItem ) ASYNC_ERROR ( " can't dispatch async call; out of memory " ) ;
2021-07-05 13:35:13 +00:00
workItem - > Dispatch ( ) ;
2021-09-29 08:02:27 +00:00
ASYNC_FINISH ;
2021-07-05 13:35:13 +00:00
} ;
2021-06-27 21:25:29 +00:00
}
2021-09-29 08:02:27 +00:00
2021-10-18 12:53:47 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
static AuSPtr < Async : : IWorkItem > NewBasicWorkCallback ( const WorkerId_t & worker , const Task_t & task , const Job_t & job , bool enableWait = false )
2021-09-29 08:02:27 +00:00
{
2021-10-18 12:53:47 +00:00
return Async : : NewWorkItem ( worker , AuMakeShared < Async : : BasicWorkCallback < Info_t , Result_t , Task_t > > ( std : : move ( task ) , job ) , enableWait ) ;
2021-09-29 08:02:27 +00:00
}
2021-10-18 12:53:47 +00:00
2021-09-29 12:36:25 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
2021-09-30 09:19:04 +00:00
static AuSPtr < Async : : IWorkItem > DispatchBasicWorkCallback ( const WorkerId_t & worker , const Task_t & task , const Job_t & job , bool enableWait = false )
2021-09-29 12:36:25 +00:00
{
2021-10-18 12:53:47 +00:00
return NewBasicWorkCallback < Info_t , Result_t , Task_t , Job_t > ( worker , task , job , enableWait ) - > Dispatch ( ) ;
}
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
static AuSPtr < Async : : IWorkItem > NewBasicWorkCallback ( const WorkerId_t & worker , Task_t & & task , const Job_t & job , bool enableWait = false )
{
return Async : : NewWorkItem ( worker , AuMakeShared < Async : : BasicWorkCallback < Info_t , Result_t , Task_t > > ( std : : move ( task ) , job ) , enableWait ) ;
2021-09-29 12:36:25 +00:00
}
2021-10-18 12:53:47 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
static AuSPtr < Async : : IWorkItem > DispatchBasicWorkCallback ( const WorkerId_t & worker , Task_t & & task , const Job_t & job , bool enableWait = false )
{
return NewBasicWorkCallback < Info_t , Result_t , Task_t , Job_t > ( worker , std : : move ( task ) , job , enableWait ) - > Dispatch ( ) ;
}
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
static AuSPtr < Async : : IWorkItem > NewBasicWorkCallback ( const WorkerId_t & worker , Task_t & & task , Job_t & & job , bool enableWait = false )
{
return Async : : NewWorkItem ( worker , AuMakeShared < Async : : BasicWorkCallback < Info_t , Result_t , Task_t > > ( std : : move ( task ) , std : : move ( job ) ) , enableWait ) ;
}
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
static AuSPtr < Async : : IWorkItem > NBasicWorkCallback ( const WorkerId_t & worker , Task_t & & task , Job_t & & job , bool enableWait = false )
{
return NewBasicWorkCallback < Info_t , Result_t , Task_t , Job_t > ( worker , std : : move ( task ) , std : : move ( job ) , enableWait ) - > Dispatch ( ) ;
}
2021-09-29 12:36:25 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > >
2021-09-30 09:19:04 +00:00
static AuSPtr < Async : : IWorkItem > DispatchBasicWorkCallback ( const WorkerId_t & worker , const Task_t & task , const Job_t & job , const Info_t & inputParameters , bool enableWait = false )
2021-09-29 12:36:25 +00:00
{
2021-10-15 23:01:49 +00:00
// TOOD: use faster object if job parguments are invalid
// It would be nice if we didn't have to drag the job callback pair around with us
2021-10-18 12:53:47 +00:00
return Async : : NewWorkItem ( worker , AuMakeShared < Async : : BasicWorkCallback < Info_t , Result_t , Task_t > > ( task , job , inputParameters ) , enableWait ) - > Dispatch ( ) ;
2021-09-29 12:36:25 +00:00
}
2021-10-18 12:53:47 +00:00
template < typename Info_t = AVoid , typename Result_t = AVoid , typename Task_t = FTask < Info_t , Result_t > , typename Job_t = FJob < Info_t , Result_t > , typename ClazzImpl >
AuSPtr < Aurora : : Async : : IWorkItem > DispatchFunctional ( const WorkerId_t & worker , ClazzImpl task , const Job_t & job , const Info_t & inputParameters , bool enableWait = false )
{
return Async : : DispatchBasicWorkCallback < Info_t , Result_t , Task_t , Job_t > ( worker , Async : : TaskFromConsumerRefT < Info_t , Result_t > ( task ) , job , inputParameters , enableWait ) ;
}
2021-10-02 14:00:52 +00:00
# undef ASYNC_ERROR
# undef ASYNC_FINISH
2021-10-01 16:26:27 +00:00
2021-10-02 14:00:52 +00:00
# endif
# pragma endregion EASE_OF_READING
2021-10-02 16:07:33 +00:00
}