Adds Serialization support for ES6 Maps.

Also includes the patch from Sanderd17 to use Maps and Sets for the
Timer components. Sets can't be serialized yet, but in this case they
don't require serialization.
Refs #2475

This was SVN commit r15770.
This commit is contained in:
Yves 2014-09-20 17:14:53 +00:00
parent 6b2677a3fd
commit f5336c42b8
4 changed files with 63 additions and 16 deletions

View File

@ -7,7 +7,7 @@ Timer.prototype.Init = function()
{
this.id = 0;
this.time = 0;
this.timers = {};
this.timers = new Map();
this.turnLength = 0;
};
@ -33,7 +33,7 @@ Timer.prototype.GetLatestTurnLength = function()
Timer.prototype.SetTimeout = function(ent, iid, funcname, time, data)
{
var id = ++this.id;
this.timers[id] = [ent, iid, funcname, this.time + time, 0, data];
this.timers.set(id, [ent, iid, funcname, this.time + time, 0, data]);
return id;
};
@ -51,7 +51,7 @@ Timer.prototype.SetInterval = function(ent, iid, funcname, time, repeattime, dat
if (typeof repeattime != "number" || !(repeattime > 0))
error("Invalid repeattime to SetInterval of "+funcname);
var id = ++this.id;
this.timers[id] = [ent, iid, funcname, this.time + time, repeattime, data];
this.timers.set(id, [ent, iid, funcname, this.time + time, repeattime, data]);
return id;
};
@ -60,7 +60,7 @@ Timer.prototype.SetInterval = function(ent, iid, funcname, time, repeattime, dat
*/
Timer.prototype.CancelTimer = function(id)
{
delete this.timers[id];
this.timers.delete(id);
};
@ -73,17 +73,15 @@ Timer.prototype.OnUpdate = function(msg)
// Collect the timers that need to run
// (We do this in two stages to avoid deleting from the timer list while
// we're in the middle of iterating through it)
var run = [];
for (var id in this.timers)
var run = new Set();
for (let id of this.timers.keys())
{
if (this.timers[id][3] <= this.time)
run.push(id);
if (this.timers.get(id)[3] <= this.time)
run.add(id);
}
for (var i = 0; i < run.length; ++i)
for (let id of run)
{
var id = run[i];
var t = this.timers[id];
var t = this.timers.get(id);
if (!t)
continue; // an earlier timer might have cancelled this one, so skip it
@ -91,7 +89,7 @@ Timer.prototype.OnUpdate = function(msg)
if (!cmp)
{
// The entity was probably destroyed; clean up the timer
delete this.timers[id];
this.timers.delete(id);
continue;
}
@ -110,12 +108,12 @@ Timer.prototype.OnUpdate = function(msg)
t[3] += t[4];
// Add it to the list to get re-executed if it's soon enough
if (t[3] <= this.time)
run.push(id);
run.add(id);
}
else
{
// Non-repeating time - delete it
delete this.timers[id];
this.timers.delete(id);
}
}
}

View File

@ -223,6 +223,38 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
m_Serializer.Bool("value", b);
break;
}
else if (protokey == JSProto_Map)
{
// TODO: There's no C++ API (yet) to work with maps. This code relies on the internal
// structure of the Iterator object returned by Map.entries(). This is not ideal
// because the structure could change in the future (and actually does change with v31).
// Change this code if SpiderMonkey gets such an API.
u32 mapSize;
m_ScriptInterface.GetProperty(val, "size", mapSize);
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_MAP);
m_Serializer.NumberU32_Unbounded("map size", mapSize);
JS::RootedValue keyValueIterator(cx);
m_ScriptInterface.CallFunction(val, "entries", &keyValueIterator);
for (u32 i=0; i<mapSize; ++i)
{
JS::RootedValue keyValuePair(cx);
ENSURE(m_ScriptInterface.CallFunction(keyValueIterator, "next", &keyValuePair));
JS::RootedObject keyValuePairObj(cx, &keyValuePair.toObject());
JS::RootedValue key(cx);
JS::RootedValue value(cx);
ENSURE(JS_GetElement(cx, keyValuePairObj, 0, key.address()));
ENSURE(JS_GetElement(cx, keyValuePairObj, 1, value.address()));
HandleScriptVal(key);
HandleScriptVal(value);
}
break;
}
else
{
// Unrecognized class

View File

@ -34,7 +34,8 @@ enum
SCRIPT_TYPE_OBJECT_PROTOTYPE = 11, // user-defined prototype
SCRIPT_TYPE_OBJECT_NUMBER = 12, // standard Number class
SCRIPT_TYPE_OBJECT_STRING = 13, // standard String class
SCRIPT_TYPE_OBJECT_BOOLEAN = 14 // standard Boolean class
SCRIPT_TYPE_OBJECT_BOOLEAN = 14, // standard Boolean class
SCRIPT_TYPE_OBJECT_MAP = 15 // Map class
};
// ArrayBufferView subclasses (to avoid relying directly on the JSAPI enums)

View File

@ -389,6 +389,22 @@ jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject
return JS::ObjectValue(*bufferObj);
}
case SCRIPT_TYPE_OBJECT_MAP:
{
u32 mapSize;
NumberU32_Unbounded("map size", mapSize);
JS::RootedValue mapVal(cx);
m_ScriptInterface.Eval("(new Map())", &mapVal);
for (u32 i=0; i<mapSize; ++i)
{
JS::RootedValue key(cx, ReadScriptVal("map key", JS::NullPtr()));
JS::RootedValue value(cx, ReadScriptVal("map value", JS::NullPtr()));
m_ScriptInterface.CallFunctionVoid(mapVal, "set", key, value);
}
AddScriptBackref(&mapVal.toObject());
return mapVal;
}
default:
throw PSERROR_Deserialize_OutOfBounds();
}