Allow anonymous functions to be garbage-collected.

Fixes #5921
This commit is contained in:
Gunnar Beutner 2014-04-02 09:04:17 +02:00
parent ebf8ed3019
commit 0683fca535
4 changed files with 35 additions and 38 deletions

View File

@ -233,15 +233,21 @@ Value DynamicObject::InvokeMethod(const String& method,
if (!methods) if (!methods)
BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
String funcName = methods->Get(method); Value funcName = methods->Get(method);
if (funcName.IsEmpty()) if (funcName.IsEmpty())
BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
ScriptFunction::Ptr func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName); ScriptFunction::Ptr func;
if (funcName.IsObjectType<ScriptFunction>()) {
func = funcName;
} else {
func = ScriptFunction::GetByName(funcName);
if (!func) if (!func)
BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + String(funcName) + "' does not exist."));
}
return func->Invoke(arguments); return func->Invoke(arguments);
} }

View File

@ -35,31 +35,27 @@ Value ScriptFunction::Invoke(const std::vector<Value>& arguments)
ScriptFunction::Ptr ScriptFunction::GetByName(const String& name) ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
{ {
return ScriptFunctionRegistry::GetInstance()->GetItem(name); ScriptVariable::Ptr sv = ScriptVariable::GetByName(name);
if (!sv)
return ScriptFunction::Ptr();
return sv->GetData();
} }
void ScriptFunction::Register(const String& name, const ScriptFunction::Callback& function) void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
{ {
ScriptVariable::Ptr sv = ScriptVariable::Set(name, name); ScriptVariable::Ptr sv = ScriptVariable::Set(name, function);
sv->SetConstant(true); sv->SetConstant(true);
ScriptFunction::Ptr func = make_shared<ScriptFunction>(function);
ScriptFunctionRegistry::GetInstance()->Register(name, func);
} }
void ScriptFunction::Unregister(const String& name) void ScriptFunction::Unregister(const String& name)
{ {
ScriptVariable::Unregister(name); ScriptVariable::Unregister(name);
ScriptFunctionRegistry::GetInstance()->Unregister(name);
} }
RegisterFunctionHelper::RegisterFunctionHelper(const String& name, const ScriptFunction::Callback& function) RegisterFunctionHelper::RegisterFunctionHelper(const String& name, const ScriptFunction::Callback& function)
{ {
ScriptFunction::Register(name, function); ScriptFunction::Register(name, make_shared<ScriptFunction>(function));
}
ScriptFunctionRegistry *ScriptFunctionRegistry::GetInstance(void)
{
return Singleton<ScriptFunctionRegistry>::GetInstance();
} }

View File

@ -48,24 +48,13 @@ public:
Value Invoke(const std::vector<Value>& arguments); Value Invoke(const std::vector<Value>& arguments);
static ScriptFunction::Ptr GetByName(const String& name); static ScriptFunction::Ptr GetByName(const String& name);
static void Register(const String& name, const ScriptFunction::Callback& function); static void Register(const String& name, const ScriptFunction::Ptr& function);
static void Unregister(const String& name); static void Unregister(const String& name);
private: private:
Callback m_Callback; Callback m_Callback;
}; };
/**
* A registry for script functions.
*
* @ingroup base
*/
class I2_BASE_API ScriptFunctionRegistry : public Registry<ScriptFunctionRegistry, ScriptFunction::Ptr>
{
public:
static ScriptFunctionRegistry *GetInstance(void);
};
/** /**
* Helper class for registering ScriptFunction implementation classes. * Helper class for registering ScriptFunction implementation classes.
* *

View File

@ -248,8 +248,14 @@ Value AExpression::OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& l
Value AExpression::OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals) Value AExpression::OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
String funcName = expr->EvaluateOperand1(locals); Value funcName = expr->EvaluateOperand1(locals);
ScriptFunction::Ptr func = ScriptFunction::GetByName(funcName);
ScriptFunction::Ptr func;
if (funcName.IsObjectType<ScriptFunction>())
func = funcName;
else
func = ScriptFunction::GetByName(funcName);
if (!func) if (!func)
BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist.")); BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
@ -478,13 +484,13 @@ Value AExpression::OpFunction(const AExpression* expr, const Dictionary::Ptr& lo
AExpression::Ptr aexpr = left->Get(1); AExpression::Ptr aexpr = left->Get(1);
String name = left->Get(0); String name = left->Get(0);
if (name.IsEmpty())
name = "__lambda" + Utility::NewUniqueID();
Array::Ptr funcargs = expr->m_Operand2; Array::Ptr funcargs = expr->m_Operand2;
ScriptFunction::Callback callback = boost::bind(&AExpression::FunctionWrapper, _1, funcargs, aexpr, locals); ScriptFunction::Ptr func = make_shared<ScriptFunction>(boost::bind(&AExpression::FunctionWrapper, _1, funcargs, aexpr, locals));
ScriptFunction::Register(name, callback);
return name; if (!name.IsEmpty())
ScriptFunction::Register(name, func);
return func;
} }
Value AExpression::OpApply(const AExpression* expr, const Dictionary::Ptr& locals) Value AExpression::OpApply(const AExpression* expr, const Dictionary::Ptr& locals)