1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/source/Misc/Signal.cpp
Sandu Liviu Catalin da76d87a93 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.
2016-11-13 14:50:04 +02:00

1064 lines
31 KiB
C++

// ------------------------------------------------------------------------------------------------
#include "Misc/Signal.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
Signal::SignalContainer Signal::s_Signals;
Signal::FreeSignals Signal::s_FreeSignals;
// ------------------------------------------------------------------------------------------------
SQInteger Signal::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqSignal");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
void Signal::Terminate()
{
// Terminate named signals
for (const auto & s : s_Signals)
{
// Clear slots
s.second.mPtr->Clear();
// Release the name
s.second.mPtr->m_Name.clear();
// Release whatever is in the user data
s.second.mPtr->m_Data.Release();
}
// Finally clear the container itself
s_Signals.clear();
// Create a copy so we don't invalidate iterators when destructor removes the instances
FreeSignals fsig(s_FreeSignals);
// Terminate anonymous signals
for (const auto & s : fsig)
{
// Clear slots
s->Clear();
// Release whatever is in the user data
s->m_Data.Release();
}
// Finally clear the container itself
s_FreeSignals.clear();
}
// ------------------------------------------------------------------------------------------------
Object Signal::Create()
{
// Remember the current stack size
const StackGuard sg;
// Create the signal instance
DeleteGuard< Signal > dg(new Signal());
// Attempt to create the signal instance
ClassType< Signal >::PushInstance(DefaultVM::Get(), dg.Get());
// This is now managed by the script
dg.Release();
// Return the created signal
return Var< Object >(DefaultVM::Get(), -1).value;
}
// ------------------------------------------------------------------------------------------------
Object Signal::Create(String name)
{
// Validate the signal name
if (name.empty())
{
STHROWF("Empty signal names are not allowed");
}
// Compute the hash of the specified name
const std::size_t hash = std::hash< String >{}(name);
// See if the signal already exists
for (const auto & e : s_Signals)
{
if (e.first == hash)
{
return e.second.mObj; // Found a match so let's return it
}
}
// Remember the current stack size
const StackGuard sg;
// Create the signal instance
DeleteGuard< Signal > dg(new Signal(std::move(name)));
// Grab the signal instance pointer
Signal * ptr = dg.Get();
// Attempt to create the signal instance
ClassType< Signal >::PushInstance(DefaultVM::Get(), ptr);
// This is now managed by the script
dg.Release();
// Grab a reference to the instance created on the stack
s_Signals.emplace_back(hash, SignalReference(ptr, Var< Object >(DefaultVM::Get(), -1).value));
// Return the created signal
return s_Signals.back().second.mObj;
}
// ------------------------------------------------------------------------------------------------
void Signal::Remove(String name)
{
// Validate the signal name
if (name.empty())
{
STHROWF("Empty signal names are not allowed");
}
// Compute the hash of the specified name
const std::size_t hash = std::hash< String >{}(name);
// Iterator to the existing signal, if any
SignalContainer::const_iterator itr = s_Signals.cbegin();
// Search for a signal with this name
for (; itr != s_Signals.cend(); ++itr)
{
if (itr->first == hash)
{
break;
}
}
// Did we find anything?
if (itr != s_Signals.cend())
{
// Clear the name
itr->second.mPtr->m_Name.clear();
// Put it on the free list
s_FreeSignals.push_back(itr->second.mPtr);
// Finally, remove it from the named list
s_Signals.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
Object Signal::Fetch(String name)
{
// Validate the signal name
if (name.empty())
{
STHROWF("Empty signal names are not allowed");
}
// Compute the hash of the specified name
const std::size_t hash = std::hash< String >{}(name);
// Search for a signal with this name
for (const auto & e : s_Signals)
{
if (e.first == hash)
{
return e.second.mObj; // Found a match so let's return it
}
}
// No such signal exists
STHROWF("Unknown signal named (%s)", name.c_str());
// SHOULD NOT REACH THIS POINT!
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)
{
const Int32 top = sq_gettop(vm);
// Was the signal name specified?
if (top <= 1)
{
sq_pushobject(DefaultVM::Get(), Signal::Create());
}
else
{
// Attempt to generate the string value
StackStrF val(vm, 2);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Create the signal instance and push it on the stack
try
{
sq_pushobject(DefaultVM::Get(), Signal::Create(String(val.mPtr, val.mLen)));
}
catch (const Sqrat::Exception & e)
{
return sq_throwerror(vm, e.what());
}
}
// We have an argument on the stack
return 1;
}
// ------------------------------------------------------------------------------------------------
static SQInteger SqRemoveSignal(HSQUIRRELVM vm)
{
const Int32 top = sq_gettop(vm);
// Was the signal name specified?
if (top <= 1)
{
return sq_throwerror(vm, "Missing signal name");
}
// Attempt to generate the string value
StackStrF val(vm, 2);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Create the signal instance and push it on the stack
try
{
Signal::Remove(String(val.mPtr, val.mLen));
}
catch (const Sqrat::Exception & e)
{
return sq_throwerror(vm, e.what());
}
// We have an argument on the stack
return 1;
}
// ------------------------------------------------------------------------------------------------
static SQInteger SqFetchSignal(HSQUIRRELVM vm)
{
const Int32 top = sq_gettop(vm);
// Was the signal name specified?
if (top <= 1)
{
return sq_throwerror(vm, "Missing signal name");
}
// Attempt to generate the string value
StackStrF val(vm, 2);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Create the signal instance and push it on the stack
try
{
sq_pushobject(DefaultVM::Get(), Signal::Fetch(String(val.mPtr, val.mLen)));
}
catch (const Sqrat::Exception & e)
{
return sq_throwerror(vm, e.what());
}
// We have an argument on the stack
return 1;
}
// ================================================================================================
void Register_Signal(HSQUIRRELVM vm)
{
RootTable(vm).Bind(_SC("SqSignalWrapper"),
Class< Signal, NoConstructor< Signal > >(vm, _SC("SqSignalWrapper"))
// Meta-methods
.Func(_SC("_cmp"), &Signal::Cmp)
.SquirrelFunc(_SC("_typename"), &Signal::Typename)
.Func(_SC("_tostring"), &Signal::ToString)
// Core Properties
.Prop(_SC("Data"), &Signal::GetData, &Signal::SetData)
.Prop(_SC("Slots"), &Signal::Count)
// Core Methods
.Func(_SC("Clear"), &Signal::Clear)
.Func(_SC("Connect"), &Signal::Connect)
.Func(_SC("Connected"), &Signal::Connected)
.Func(_SC("Disconnect"), &Signal::Disconnect)
.Func(_SC("EliminateThis"), &Signal::DisconnectThis)
.Func(_SC("EliminateFunc"), &Signal::DisconnectFunc)
.Func(_SC("CountThis"), &Signal::CountThis)
.Func(_SC("CountFunc"), &Signal::CountFunc)
.Func(_SC("Head"), &Signal::Head)
.Func(_SC("Tail"), &Signal::Tail)
// Squirrel Functions
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
.SquirrelFunc(_SC("Broadcast"), &Signal::SqEmit)
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
.SquirrelFunc(_SC("Approve"), &Signal::SqApprove)
.SquirrelFunc(_SC("Request"), &Signal::SqRequest)
);
RootTable(vm)
.SquirrelFunc(_SC("SqSignal"), &SqFetchSignal)
.SquirrelFunc(_SC("SqCreateSignal"), &SqCreateSignal)
.SquirrelFunc(_SC("SqRemoveSignal"), &SqRemoveSignal);
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to terminate the signals.
*/
void TerminateSignals()
{
Signal::Terminate();
}
} // Namespace:: SqMod