From a8d9c58b1f618f518dc3a5a73023e6847544979f Mon Sep 17 00:00:00 2001 From: adamk Date: Tue, 26 May 2015 11:13:22 -0700 Subject: [PATCH] Add {Map,Set}::AsArray to the API These return arrays representing the current contents of the given Map/Set. They are similar to what would be returned by the JS code: Array.from(collection) except that they are guaranteed side-effect free. This will be useful in implementing structured clone which, as specified in HTML, speaks in terms of the internal [[MapData]] and [[SetData]] slots without going through the exposed iteration ES semantics. BUG=v8:3340 LOG=y Review URL: https://codereview.chromium.org/1148383007 Cr-Commit-Position: refs/heads/master@{#28640} --- include/v8.h | 11 +++++++++++ src/api.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ test/cctest/test-api.cc | 16 ++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/include/v8.h b/include/v8.h index 16975d5..fb07e9c 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2952,6 +2952,12 @@ class V8_EXPORT Map : public Object { size_t Size() const; /** + * Returns an array of [key, value] arrays representing the contents + * of this Map. + */ + Local AsArray() const; + + /** * Creates a new Map. */ static Local New(Isolate* isolate); @@ -2972,6 +2978,11 @@ class V8_EXPORT Set : public Object { size_t Size() const; /** + * Returns an array of the keys in this Set. + */ + Local AsArray() const; + + /** * Creates a new Set. */ static Local New(Isolate* isolate); diff --git a/src/api.cc b/src/api.cc index dbc782c..7cf416c 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6131,6 +6131,31 @@ size_t v8::Map::Size() const { } +Local Map::AsArray() const { + i::Handle obj = Utils::OpenHandle(this); + i::Isolate* isolate = obj->GetIsolate(); + i::Factory* factory = isolate->factory(); + LOG_API(isolate, "Map::AsArray"); + ENTER_V8(isolate); + i::Handle table(i::OrderedHashMap::cast(obj->table())); + int length = table->NumberOfElements(); + i::Handle result = factory->NewFixedArray(length); + for (int i = 0; i < length; ++i) { + if (table->KeyAt(i)->IsTheHole()) continue; + i::HandleScope handle_scope(isolate); + i::Handle entry = factory->NewFixedArray(2); + entry->set(0, table->KeyAt(i)); + entry->set(1, table->ValueAt(i)); + i::Handle entry_array = + factory->NewJSArrayWithElements(entry, i::FAST_ELEMENTS, 2); + result->set(i, *entry_array); + } + i::Handle result_array = + factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length); + return Utils::ToLocal(result_array); +} + + Local v8::Set::New(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast(isolate); LOG_API(i_isolate, "Set::New"); @@ -6146,6 +6171,27 @@ size_t v8::Set::Size() const { } +Local Set::AsArray() const { + i::Handle obj = Utils::OpenHandle(this); + i::Isolate* isolate = obj->GetIsolate(); + i::Factory* factory = isolate->factory(); + LOG_API(isolate, "Set::AsArray"); + ENTER_V8(isolate); + i::Handle table(i::OrderedHashSet::cast(obj->table())); + int length = table->NumberOfElements(); + i::Handle result = factory->NewFixedArray(length); + for (int i = 0; i < length; ++i) { + i::Object* key = table->KeyAt(i); + if (!key->IsTheHole()) { + result->set(i, key); + } + } + i::Handle result_array = + factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length); + return Utils::ToLocal(result_array); +} + + bool Value::IsPromise() const { auto self = Utils::OpenHandle(this); return i::Object::IsPromise(self); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index af83daa..395450d 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -21116,6 +21116,17 @@ TEST(Map) { CHECK(val->IsMap()); map = v8::Local::Cast(val); CHECK_EQ(2, map->Size()); + + v8::Local entries = map->AsArray(); + CHECK_EQ(2, entries->Length()); + v8::Local entry = entries->Get(0).As(); + CHECK_EQ(2, entry->Length()); + CHECK_EQ(1, entry->Get(0).As()->Value()); + CHECK_EQ(2, entry->Get(1).As()->Value()); + entry = entries->Get(1).As(); + CHECK_EQ(2, entry->Length()); + CHECK_EQ(3, entry->Get(0).As()->Value()); + CHECK_EQ(4, entry->Get(1).As()->Value()); } @@ -21133,4 +21144,9 @@ TEST(Set) { CHECK(val->IsSet()); set = v8::Local::Cast(val); CHECK_EQ(2, set->Size()); + + v8::Local keys = set->AsArray(); + CHECK_EQ(2, keys->Length()); + CHECK_EQ(1, keys->Get(0).As()->Value()); + CHECK_EQ(2, keys->Get(1).As()->Value()); } -- 2.7.4