| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <tuple> |
| |
| #include "src/base/utils/random-number-generator.h" |
| #include "src/compiler/persistent-map.h" |
| #include "test/unittests/test-utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| // A random distribution that produces both small values and arbitrary numbers. |
| static int small_big_distr(base::RandomNumberGenerator* rand) { |
| return rand->NextInt() / std::max(1, rand->NextInt() / 100); |
| } |
| |
| TEST(PersistentMap, RefTest) { |
| base::RandomNumberGenerator rand(92834738); |
| AccountingAllocator allocator; |
| Zone zone(&allocator, ZONE_NAME); |
| std::vector<PersistentMap<int, int>> pers_maps; |
| pers_maps.emplace_back(&zone); |
| std::vector<std::map<int, int>> ref_maps(1); |
| for (int i = 0; i < 100000; ++i) { |
| if (rand.NextInt(2) == 0) { |
| // Read value; |
| int key = small_big_distr(&rand); |
| if (ref_maps[0].count(key) > 0) { |
| ASSERT_EQ(pers_maps[0].Get(key), ref_maps[0][key]); |
| } else { |
| ASSERT_EQ(pers_maps[0].Get(key), 0); |
| } |
| } |
| if (rand.NextInt(2) == 0) { |
| // Add value; |
| int key = small_big_distr(&rand); |
| int value = small_big_distr(&rand); |
| pers_maps[0].Set(key, value); |
| ref_maps[0][key] = value; |
| } |
| if (rand.NextInt(1000) == 0) { |
| // Create empty map. |
| pers_maps.emplace_back(&zone); |
| ref_maps.emplace_back(); |
| } |
| if (rand.NextInt(100) == 0) { |
| // Copy and move around maps. |
| int num_maps = static_cast<int>(pers_maps.size()); |
| int source = rand.NextInt(num_maps - 1) + 1; |
| int target = rand.NextInt(num_maps - 1) + 1; |
| pers_maps[target] = std::move(pers_maps[0]); |
| ref_maps[target] = std::move(ref_maps[0]); |
| pers_maps[0] = pers_maps[source]; |
| ref_maps[0] = ref_maps[source]; |
| } |
| } |
| for (size_t i = 0; i < pers_maps.size(); ++i) { |
| std::set<int> keys; |
| for (auto pair : pers_maps[i]) { |
| ASSERT_EQ(keys.count(pair.first), 0u); |
| keys.insert(pair.first); |
| ASSERT_EQ(ref_maps[i][pair.first], pair.second); |
| } |
| for (auto pair : ref_maps[i]) { |
| int value = pers_maps[i].Get(pair.first); |
| ASSERT_EQ(pair.second, value); |
| if (value != 0) { |
| ASSERT_EQ(keys.count(pair.first), 1u); |
| keys.erase(pair.first); |
| } |
| } |
| ASSERT_TRUE(keys.empty()); |
| } |
| } |
| |
| TEST(PersistentMap, Zip) { |
| base::RandomNumberGenerator rand(92834738); |
| AccountingAllocator allocator; |
| Zone zone(&allocator, ZONE_NAME); |
| |
| // Provoke hash collisions to stress the iterator. |
| struct bad_hash { |
| size_t operator()(uint32_t key) { |
| return base::hash_value(static_cast<size_t>(key) % 1000); |
| } |
| }; |
| PersistentMap<int, uint32_t, bad_hash> a(&zone); |
| PersistentMap<int, uint32_t, bad_hash> b(&zone); |
| |
| uint32_t sum_a = 0; |
| uint32_t sum_b = 0; |
| |
| for (int i = 0; i < 30000; ++i) { |
| int key = small_big_distr(&rand); |
| uint32_t value = small_big_distr(&rand); |
| if (rand.NextBool()) { |
| sum_a += value; |
| a.Set(key, a.Get(key) + value); |
| } else { |
| sum_b += value; |
| b.Set(key, b.Get(key) + value); |
| } |
| } |
| |
| uint32_t sum = sum_a + sum_b; |
| |
| for (auto pair : a) { |
| sum_a -= pair.second; |
| } |
| ASSERT_EQ(0u, sum_a); |
| |
| for (auto pair : b) { |
| sum_b -= pair.second; |
| } |
| ASSERT_EQ(0u, sum_b); |
| |
| for (auto triple : a.Zip(b)) { |
| int key = std::get<0>(triple); |
| uint32_t value_a = std::get<1>(triple); |
| uint32_t value_b = std::get<2>(triple); |
| ASSERT_EQ(value_a, a.Get(key)); |
| ASSERT_EQ(value_b, b.Get(key)); |
| sum -= value_a; |
| sum -= value_b; |
| } |
| ASSERT_EQ(0u, sum); |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |