mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
Move some of the signal implementation to source file.
Don't combine the Consume and Approve methods. The null value does not count towards returned values anymore.
This commit is contained in:
parent
df12603405
commit
da76d87a93
@ -150,6 +150,780 @@ Object Signal::Fetch(String name)
|
||||
return NullObject();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Signal::Signal()
|
||||
: m_Head(nullptr), m_Data(), m_Name()
|
||||
{
|
||||
s_FreeSignals.push_back(this);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Signal::Signal(const CSStr name)
|
||||
: Signal(String(name ? name : _SC("")))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Signal::Signal(const String & name)
|
||||
: Signal(String(name))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Signal::Signal(String && name)
|
||||
: m_Head(nullptr), m_Data(), m_Name(std::move(name))
|
||||
{
|
||||
if (m_Name.empty())
|
||||
{
|
||||
s_FreeSignals.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Signal::~Signal()
|
||||
{
|
||||
Clear();
|
||||
if (m_Name.empty())
|
||||
{
|
||||
s_FreeSignals.erase(std::remove(s_FreeSignals.begin(), s_FreeSignals.end(), this),
|
||||
s_FreeSignals.end());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::Count() const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count all nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::Clear()
|
||||
{
|
||||
// Don't attempt to clear anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk down the chain and delete all nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
// Reset the head
|
||||
m_Head = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::Connect(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk down the chain and find an already matching node
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
return; // Already connected
|
||||
}
|
||||
}
|
||||
// Connect now
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Signal::Connected(Object & env, Function & func) const
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Walk down the chain and find a matching node
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
return true; // Found it
|
||||
}
|
||||
}
|
||||
// No such slot exists
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::Disconnect(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (*node == slot)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::DisconnectThis(Object & env)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{env, NullFunction()}.mEnvHash;
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (node->mEnvHash == hash)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::DisconnectFunc(Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{NullObject(), func}.mFuncHash;
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (node->mFuncHash == hash)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Uint32 Signal::CountThis(Object & env) const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{env, NullFunction()}.mEnvHash;
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count the matching nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
// Is this our node?
|
||||
if (node->mEnvHash == hash)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Uint32 Signal::CountFunc(Function & func) const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{NullObject(), func}.mFuncHash;
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count the matching nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
// Is this our node?
|
||||
if (node->mFuncHash == hash)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::Head(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the head node
|
||||
Slot * node = m_Head;
|
||||
// Walk down the chain and find a matching node
|
||||
for (; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
break; // Found it
|
||||
}
|
||||
}
|
||||
// Have we found anything?
|
||||
if (node == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head); // Lead everyone
|
||||
}
|
||||
// Is it the head already?
|
||||
else if (m_Head != node)
|
||||
{
|
||||
node->AttachNext(m_Head);
|
||||
// We're the head now
|
||||
m_Head = node;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Signal::Tail(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head->mNext = new Slot(env, func, nullptr);
|
||||
// Link with the head
|
||||
m_Head->mNext->mPrev = m_Head;
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the head node
|
||||
Slot * node = m_Head, * prev = nullptr;
|
||||
// Walk down the chain and find a matching node
|
||||
for (; node != nullptr; prev = node, node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
break; // Found it
|
||||
}
|
||||
}
|
||||
// Have we found anything?
|
||||
if (node == nullptr)
|
||||
{
|
||||
// Create the slot now
|
||||
node = new Slot(env, func, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Walk down the chain until the end
|
||||
while (prev->mNext != nullptr)
|
||||
{
|
||||
prev = prev->mNext;
|
||||
}
|
||||
// Finally, detach the node from it's current position
|
||||
node->Detach();
|
||||
}
|
||||
// Knowing 'prev' points to last element
|
||||
node->AttachPrev(prev);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::SqEmit(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, false, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Specify that we don't return anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::SqQuery(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// Do we have the collector environment?
|
||||
if (top <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing collector environment");
|
||||
}
|
||||
// Do we have the collector function?
|
||||
else if (top <= 2)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing collector callback");
|
||||
}
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance and collector
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// The collector
|
||||
HSQOBJECT cenv, cfunc;
|
||||
// Grab the collector environment
|
||||
SQRESULT res = sq_getstackobj(vm, 2, &cenv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Was there a valid environment?
|
||||
else if (sq_isnull(cenv))
|
||||
{
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Default to the root table
|
||||
sq_pushroottable(vm);
|
||||
// Try to grab the collector environment again
|
||||
SQRESULT res = sq_getstackobj(vm, -1, &cenv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Grab the collector function
|
||||
res = sq_getstackobj(vm, 3, &cfunc);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Some dummy checks to make sure the collector is a callable object
|
||||
else if (!sq_isfunction(cfunc) && !sq_isclosure(cfunc) && !sq_isnativeclosure(cfunc))
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid collector");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 3)
|
||||
{
|
||||
for (SQInteger i = 4; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
res = sq_call(vm, top - 2, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Push the collector onto the stack
|
||||
sq_pushobject(vm, cfunc);
|
||||
sq_pushobject(vm, cenv);
|
||||
// Push the returned value
|
||||
sq_push(vm, -3);
|
||||
// Make the function call and store the result
|
||||
res = sq_call(vm, 2, false, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Specify that we don't return anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::SqConsume(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Default to not consumed
|
||||
SQBool ret = SQFalse;
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Is the returned value not null?
|
||||
else if (sq_gettype(vm, -1) != OT_NULL)
|
||||
{
|
||||
// Obtain the returned value
|
||||
sq_tobool(vm, -1, &ret);
|
||||
// Should we proceed to the next slot or stop here?
|
||||
if (ret == SQTrue)
|
||||
{
|
||||
break; // The slot consumed the signal
|
||||
}
|
||||
}
|
||||
}
|
||||
// Forward the returned value to the invoker
|
||||
sq_pushbool(vm, ret);
|
||||
// Specify that we returned something
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::SqApprove(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Default to approved
|
||||
SQBool ret = SQTrue;
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Is the returned value not null?
|
||||
else if (sq_gettype(vm, -1) != OT_NULL)
|
||||
{
|
||||
// Obtain the returned value
|
||||
sq_tobool(vm, -1, &ret);
|
||||
// Should we proceed to the next slot or stop here?
|
||||
if (ret == SQFalse)
|
||||
{
|
||||
break; // The slot did not approve the signal
|
||||
}
|
||||
}
|
||||
}
|
||||
// Forward the returned value to the invoker
|
||||
sq_pushbool(vm, ret);
|
||||
// Specify that we returned something
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Signal::SqRequest(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Is the returned value not null?
|
||||
else if (sq_gettype(vm, -1) != OT_NULL)
|
||||
{
|
||||
// Push back the returned value
|
||||
sq_push(vm, -1);
|
||||
// Specify that we returned something
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Specify that we returned nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqCreateSignal(HSQUIRRELVM vm)
|
||||
{
|
||||
|
@ -347,41 +347,22 @@ private:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Signal()
|
||||
: m_Head(nullptr), m_Data(), m_Name()
|
||||
{
|
||||
s_FreeSignals.push_back(this);
|
||||
}
|
||||
Signal();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Signal(const CSStr name)
|
||||
: Signal(String(name ? name : _SC("")))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
Signal(const CSStr name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Signal(const String & name)
|
||||
: Signal(String(name))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
Signal(const String & name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Signal(String && name)
|
||||
: m_Head(nullptr), m_Data(), m_Name(std::move(name))
|
||||
{
|
||||
if (m_Name.empty())
|
||||
{
|
||||
s_FreeSignals.push_back(this);
|
||||
}
|
||||
}
|
||||
Signal(String && name);
|
||||
|
||||
public:
|
||||
|
||||
@ -398,15 +379,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Signal()
|
||||
{
|
||||
Clear();
|
||||
if (m_Name.empty())
|
||||
{
|
||||
s_FreeSignals.erase(std::remove(s_FreeSignals.begin(), s_FreeSignals.end(), this),
|
||||
s_FreeSignals.end());
|
||||
}
|
||||
}
|
||||
~Signal();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
@ -469,708 +442,82 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The number of slots connected to the signal.
|
||||
*/
|
||||
SQInteger Count() const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count all nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
SQInteger Count() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all slots connected to the signal.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
// Don't attempt to clear anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk down the chain and delete all nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
// Reset the head
|
||||
m_Head = nullptr;
|
||||
}
|
||||
void Clear();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Connect a function with a specific environment to the signal.
|
||||
*/
|
||||
void Connect(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk down the chain and find an already matching node
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
return; // Already connected
|
||||
}
|
||||
}
|
||||
// Connect now
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
void Connect(Object & env, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether a function with a specific environment is connected to the signal.
|
||||
*/
|
||||
bool Connected(Object & env, Function & func) const
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Walk down the chain and find a matching node
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
return true; // Found it
|
||||
}
|
||||
}
|
||||
// No such slot exists
|
||||
return false;
|
||||
}
|
||||
bool Connected(Object & env, Function & func) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Disconnect a function with a specific environment from the signal.
|
||||
*/
|
||||
void Disconnect(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (*node == slot)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Disconnect(Object & env, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Disconnect all functions with a specific environment from the signal.
|
||||
*/
|
||||
void DisconnectThis(Object & env)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{env, NullFunction()}.mEnvHash;
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (node->mEnvHash == hash)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
void DisconnectThis(Object & env);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Disconnect all matching functions regardless of the environment from the signal.
|
||||
*/
|
||||
void DisconnectFunc(Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{NullObject(), func}.mFuncHash;
|
||||
// Walk down the chain and remove the matching nodes
|
||||
for (Slot * node = m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Is this our node?
|
||||
if (node->mFuncHash == hash)
|
||||
{
|
||||
// Is this the head?
|
||||
if (node == m_Head)
|
||||
{
|
||||
m_Head = next; // Move the head to the next one
|
||||
}
|
||||
// Detach it from the chain
|
||||
node->Detach();
|
||||
// Delete the node instance
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
void DisconnectFunc(Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Count all functions with a specific environment from the signal.
|
||||
*/
|
||||
Uint32 CountThis(Object & env) const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{env, NullFunction()}.mEnvHash;
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count the matching nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
// Is this our node?
|
||||
if (node->mEnvHash == hash)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
Uint32 CountThis(Object & env) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Count all matching functions regardless of the environment from the signal.
|
||||
*/
|
||||
Uint32 CountFunc(Function & func) const
|
||||
{
|
||||
// Don't attempt to count anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const SQHash hash = Slot{NullObject(), func}.mFuncHash;
|
||||
// Final count
|
||||
Uint32 count = 0;
|
||||
// Walk down the chain and count the matching nodes
|
||||
for (Slot * node = m_Head; node != nullptr; node = node->mNext)
|
||||
{
|
||||
// Is this our node?
|
||||
if (node->mFuncHash == hash)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Return the count
|
||||
return count;
|
||||
}
|
||||
Uint32 CountFunc(Function & func) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure that specified slot is positioned ahead of all other slots.
|
||||
*/
|
||||
void Head(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head);
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the head node
|
||||
Slot * node = m_Head;
|
||||
// Walk down the chain and find a matching node
|
||||
for (; node != nullptr; node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
break; // Found it
|
||||
}
|
||||
}
|
||||
// Have we found anything?
|
||||
if (node == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, m_Head); // Lead everyone
|
||||
}
|
||||
// Is it the head already?
|
||||
else if (m_Head != node)
|
||||
{
|
||||
node->AttachNext(m_Head);
|
||||
// We're the head now
|
||||
m_Head = node;
|
||||
}
|
||||
}
|
||||
void Head(Object & env, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure that specified slot is positioned behind of all other slots.
|
||||
*/
|
||||
void Tail(Object & env, Function & func)
|
||||
{
|
||||
// Don't attempt to search anything if there's no head
|
||||
if (m_Head == nullptr)
|
||||
{
|
||||
m_Head = new Slot(env, func, nullptr);
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
const Slot slot{env, func};
|
||||
// Don't attempt to search anything if there's only one element
|
||||
if (m_Head->mNext == nullptr)
|
||||
{
|
||||
// Is it already inserted?
|
||||
if (*m_Head != slot)
|
||||
{
|
||||
m_Head->mNext = new Slot(env, func, nullptr);
|
||||
// Link with the head
|
||||
m_Head->mNext->mPrev = m_Head;
|
||||
}
|
||||
// We're done here
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the head node
|
||||
Slot * node = m_Head, * prev = nullptr;
|
||||
// Walk down the chain and find a matching node
|
||||
for (; node != nullptr; prev = node, node = node->mNext)
|
||||
{
|
||||
if (*node == slot)
|
||||
{
|
||||
break; // Found it
|
||||
}
|
||||
}
|
||||
// Have we found anything?
|
||||
if (node == nullptr)
|
||||
{
|
||||
// Create the slot now
|
||||
node = new Slot(env, func, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Walk down the chain until the end
|
||||
while (prev->mNext != nullptr)
|
||||
{
|
||||
prev = prev->mNext;
|
||||
}
|
||||
// Finally, detach the node from it's current position
|
||||
node->Detach();
|
||||
}
|
||||
// Knowing 'prev' points to last element
|
||||
node->AttachPrev(prev);
|
||||
}
|
||||
void Tail(Object & env, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots.
|
||||
*/
|
||||
static SQInteger SqEmit(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, false, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Specify that we don't return anything
|
||||
return 0;
|
||||
}
|
||||
static SQInteger SqEmit(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and collect returned values.
|
||||
*/
|
||||
static SQInteger SqQuery(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// Do we have the collector environment?
|
||||
if (top <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing collector environment");
|
||||
}
|
||||
// Do we have the collector function?
|
||||
else if (top <= 2)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing collector callback");
|
||||
}
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance and collector
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// The collector
|
||||
HSQOBJECT cenv, cfunc;
|
||||
// Grab the collector environment
|
||||
SQRESULT res = sq_getstackobj(vm, 2, &cenv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Was there a valid environment?
|
||||
else if (sq_isnull(cenv))
|
||||
{
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Default to the root table
|
||||
sq_pushroottable(vm);
|
||||
// Try to grab the collector environment again
|
||||
SQRESULT res = sq_getstackobj(vm, -1, &cenv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Grab the collector function
|
||||
res = sq_getstackobj(vm, 3, &cfunc);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Some dummy checks to make sure the collector is a callable object
|
||||
else if (!sq_isfunction(cfunc) && !sq_isclosure(cfunc) && !sq_isnativeclosure(cfunc))
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid collector");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 3)
|
||||
{
|
||||
for (SQInteger i = 4; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
res = sq_call(vm, top - 2, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Push the collector onto the stack
|
||||
sq_pushobject(vm, cfunc);
|
||||
sq_pushobject(vm, cenv);
|
||||
// Push the returned value
|
||||
sq_push(vm, -3);
|
||||
// Make the function call and store the result
|
||||
res = sq_call(vm, 2, false, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Specify that we don't return anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Actual implementation of the consume method.
|
||||
*/
|
||||
static SQInteger SqConsumeApproveImpl(HSQUIRRELVM vm, const SQBool rval, bool neg)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Return value of each slot
|
||||
SQBool ret = !rval;
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Obtain the returned value
|
||||
sq_tobool(vm, -1, &ret);
|
||||
// Should we proceed to the next slot or stop here?
|
||||
if (ret == rval)
|
||||
{
|
||||
// The slot satisfied our criteria
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Forward the returned value to the invoker
|
||||
sq_pushbool(vm, neg ? !ret : ret);
|
||||
// Specify that we returned something
|
||||
return 1;
|
||||
}
|
||||
|
||||
public:
|
||||
static SQInteger SqQuery(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they consume it.
|
||||
*/
|
||||
static SQInteger SqConsume(HSQUIRRELVM vm)
|
||||
{
|
||||
return SqConsumeApproveImpl(vm, SQTrue, false);
|
||||
}
|
||||
static SQInteger SqConsume(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they approve it.
|
||||
*/
|
||||
static SQInteger SqApprove(HSQUIRRELVM vm)
|
||||
{
|
||||
return SqConsumeApproveImpl(vm, SQFalse, true);
|
||||
}
|
||||
static SQInteger SqApprove(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they return something.
|
||||
*/
|
||||
static SQInteger SqRequest(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// The signal instance
|
||||
Signal * signal = nullptr;
|
||||
// Attempt to extract the signal instance
|
||||
try
|
||||
{
|
||||
signal = Var< Signal * >(vm, 1).value;
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Do we have a valid signal instance?
|
||||
if (!signal)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid signal instance");
|
||||
}
|
||||
// Walk down the chain and trigger slots
|
||||
for (Slot * node = signal->m_Head, * next = nullptr; node != nullptr; node = next)
|
||||
{
|
||||
// Grab the next node upfront
|
||||
next = node->mNext;
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, node->mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (sq_isnull(node->mEnvRef))
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, node->mEnvRef);
|
||||
}
|
||||
// Are there any parameters to forward?
|
||||
if (top > 1)
|
||||
{
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
sq_push(vm, i);
|
||||
}
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, top, true, ErrorHandling::IsEnabled());
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Is the returned value not null?
|
||||
else if (sq_gettype(vm, -1) != OT_NULL)
|
||||
{
|
||||
// Push back the returned value
|
||||
sq_push(vm, -1);
|
||||
// Specify that we returned something
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Specify that we returned nothing
|
||||
return 0;
|
||||
}
|
||||
static SQInteger SqRequest(HSQUIRRELVM vm);
|
||||
|
||||
private:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user