Commit d5040c43 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[collections] Add OrderedHashTable::Delete

Bug: v8:5717
Change-Id: Icc601c409ac79195991facf1cb2027aab6145ff8
Reviewed-on: https://chromium-review.googlesource.com/540659
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46066}
parent da607264
...@@ -18158,14 +18158,9 @@ Object* OrderedHashTable<Derived, entrysize>::HasKey(Isolate* isolate, ...@@ -18158,14 +18158,9 @@ Object* OrderedHashTable<Derived, entrysize>::HasKey(Isolate* isolate,
Object* key) { Object* key) {
DCHECK(table->IsOrderedHashTable()); DCHECK(table->IsOrderedHashTable());
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
int entry = table->KeyToFirstEntry(isolate, key); int entry = table->FindEntry(isolate, key);
// Walk the chain in the bucket to find the key. return entry == kNotFound ? isolate->heap()->false_value()
while (entry != kNotFound) { : isolate->heap()->true_value();
Object* candidate_key = table->KeyAt(entry);
if (candidate_key->SameValueZero(key)) return isolate->heap()->true_value();
entry = table->NextChainEntry(entry);
}
return isolate->heap()->false_value();
} }
Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table, Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
...@@ -18267,20 +18262,35 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash( ...@@ -18267,20 +18262,35 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
return new_table; return new_table;
} }
template <class Derived, int entrysize>
bool OrderedHashTable<Derived, entrysize>::Delete(Isolate* isolate,
Derived* table, Object* key) {
DisallowHeapAllocation no_gc;
int entry = table->FindEntry(isolate, key);
if (entry == kNotFound) return false;
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
int index = table->EntryToIndex(entry);
Object* hole = isolate->heap()->the_hole_value();
for (int i = 0; i < entrysize; ++i) {
table->set(index + i, hole);
}
table->SetNumberOfElements(nof - 1);
table->SetNumberOfDeletedElements(nod + 1);
return true;
}
Object* OrderedHashMap::Get(Isolate* isolate, OrderedHashMap* table, Object* OrderedHashMap::Get(Isolate* isolate, OrderedHashMap* table,
Object* key) { Object* key) {
DCHECK(table->IsOrderedHashMap()); DCHECK(table->IsOrderedHashMap());
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
int entry = table->KeyToFirstEntry(isolate, key); int entry = table->FindEntry(isolate, key);
// Walk the chain in the bucket to find the key. if (entry == kNotFound) return isolate->heap()->undefined_value();
while (entry != kNotFound) { return table->ValueAt(entry);
Object* candidate_key = table->KeyAt(entry);
if (candidate_key->SameValueZero(key)) {
return table->ValueAt(entry);
}
entry = table->NextChainEntry(entry);
}
return isolate->heap()->undefined_value();
} }
Handle<OrderedHashMap> OrderedHashMap::Add(Handle<OrderedHashMap> table, Handle<OrderedHashMap> OrderedHashMap::Add(Handle<OrderedHashMap> table,
...@@ -18332,6 +18342,10 @@ template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear( ...@@ -18332,6 +18342,10 @@ template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear(
template Object* OrderedHashTable<OrderedHashSet, 1>::HasKey( template Object* OrderedHashTable<OrderedHashSet, 1>::HasKey(
Isolate* isolate, OrderedHashSet* table, Object* key); Isolate* isolate, OrderedHashSet* table, Object* key);
template bool OrderedHashTable<OrderedHashSet, 1>::Delete(Isolate* isolate,
OrderedHashSet* table,
Object* key);
template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate( template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure); Isolate* isolate, int capacity, PretenureFlag pretenure);
...@@ -18347,6 +18361,10 @@ template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear( ...@@ -18347,6 +18361,10 @@ template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear(
template Object* OrderedHashTable<OrderedHashMap, 2>::HasKey( template Object* OrderedHashTable<OrderedHashMap, 2>::HasKey(
Isolate* isolate, OrderedHashMap* table, Object* key); Isolate* isolate, OrderedHashMap* table, Object* key);
template bool OrderedHashTable<OrderedHashMap, 2>::Delete(Isolate* isolate,
OrderedHashMap* table,
Object* key);
template <> template <>
Handle<SmallOrderedHashSet> Handle<SmallOrderedHashSet>
SmallOrderedHashTable<SmallOrderedHashSet>::Allocate(Isolate* isolate, SmallOrderedHashTable<SmallOrderedHashSet>::Allocate(Isolate* isolate,
......
...@@ -410,6 +410,10 @@ class OrderedHashTable : public FixedArray { ...@@ -410,6 +410,10 @@ class OrderedHashTable : public FixedArray {
// existing iterators can be updated. // existing iterators can be updated.
static Handle<Derived> Clear(Handle<Derived> table); static Handle<Derived> Clear(Handle<Derived> table);
// Returns a true value if the OrderedHashTable contains the key and
// the key has been deleted. This does not shrink the table.
static bool Delete(Isolate* isolate, Derived* table, Object* key);
// Returns a true value if the OrderedHashTable contains the key // Returns a true value if the OrderedHashTable contains the key
static Object* HasKey(Isolate* isolate, Derived* table, Object* key); static Object* HasKey(Isolate* isolate, Derived* table, Object* key);
...@@ -457,6 +461,18 @@ class OrderedHashTable : public FixedArray { ...@@ -457,6 +461,18 @@ class OrderedHashTable : public FixedArray {
return HashToEntry(Smi::cast(hash)->value()); return HashToEntry(Smi::cast(hash)->value());
} }
int FindEntry(Isolate* isolate, Object* key) {
int entry = KeyToFirstEntry(isolate, key);
// Walk the chain in the bucket to find the key.
while (entry != kNotFound) {
Object* candidate_key = KeyAt(entry);
if (candidate_key->SameValueZero(key)) break;
entry = NextChainEntry(entry);
}
return entry;
}
int NextChainEntry(int entry) { int NextChainEntry(int entry) {
Object* next_entry = get(EntryToIndex(entry) + kChainOffset); Object* next_entry = get(EntryToIndex(entry) + kChainOffset);
return Smi::cast(next_entry)->value(); return Smi::cast(next_entry)->value();
......
...@@ -13,6 +13,19 @@ static Isolate* GetIsolateFrom(LocalContext* context) { ...@@ -13,6 +13,19 @@ static Isolate* GetIsolateFrom(LocalContext* context) {
return reinterpret_cast<Isolate*>((*context)->GetIsolate()); return reinterpret_cast<Isolate*>((*context)->GetIsolate());
} }
void CopyHashCode(Isolate* isolate, Handle<JSReceiver> from,
Handle<JSReceiver> to) {
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
Handle<Smi> hash =
Handle<Smi>::cast(JSObject::GetDataProperty(from, hash_code_symbol));
LookupIterator it(to, hash_code_symbol, to, LookupIterator::OWN);
CHECK(to->AddDataProperty(
&it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR,
v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED)
.IsJust());
}
void Verify(Handle<SmallOrderedHashSet> set) { void Verify(Handle<SmallOrderedHashSet> set) {
#if VERIFY_HEAP #if VERIFY_HEAP
set->ObjectVerify(); set->ObjectVerify();
...@@ -31,6 +44,12 @@ void Verify(Handle<OrderedHashMap> map) { ...@@ -31,6 +44,12 @@ void Verify(Handle<OrderedHashMap> map) {
#endif #endif
} }
void Verify(Handle<OrderedHashSet> set) {
#if VERIFY_HEAP
set->ObjectVerify();
#endif
}
TEST(SmallOrderedHashSetInsertion) { TEST(SmallOrderedHashSetInsertion) {
LocalContext context; LocalContext context;
Isolate* isolate = GetIsolateFrom(&context); Isolate* isolate = GetIsolateFrom(&context);
...@@ -211,20 +230,8 @@ TEST(SmallOrderedHashSetDuplicateHashCode) { ...@@ -211,20 +230,8 @@ TEST(SmallOrderedHashSetDuplicateHashCode) {
CHECK_EQ(1, set->NumberOfElements()); CHECK_EQ(1, set->NumberOfElements());
CHECK(set->HasKey(isolate, key1)); CHECK(set->HasKey(isolate, key1));
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
Handle<Smi> hash =
Handle<Smi>::cast(JSObject::GetDataProperty(key1, hash_code_symbol));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto(); Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
LookupIterator it(key2, hash_code_symbol, key2, LookupIterator::OWN); CopyHashCode(isolate, key1, key2);
CHECK(key2->AddDataProperty(
&it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR,
v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED)
.IsJust());
CHECK(!key1->SameValue(*key2));
Object* hash1 = key1->GetHash();
Object* hash2 = key2->GetHash();
CHECK_EQ(hash1, hash2);
set = SmallOrderedHashSet::Add(set, key2); set = SmallOrderedHashSet::Add(set, key2);
Verify(set); Verify(set);
...@@ -612,16 +619,8 @@ TEST(OrderedHashMapDuplicateHashCode) { ...@@ -612,16 +619,8 @@ TEST(OrderedHashMapDuplicateHashCode) {
CHECK_EQ(1, map->NumberOfElements()); CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1)); CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
Handle<Smi> hash =
Handle<Smi>::cast(JSObject::GetDataProperty(key1, hash_code_symbol));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto(); Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
LookupIterator it(key2, hash_code_symbol, key2, LookupIterator::OWN); CopyHashCode(isolate, key1, key2);
CHECK(key2->AddDataProperty(
&it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR,
v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED)
.IsJust());
map = OrderedHashMap::Add(map, key2, value); map = OrderedHashMap::Add(map, key2, value);
Verify(map); Verify(map);
...@@ -630,3 +629,312 @@ TEST(OrderedHashMapDuplicateHashCode) { ...@@ -630,3 +629,312 @@ TEST(OrderedHashMapDuplicateHashCode) {
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1)); CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2)); CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
} }
TEST(OrderedHashMapDeletion) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<Object> true_val = factory->true_value();
Handle<Object> false_val = factory->false_value();
Handle<Smi> value1(Smi::FromInt(1), isolate);
Handle<String> value = factory->NewStringFromAsciiChecked("bar");
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(0, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
// Delete from an empty hash table
Handle<Smi> key1(Smi::FromInt(1), isolate);
CHECK(!OrderedHashMap::Delete(isolate, *map, *key1));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(0, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
map = OrderedHashMap::Add(map, key1, value1);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
// Delete single existing key
CHECK(OrderedHashMap::Delete(isolate, *map, *key1));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(0, map->NumberOfElements());
CHECK_EQ(1, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
map = OrderedHashMap::Add(map, key1, value1);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(1, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
map = OrderedHashMap::Add(map, key2, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
CHECK_EQ(1, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
Handle<Symbol> key3 = factory->NewSymbol();
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key3));
map = OrderedHashMap::Add(map, key3, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(3, map->NumberOfElements());
CHECK_EQ(1, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
// Delete multiple existing keys
CHECK(OrderedHashMap::Delete(isolate, *map, *key1));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
CHECK_EQ(2, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK(OrderedHashMap::Delete(isolate, *map, *key2));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(3, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK(OrderedHashMap::Delete(isolate, *map, *key3));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(0, map->NumberOfElements());
CHECK_EQ(4, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key3));
// Delete non existant key from non new hash table
CHECK(!OrderedHashMap::Delete(isolate, *map, *key3));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(0, map->NumberOfElements());
CHECK_EQ(4, map->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key3));
// Delete non existant key from non empty hash table
map = OrderedHashMap::Shrink(map);
map = OrderedHashMap::Add(map, key1, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK(!OrderedHashMap::Delete(isolate, *map, *key2));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key3));
}
TEST(OrderedHashMapDuplicateHashCodeDeletion) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
Handle<Object> true_val = factory->true_value();
Handle<Object> false_val = factory->false_value();
map = OrderedHashMap::Add(map, key1, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
// We shouldn't be able to delete the key!
CHECK(!OrderedHashMap::Delete(isolate, *map, *key2));
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key2));
}
TEST(OrderedHashSetDeletion) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<Object> true_val = factory->true_value();
Handle<Object> false_val = factory->false_value();
Handle<OrderedHashSet> set = factory->NewOrderedHashSet();
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(0, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
// Delete from an empty hash table
Handle<Smi> key1(Smi::FromInt(1), isolate);
CHECK(!OrderedHashSet::Delete(isolate, *set, *key1));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(0, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
set = OrderedHashSet::Add(set, key1);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
// Delete single existing key
CHECK(OrderedHashSet::Delete(isolate, *set, *key1));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(0, set->NumberOfElements());
CHECK_EQ(1, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
set = OrderedHashSet::Add(set, key1);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(1, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
set = OrderedHashSet::Add(set, key2);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(2, set->NumberOfElements());
CHECK_EQ(1, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key2));
Handle<Symbol> key3 = factory->NewSymbol();
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key3));
set = OrderedHashSet::Add(set, key3);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(3, set->NumberOfElements());
CHECK_EQ(1, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key3));
// Delete multiple existing keys
CHECK(OrderedHashSet::Delete(isolate, *set, *key1));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(2, set->NumberOfElements());
CHECK_EQ(2, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key3));
CHECK(OrderedHashSet::Delete(isolate, *set, *key2));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(3, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key3));
CHECK(OrderedHashSet::Delete(isolate, *set, *key3));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(0, set->NumberOfElements());
CHECK_EQ(4, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key3));
// Delete non existant key from non new hash table
CHECK(!OrderedHashSet::Delete(isolate, *set, *key3));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(0, set->NumberOfElements());
CHECK_EQ(4, set->NumberOfDeletedElements());
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key3));
// Delete non existant key from non empty hash table
set = OrderedHashSet::Shrink(set);
set = OrderedHashSet::Add(set, key1);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key3));
CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key3));
}
TEST(OrderedHashSetDuplicateHashCodeDeletion) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<OrderedHashSet> set = factory->NewOrderedHashSet();
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
Handle<Object> true_val = factory->true_value();
Handle<Object> false_val = factory->false_value();
set = OrderedHashSet::Add(set, key1);
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
// We shouldn't be able to delete the key!
CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));
Verify(set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK_EQ(*true_val, OrderedHashSet::HasKey(isolate, *set, *key1));
CHECK_EQ(*false_val, OrderedHashSet::HasKey(isolate, *set, *key2));
}
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