ES6: Adding support for size to Set and Map

Section 15.14.5.10 and 15.16.5.7 in the October 26, 2012 ES6 draft,
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

This adds a getter for "size" to Set.prototype and Map.prototype which reflects
the number of elements in the Set and Map respectively.

BUG=v8:2395

Review URL: https://codereview.chromium.org/11360089
Patch from Erik Arvidsson <arv@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12875 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 762c36b6
...@@ -88,6 +88,15 @@ function SetDelete(key) { ...@@ -88,6 +88,15 @@ function SetDelete(key) {
} }
function SetGetSize() {
if (!IS_SET(this)) {
throw MakeTypeError('incompatible_method_receiver',
['Set.prototype.size', this]);
}
return %SetGetSize(this);
}
function MapConstructor() { function MapConstructor() {
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
%MapInitialize(this); %MapInitialize(this);
...@@ -145,6 +154,15 @@ function MapDelete(key) { ...@@ -145,6 +154,15 @@ function MapDelete(key) {
} }
function MapGetSize() {
if (!IS_MAP(this)) {
throw MakeTypeError('incompatible_method_receiver',
['Map.prototype.size', this]);
}
return %MapGetSize(this);
}
function WeakMapConstructor() { function WeakMapConstructor() {
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
%WeakMapInitialize(this); %WeakMapInitialize(this);
...@@ -215,6 +233,7 @@ function WeakMapDelete(key) { ...@@ -215,6 +233,7 @@ function WeakMapDelete(key) {
%SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM); %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
// Set up the non-enumerable functions on the Set prototype object. // Set up the non-enumerable functions on the Set prototype object.
InstallGetter($Set.prototype, "size", SetGetSize);
InstallFunctions($Set.prototype, DONT_ENUM, $Array( InstallFunctions($Set.prototype, DONT_ENUM, $Array(
"add", SetAdd, "add", SetAdd,
"has", SetHas, "has", SetHas,
...@@ -222,6 +241,7 @@ function WeakMapDelete(key) { ...@@ -222,6 +241,7 @@ function WeakMapDelete(key) {
)); ));
// Set up the non-enumerable functions on the Map prototype object. // Set up the non-enumerable functions on the Map prototype object.
InstallGetter($Map.prototype, "size", MapGetSize);
InstallFunctions($Map.prototype, DONT_ENUM, $Array( InstallFunctions($Map.prototype, DONT_ENUM, $Array(
"get", MapGet, "get", MapGet,
"set", MapSet, "set", MapSet,
......
...@@ -783,6 +783,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { ...@@ -783,6 +783,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
return Smi::FromInt(table->NumberOfElements());
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) { RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
...@@ -842,6 +851,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { ...@@ -842,6 +851,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
return Smi::FromInt(table->NumberOfElements());
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) { RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
......
...@@ -302,6 +302,7 @@ namespace internal { ...@@ -302,6 +302,7 @@ namespace internal {
F(SetAdd, 2, 1) \ F(SetAdd, 2, 1) \
F(SetHas, 2, 1) \ F(SetHas, 2, 1) \
F(SetDelete, 2, 1) \ F(SetDelete, 2, 1) \
F(SetGetSize, 1, 1) \
\ \
/* Harmony maps */ \ /* Harmony maps */ \
F(MapInitialize, 1, 1) \ F(MapInitialize, 1, 1) \
...@@ -309,6 +310,7 @@ namespace internal { ...@@ -309,6 +310,7 @@ namespace internal {
F(MapHas, 2, 1) \ F(MapHas, 2, 1) \
F(MapDelete, 2, 1) \ F(MapDelete, 2, 1) \
F(MapSet, 3, 1) \ F(MapSet, 3, 1) \
F(MapGetSize, 1, 1) \
\ \
/* Harmony weakmaps */ \ /* Harmony weakmaps */ \
F(WeakMapInitialize, 1, 1) \ F(WeakMapInitialize, 1, 1) \
......
...@@ -60,6 +60,16 @@ function InstallFunctions(object, attributes, functions) { ...@@ -60,6 +60,16 @@ function InstallFunctions(object, attributes, functions) {
%ToFastProperties(object); %ToFastProperties(object);
} }
// Helper function to install a getter only property.
function InstallGetter(object, name, getter) {
%FunctionSetName(getter, name);
%FunctionRemovePrototype(getter);
%DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
%SetNativeFlag(getter);
}
// Prevents changes to the prototype of a built-in function. // Prevents changes to the prototype of a built-in function.
// The "prototype" property of the function object is made non-configurable, // The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents // and the prototype object is made non-extensible. The latter prevents
......
...@@ -314,3 +314,44 @@ TestBogusReceivers(bogusReceiversTestSet); ...@@ -314,3 +314,44 @@ TestBogusReceivers(bogusReceiversTestSet);
// There is a proposed stress-test available at the es-discuss mailing list // There is a proposed stress-test available at the es-discuss mailing list
// which cannot be reasonably automated. Check it out by hand if you like: // which cannot be reasonably automated. Check it out by hand if you like:
// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html // https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
// Set and Map size getters
var setSizeDescriptor = Object.getOwnPropertyDescriptor(Set.prototype, 'size');
assertEquals(undefined, setSizeDescriptor.value);
assertEquals(undefined, setSizeDescriptor.set);
assertTrue(setSizeDescriptor.get instanceof Function);
assertEquals(undefined, setSizeDescriptor.get.prototype);
assertFalse(setSizeDescriptor.enumerable);
assertTrue(setSizeDescriptor.configurable);
var s = new Set();
assertFalse(s.hasOwnProperty('size'));
for (var i = 0; i < 10; i++) {
assertEquals(i, s.size);
s.add(i);
}
for (var i = 9; i >= 0; i--) {
s.delete(i);
assertEquals(i, s.size);
}
var mapSizeDescriptor = Object.getOwnPropertyDescriptor(Map.prototype, 'size');
assertEquals(undefined, mapSizeDescriptor.value);
assertEquals(undefined, mapSizeDescriptor.set);
assertTrue(mapSizeDescriptor.get instanceof Function);
assertEquals(undefined, mapSizeDescriptor.get.prototype);
assertFalse(mapSizeDescriptor.enumerable);
assertTrue(mapSizeDescriptor.configurable);
var m = new Map();
assertFalse(m.hasOwnProperty('size'));
for (var i = 0; i < 10; i++) {
assertEquals(i, m.size);
m.set(i, i);
}
for (var i = 9; i >= 0; i--) {
m.delete(i);
assertEquals(i, m.size);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment