// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "platform/hashmap.h" #include "platform/assert.h" #include "platform/globals.h" #include "vm/unit_test.h" namespace dart { // Default initial size of hashmaps used in these tests. static intptr_t kInitialSize = 8; typedef uint32_t (*IntKeyHash)(uint32_t key); class IntSet { public: explicit IntSet(IntKeyHash hash) : hash_(hash), map_(SimpleHashMap::SamePointerValue, kInitialSize) {} void Insert(int x) { EXPECT_NE(0, x); // 0 corresponds to (void*)nullptr - illegal key value SimpleHashMap::Entry* p = map_.Lookup(reinterpret_cast(x), hash_(x), true); EXPECT(p != nullptr); // insert is set! EXPECT_EQ(reinterpret_cast(x), p->key); // We don't care about p->value. } void Remove(int x) { EXPECT_NE(0, x); // 0 corresponds to (void*)nullptr - illegal key value map_.Remove(reinterpret_cast(x), hash_(x)); } bool Present(int x) { SimpleHashMap::Entry* p = map_.Lookup(reinterpret_cast(x), hash_(x), false); if (p != nullptr) { EXPECT_EQ(reinterpret_cast(x), p->key); } return p != nullptr; } void Clear() { map_.Clear(); } uint32_t occupancy() const { uint32_t count = 0; for (SimpleHashMap::Entry* p = map_.Start(); p != nullptr; p = map_.Next(p)) { count++; } EXPECT_EQ(map_.occupancy_, count); return count; } private: IntKeyHash hash_; SimpleHashMap map_; }; static uint32_t WordHash(uint32_t key) { return dart::Utils::WordHash(key); } static uint32_t Hash(uint32_t key) { return 23; } static uint32_t CollisionHash1(uint32_t key) { return key & 0x3; } static uint32_t CollisionHash2(uint32_t key) { return kInitialSize - 1; } static uint32_t CollisionHash3(uint32_t key) { return kInitialSize - 2; } void TestSet(IntKeyHash hash, int size) { IntSet set(hash); EXPECT_EQ(0u, set.occupancy()); set.Insert(1); set.Insert(2); set.Insert(3); set.Insert(4); EXPECT_EQ(4u, set.occupancy()); set.Insert(2); set.Insert(3); EXPECT_EQ(4u, set.occupancy()); EXPECT(set.Present(1)); EXPECT(set.Present(2)); EXPECT(set.Present(3)); EXPECT(set.Present(4)); EXPECT(!set.Present(5)); EXPECT_EQ(4u, set.occupancy()); set.Remove(1); EXPECT(!set.Present(1)); EXPECT(set.Present(2)); EXPECT(set.Present(3)); EXPECT(set.Present(4)); EXPECT_EQ(3u, set.occupancy()); set.Remove(3); EXPECT(!set.Present(1)); EXPECT(set.Present(2)); EXPECT(!set.Present(3)); EXPECT(set.Present(4)); EXPECT_EQ(2u, set.occupancy()); set.Remove(4); EXPECT(!set.Present(1)); EXPECT(set.Present(2)); EXPECT(!set.Present(3)); EXPECT(!set.Present(4)); EXPECT_EQ(1u, set.occupancy()); set.Clear(); EXPECT_EQ(0u, set.occupancy()); // Insert a long series of values. const uint32_t start = 453; const uint32_t factor = 13; const uint32_t offset = 7; const uint32_t n = size; uint32_t x = start; for (uint32_t i = 0; i < n; i++) { EXPECT_EQ(i, set.occupancy()); set.Insert(x); x = x * factor + offset; } EXPECT_EQ(n, set.occupancy()); // Verify the same sequence of values. x = start; for (uint32_t i = 0; i < n; i++) { EXPECT(set.Present(x)); x = x * factor + offset; } EXPECT_EQ(n, set.occupancy()); // Remove all these values. x = start; for (uint32_t i = 0; i < n; i++) { EXPECT_EQ(n - i, set.occupancy()); EXPECT(set.Present(x)); set.Remove(x); EXPECT(!set.Present(x)); x = x * factor + offset; // Verify the expected values are still there. int y = start; for (uint32_t j = 0; j < n; j++) { if (j <= i) { EXPECT(!set.Present(y)); } else { EXPECT(set.Present(y)); } y = y * factor + offset; } } EXPECT_EQ(0u, set.occupancy()); } VM_UNIT_TEST_CASE(SimpleHashMap_Basic) { TestSet(WordHash, 100); TestSet(Hash, 100); TestSet(CollisionHash1, 50); TestSet(CollisionHash2, 50); TestSet(CollisionHash3, 50); } } // namespace dart