diff --git a/module/Core/Routine.cpp b/module/Core/Routine.cpp index de524179..9b1a383c 100644 --- a/module/Core/Routine.cpp +++ b/module/Core/Routine.cpp @@ -18,6 +18,7 @@ Routine::Time Routine::s_Last = 0; Routine::Time Routine::s_Prev = 0; Routine::Interval Routine::s_Intervals[SQMOD_MAX_ROUTINES]; Routine::Instance Routine::s_Instances[SQMOD_MAX_ROUTINES]; +SQInteger Routine::s_Current = SQMOD_MAX_ROUTINES; bool Routine::s_Silenced = false; bool Routine::s_Persistent = false; @@ -48,11 +49,14 @@ void Routine::Process() // Have we completed the routine interval? if ((*itr) <= 0) { + s_Current = static_cast< SQInteger >(itr - s_Intervals); // Execute and reset the elapsed time - (*itr) = s_Instances[itr - s_Intervals].Execute(); + (*itr) = s_Instances[s_Current].Execute(); } } } + // Clear currently executed routine + s_Current = SQMOD_MAX_ROUTINES; } // ------------------------------------------------------------------------------------------------ @@ -535,6 +539,7 @@ void Register_Routine(HSQUIRRELVM vm) .Prop(_SC("Env"), &Routine::GetEnv, &Routine::SetEnv) .Prop(_SC("Func"), &Routine::GetFunc, &Routine::SetFunc) .Prop(_SC("Data"), &Routine::GetData, &Routine::SetData) + .Prop(_SC("Result"), &Routine::GetResult, &Routine::SetResult) .Prop(_SC("Interval"), &Routine::GetInterval, &Routine::SetInterval) .Prop(_SC("Iterations"), &Routine::GetIterations, &Routine::SetIterations) .Prop(_SC("Suspended"), &Routine::GetSuspended, &Routine::SetSuspended) @@ -543,6 +548,7 @@ void Register_Routine(HSQUIRRELVM vm) .Prop(_SC("Endure"), &Routine::GetEndure, &Routine::SetEndure) .Prop(_SC("Inactive"), &Routine::GetInactive) .Prop(_SC("Persistent"), &Routine::GetPersistent, &Routine::SetPersistent) + .Prop(_SC("Yields"), &Routine::GetYields, &Routine::SetYields) .Prop(_SC("Terminated"), &Routine::GetTerminated) .Prop(_SC("Arguments"), &Routine::GetArguments) // Member Methods @@ -554,10 +560,12 @@ void Register_Routine(HSQUIRRELVM vm) .Func(_SC("SetQuiet"), &Routine::ApplyQuiet) .Func(_SC("SetEndure"), &Routine::ApplyEndure) .Func(_SC("SetPersistent"), &Routine::ApplyPersistent) + .Func(_SC("SetYields"), &Routine::ApplyYields) .Func(_SC("Terminate"), &Routine::Terminate) .Func(_SC("GetArgument"), &Routine::GetArgument) .Func(_SC("DropEnv"), &Routine::DropEnv) .Func(_SC("Restart"), &Routine::Restart) + .StaticFunc(_SC("Current"), &Routine::GetCurrent) .StaticFunc(_SC("UsedCount"), &Routine::GetUsed) .StaticFunc(_SC("AreSilenced"), &Routine::GetSilenced) .StaticFunc(_SC("SetSilenced"), &Routine::SetSilenced) diff --git a/module/Core/Routine.hpp b/module/Core/Routine.hpp index 50dc9af0..e2300577 100644 --- a/module/Core/Routine.hpp +++ b/module/Core/Routine.hpp @@ -37,6 +37,7 @@ private: LightObj mFunc{}; // A reference to the managed function object. LightObj mInst{}; // Reference to the routine associated with this instance. LightObj mData{}; // A reference to the arbitrary data associated with this instance. + LightObj mResult{}; // A reference to the value returned by the callback on last invocation. String mTag{}; // An arbitrary string which represents the tag. Iterator mIterations{0}; // Number of iterations before self destruct. Interval mInterval{0}; // Interval between routine invocations. @@ -46,6 +47,7 @@ private: bool mEndure{false}; // Whether this instance is allowed to terminate itself on errors. bool mInactive{true}; // Whether this instance has finished all iterations. bool mPersistent{false}; // Whether this instance should not reset when finished. + bool mYields{false}; // Whether this instance may yield a value when callback is invoked. uint8_t mArgc{0}; // The number of arguments that the routine must forward. Argument mArgv[14]{}; // The arguments that the routine must forward. @@ -57,6 +59,7 @@ private: , mFunc() , mInst() , mData() + , mResult() , mTag() , mIterations(0) , mInterval(0) @@ -66,6 +69,7 @@ private: , mEndure(false) , mInactive(true) , mPersistent(GetPersistency()) + , mYields(false) , mArgc(0) , mArgv() { @@ -128,6 +132,7 @@ private: mFunc.Release(); mInst.Release(); mData.Release(); + mResult.Release(); mIterations = 0; mInterval = 0; mInactive = true; @@ -168,9 +173,30 @@ private: // This routine is currently executing mExecuting = true; // Make the function call and store the result - const SQRESULT res = sq_call(vm, mArgc + 1, static_cast< SQBool >(false), static_cast< SQBool >(!mQuiet)); + const SQRESULT res = sq_call(vm, mArgc + 1, static_cast< SQBool >(mYields), static_cast< SQBool >(!mQuiet)); // This routine has finished executing mExecuting = false; + // Should we look for a yielded value? + if (mYields) + { + // Release previous value, if any + if (!sq_isnull(mResult.mObj)) + { + sq_release(vm, &(mResult.mObj)); + } + // Attempt to retrieve the new value if possible + if (SQ_SUCCEEDED(res) && SQ_SUCCEEDED(sq_getstackobj(vm, -1, &(mResult.mObj)))) + { + sq_addref(vm, &(mResult.mObj)); // Don't destroy once popped + } + else + { + sq_resetobject(&(mResult.mObj)); // Discard anything so far + } + // Pop the returned value from the stack + sq_pop(vm, 1); + } + // Pop the callback object from the stack sq_pop(vm, 1); // Validate the result @@ -242,6 +268,7 @@ private: static Time s_Prev; // Previous time point. static Interval s_Intervals[SQMOD_MAX_ROUTINES]; // List of intervals to be processed. static Instance s_Instances[SQMOD_MAX_ROUTINES]; // List of routines to be executed. + static SQInteger s_Current; // Currently executed routine index (SQMOD_MAX_ROUTINES if none). static bool s_Silenced; // Error reporting independent from global setting. static bool s_Persistent; // Whether all routines should be persistent by default. @@ -562,6 +589,22 @@ public: return *this; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the value that the callback has yielded last invocation. + */ + SQMOD_NODISCARD const LightObj & GetResult() const + { + return GetValid().mResult; + } + + /* -------------------------------------------------------------------------------------------- + * Modify the value that the callback has yielded last invocation. + */ + void SetResult(const LightObj & value) + { + GetValid().mResult = value; + } + /* -------------------------------------------------------------------------------------------- * Retrieve the execution interval. */ @@ -728,6 +771,31 @@ public: return *this; } + /* -------------------------------------------------------------------------------------------- + * See whether the routine is yielding a value. + */ + SQMOD_NODISCARD bool GetYields() const + { + return GetValid().mYields; + } + + /* -------------------------------------------------------------------------------------------- + * Set whether the routine should be yielding values. + */ + void SetYields(bool toggle) + { + GetValid().mYields = toggle; + } + + /* -------------------------------------------------------------------------------------------- + * Set whether the routine should be yielding values. + */ + Routine & ApplyYields(bool toggle) + { + SetYields(toggle); + return *this; + } + /* -------------------------------------------------------------------------------------------- * See whether the routine was terminated. */ @@ -791,6 +859,14 @@ public: return *this; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the currently executed routine, if any. + */ + static LightObj & GetCurrent() + { + return (s_Current != SQMOD_MAX_ROUTINES) ? s_Instances[s_Current].mInst : NullLightObj(); + } + /* -------------------------------------------------------------------------------------------- * See if error reporting is enabled for all newly created routines. */