Added support for a native implementation of a Javascript HashList.

When generating iterator for JsObjects avoid checking that were not setting duplicates in the iterator. JsObject does not allow setting duplicates.



git-svn-id: http://yate.null.ro/svn/yate/trunk@6264 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
oana 2017-09-18 12:14:44 +00:00
parent e2060c65fe
commit 6f58478394
5 changed files with 161 additions and 6 deletions

View File

@ -2570,7 +2570,7 @@ bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* c
bool ret = false;
if (obj && (!obj->frozen() || !obj->hasField(stack,name,context))
&& obj->toString() != YSTRING("()")) {
obj->params().clearParam(name);
obj->clearField(name);
ret = true;
}
DDebug(DebugAll,"Deleted '%s' : %s",name.c_str(),String::boolText(ret));

View File

@ -271,7 +271,7 @@ JsObject* JsObject::buildCallContext(Mutex* mtx, JsObject* thisObj)
void JsObject::fillFieldNames(ObjList& names)
{
ScriptContext::fillFieldNames(names,params(),"__");
ScriptContext::fillFieldNames(names,params(),false,"__");
const NamedList* native = nativeParams();
if (native)
ScriptContext::fillFieldNames(names,*native);

View File

@ -184,7 +184,8 @@ bool ScriptContext::copyFields(ObjList& stack, const ScriptContext& original, Ge
void ScriptContext::fillFieldNames(ObjList& names)
{
fillFieldNames(names,params());
bool checkDupl = !(YOBJECT(JsObject,this));
fillFieldNames(names,params(),checkDupl);
const NamedList* native = nativeParams();
if (native)
fillFieldNames(names,*native);
@ -195,7 +196,7 @@ void ScriptContext::fillFieldNames(ObjList& names)
#endif
}
void ScriptContext::fillFieldNames(ObjList& names, const NamedList& list, const char* skip)
void ScriptContext::fillFieldNames(ObjList& names, const NamedList& list, bool checkDupl, const char* skip)
{
ObjList* tail = &names;
for (const ObjList* l = list.paramList()->skipNull(); l; l = l->skipNext()) {
@ -204,12 +205,25 @@ void ScriptContext::fillFieldNames(ObjList& names, const NamedList& list, const
continue;
if (skip && s->name().startsWith(skip))
continue;
if (names.find(s->name()))
if (checkDupl && names.find(s->name()))
continue;
tail = tail->append(new String(s->name()));
}
}
void ScriptContext::fillFieldNames(ObjList& names, const HashList& list)
{
ObjList* tail = &names;
for (unsigned int i = 0; i < list.length(); i++) {
ObjList* o = list.getList(i);
for (o = o ? o->skipNull() : 0;o;o = o->skipNext()) {
GenObject* obj = o->get();
if (obj->toString().null())
continue;
tail = tail->append(new String(obj->toString()));
}
}
}
#define MAKE_NAME(x) { #x, ScriptRun::x }
static const TokenDict s_states[] = {

View File

@ -1469,9 +1469,17 @@ public:
* Fill a list with the unique names of all fields
* @param names List to which key names must be added
* @param list List of parameters whose names to be added
* @param checkDupl True to ignore duplicates from the given list
* @param skip Parameters starting with this prefix will not be added
*/
static void fillFieldNames(ObjList& names, const NamedList& list, const char* skip = 0);
static void fillFieldNames(ObjList& names, const NamedList& list, bool checkDupl = true, const char* skip = 0);
/**
* Fill a list with the unique names from a Hash list
* @param names List to which key names must be added
* @param list Hash list whose names are to be added
*/
static void fillFieldNames(ObjList& names, const HashList& list);
/**
* Try to evaluate a single function in the context
@ -2050,6 +2058,13 @@ public:
*/
virtual ExpOperation* popValue(ObjList& stack, GenObject* context = 0);
/**
* Delete a field of the object
* @param name Name of field to remove
*/
virtual void clearField(const String& name)
{ params().clearParam(name); }
/**
* Retrieve the object frozen status (cannot modify attributes or methods)
* @return True if the object is frozen

View File

@ -255,6 +255,37 @@ private:
bool m_exit;
};
class JsHashList : public JsObject
{
public:
inline JsHashList(Mutex* mtx)
: JsObject("HashList",mtx,true),
m_list()
{
XDebug(DebugAll,"JsHashList::JsHashList() [%p]",this);
}
inline JsHashList(unsigned int size, Mutex* mtx)
: JsObject(mtx,"[object HashList]",false),
m_list(size)
{
XDebug(DebugAll,"JsHashList::JsHashList(%u) [%p]",size,this);
}
virtual ~JsHashList()
{
XDebug(DebugAll,"~JsHashList() [%p]",this);
m_list.clear();
}
virtual void* getObject(const String& name) const;
virtual JsObject* runConstructor(ObjList& stack, const ExpOperation& oper, GenObject* context);
virtual void fillFieldNames(ObjList& names);
virtual bool runField(ObjList& stack, const ExpOperation& oper, GenObject* context);
virtual bool runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context);
virtual void clearField(const String& name)
{ m_list.remove(name); }
private:
HashList m_list;
};
#define MKDEBUG(lvl) params().addParam(new ExpOperation((int64_t)Debug ## lvl,"Debug" # lvl))
#define MKTIME(typ) params().addParam(new ExpOperation((int64_t)SysUsage:: typ ## Time,# typ "Time"))
class JsEngine : public JsObject, public DebugEnabler
@ -322,6 +353,7 @@ public:
params().addParam(new ExpFunction("btoh"));
params().addParam(new ExpFunction("htob"));
addConstructor(params(), "Semaphore", new JsSemaphore(mtx));
addConstructor(params(),"HashList",new JsHashList(mtx));
}
static void initialize(ScriptContext* context, const char* name = 0);
inline void resetWorker()
@ -3663,6 +3695,100 @@ void JsXML::initialize(ScriptContext* context)
addConstructor(params,"XML",new JsXML(mtx));
}
void* JsHashList::getObject(const String& name) const
{
void* obj = (name == YATOM("JsHashList")) ? const_cast<JsHashList*>(this) : JsObject::getObject(name);
if (!obj)
obj = m_list.getObject(name);
return obj;
}
JsObject* JsHashList::runConstructor(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(&__plugin,DebugAll,"JsHashList::runConstructor '%s'(" FMT64 ")",oper.name().c_str(),oper.number());
ObjList args;
unsigned int cnt = 17; // default value for HashList
switch (extractArgs(stack,oper,context,args)) {
case 1:
{
ExpOperation* op = static_cast<ExpOperation*>(args[0]);
if (!op || !op->isInteger() || op->toNumber() <= 0)
return 0;
cnt = op->toNumber();
break;
}
case 0:
break;
default:
return 0;
}
JsHashList* obj = new JsHashList(cnt,mutex());
if (!ref()) {
TelEngine::destruct(obj);
return 0;
}
obj->params().addParam(new ExpWrapper(this,protoName()));
return obj;
}
void JsHashList::fillFieldNames(ObjList& names)
{
JsObject::fillFieldNames(names);
ScriptContext::fillFieldNames(names,m_list);
#ifdef XDEBUG
String tmp;
tmp.append(names,",");
Debug(DebugInfo,"JsHashList::fillFieldNames: %s",tmp.c_str());
#endif
}
bool JsHashList::runField(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsHashList::runField() '%s' in '%s' [%p]",
oper.name().c_str(),toString().c_str(),this);
ExpOperation* obj = static_cast<ExpOperation*>(m_list[oper.name()]);
if (obj) {
ExpWrapper* wrp = YOBJECT(ExpWrapper,obj);
if (wrp)
ExpEvaluator::pushOne(stack,wrp->clone(oper.name()));
else
ExpEvaluator::pushOne(stack,new ExpOperation(*obj,oper.name()));
return true;
}
return JsObject::runField(stack,oper,context);
}
bool JsHashList::runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsHashList::runAssign() '%s'='%s' (%s) in '%s' [%p]",
oper.name().c_str(),oper.c_str(),oper.typeOf(),toString().c_str(),this);
if (frozen()) {
Debug(DebugWarn,"Object '%s' is frozen",toString().c_str());
return false;
}
ObjList* obj = m_list.find(oper.name());
ExpOperation* cln = 0;
ExpFunction* ef = YOBJECT(ExpFunction,&oper);
if (ef)
cln = ef->ExpOperation::clone();
else {
ExpWrapper* w = YOBJECT(ExpWrapper,&oper);
if (w) {
JsFunction* jsf = YOBJECT(JsFunction,w->object());
if (jsf)
jsf->firstName(oper.name());
cln = w->clone(oper.name());
}
else
cln = oper.clone();
}
if (!obj)
m_list.append(cln);
else
obj->set(cln);
return true;
}
bool JsJSON::runNative(ObjList& stack, const ExpOperation& oper, GenObject* context)
{