tint/utils: Add Generation() to Hashmap and Hashset.

Useful for knowing if you have to look up an entry again since the last
lookup.

Change-Id: Ib0374627ef5cd7fcff7fa2d9e72b4214260b2df3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100901
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
Ben Clayton 2022-08-31 19:04:28 +00:00 committed by Dawn LUCI CQ
parent 4d67a883b6
commit 4e0335c5af
4 changed files with 58 additions and 1 deletions

View File

@ -288,6 +288,9 @@ class Hashmap {
/// @returns the number of entries in the map. /// @returns the number of entries in the map.
size_t Count() const { return set_.Count(); } size_t Count() const { return set_.Count(); }
/// @returns a monotonic counter which is incremented whenever the map is mutated.
size_t Generation() const { return set_.Generation(); }
/// @returns true if the map contains no entries. /// @returns true if the map contains no entries.
bool IsEmpty() const { return set_.IsEmpty(); } bool IsEmpty() const { return set_.IsEmpty(); }

View File

@ -69,6 +69,27 @@ TEST(Hashmap, ReplaceRemove) {
EXPECT_FALSE(map.Contains("world")); EXPECT_FALSE(map.Contains("world"));
} }
TEST(Hashmap, Generation) {
Hashmap<int, std::string, 8> map;
EXPECT_EQ(map.Generation(), 0u);
map.Add(1, "one");
EXPECT_EQ(map.Generation(), 1u);
map.Add(1, "uno");
EXPECT_EQ(map.Generation(), 1u);
map.Replace(1, "une");
EXPECT_EQ(map.Generation(), 2u);
map.Add(2, "dos");
EXPECT_EQ(map.Generation(), 3u);
map.Remove(1);
EXPECT_EQ(map.Generation(), 4u);
map.Clear();
EXPECT_EQ(map.Generation(), 5u);
map.Find(2);
EXPECT_EQ(map.Generation(), 5u);
map.Get(2);
EXPECT_EQ(map.Generation(), 5u);
}
TEST(Hashmap, Iterator) { TEST(Hashmap, Iterator) {
using Map = Hashmap<int, std::string, 8>; using Map = Hashmap<int, std::string, 8>;
using KV = typename Map::KeyValue; using KV = typename Map::KeyValue;

View File

@ -73,7 +73,8 @@ class Hashset {
static constexpr size_t kMinSlots = std::max<size_t>(kNumFixedSlots, 4); static constexpr size_t kMinSlots = std::max<size_t>(kNumFixedSlots, 4);
public: public:
/// Iterator for entries in the set /// Iterator for entries in the set.
/// Iterators are invalidated if the set is modified.
class Iterator { class Iterator {
public: public:
/// @returns the value pointed to by this iterator /// @returns the value pointed to by this iterator
@ -152,6 +153,7 @@ class Hashset {
slots_.Clear(); // Destructs all entries slots_.Clear(); // Destructs all entries
slots_.Resize(kMinSlots); slots_.Resize(kMinSlots);
count_ = 0; count_ = 0;
generation_++;
} }
/// Result of Add() /// Result of Add()
@ -219,6 +221,7 @@ class Hashset {
// Entry was removed. // Entry was removed.
count_--; count_--;
generation_++;
return true; return true;
} }
@ -299,6 +302,9 @@ class Hashset {
/// @returns true if the set contains no entries. /// @returns true if the set contains no entries.
bool IsEmpty() const { return count_ == 0; } bool IsEmpty() const { return count_ == 0; }
/// @returns a monotonic counter which is incremented whenever the set is mutated.
size_t Generation() const { return generation_; }
/// @returns an iterator to the start of the set. /// @returns an iterator to the start of the set.
Iterator begin() const { return Iterator{slots_.begin(), slots_.end()}; } Iterator begin() const { return Iterator{slots_.begin(), slots_.end()}; }
@ -351,6 +357,7 @@ class Hashset {
slot.hash = hash.value; slot.hash = hash.value;
slot.distance = distance; slot.distance = distance;
count_++; count_++;
generation_++;
result = AddResult{AddAction::kAdded, &slot.value.value()}; result = AddResult{AddAction::kAdded, &slot.value.value()};
return Action::kStop; return Action::kStop;
} }
@ -361,6 +368,7 @@ class Hashset {
// Slot is equal to value. Replace or preserve? // Slot is equal to value. Replace or preserve?
if constexpr (MODE == PutMode::kReplace) { if constexpr (MODE == PutMode::kReplace) {
slot.value = std::forward<V>(value); slot.value = std::forward<V>(value);
generation_++;
result = AddResult{AddAction::kReplaced, &slot.value.value()}; result = AddResult{AddAction::kReplaced, &slot.value.value()};
} else { } else {
result = AddResult{AddAction::kKeptExisting, &slot.value.value()}; result = AddResult{AddAction::kKeptExisting, &slot.value.value()};
@ -380,6 +388,7 @@ class Hashset {
InsertShuffle(Wrap(index + 1), std::move(evicted)); InsertShuffle(Wrap(index + 1), std::move(evicted));
count_++; count_++;
generation_++;
result = AddResult{AddAction::kAdded, &slot.value.value()}; result = AddResult{AddAction::kAdded, &slot.value.value()};
return Action::kStop; return Action::kStop;
@ -502,6 +511,9 @@ class Hashset {
/// The number of entries in the set. /// The number of entries in the set.
size_t count_ = 0; size_t count_ = 0;
/// Counter that's incremented with each modification to the set.
size_t generation_ = 0;
}; };
} // namespace tint::utils } // namespace tint::utils

View File

@ -67,6 +67,27 @@ TEST(Hashset, AddMany) {
} }
} }
TEST(Hashset, Generation) {
Hashset<int, 8> set;
EXPECT_EQ(set.Generation(), 0u);
set.Add(1);
EXPECT_EQ(set.Generation(), 1u);
set.Add(1);
EXPECT_EQ(set.Generation(), 1u);
set.Replace(1);
EXPECT_EQ(set.Generation(), 2u);
set.Add(2);
EXPECT_EQ(set.Generation(), 3u);
set.Remove(1);
EXPECT_EQ(set.Generation(), 4u);
set.Clear();
EXPECT_EQ(set.Generation(), 5u);
set.Find(2);
EXPECT_EQ(set.Generation(), 5u);
set.Get(2);
EXPECT_EQ(set.Generation(), 5u);
}
TEST(Hashset, Iterator) { TEST(Hashset, Iterator) {
Hashset<std::string, 8> set; Hashset<std::string, 8> set;
set.Add("one"); set.Add("one");