tint/utils/UniqueVector: Use utils::Vector and utils::Hashset

For fewer heap allocations, faster lookups.

Change-Id: I02da7c1a63608096ec898b0d89f9f97c6db8733f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98141
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton
2022-08-17 18:07:20 +00:00
committed by Dawn LUCI CQ
parent b79238d7ec
commit dce63f5717
27 changed files with 224 additions and 218 deletions

View File

@@ -21,17 +21,15 @@
#include <utility>
#include <vector>
#include "src/tint/utils/hashset.h"
#include "src/tint/utils/vector.h"
namespace tint::utils {
/// UniqueVector is an ordered container that only contains unique items.
/// Attempting to add a duplicate is a no-op.
template <typename T, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
struct UniqueVector {
/// The iterator returned by begin() and end()
using ConstIterator = typename std::vector<T>::const_iterator;
/// The iterator returned by rbegin() and rend()
using ConstReverseIterator = typename std::vector<T>::const_reverse_iterator;
/// Constructor
UniqueVector() = default;
@@ -40,7 +38,7 @@ struct UniqueVector {
/// elements will be removed.
explicit UniqueVector(std::vector<T>&& v) {
for (auto& el : v) {
add(el);
Add(el);
}
}
@@ -48,10 +46,9 @@ struct UniqueVector {
/// already contain the given item.
/// @param item the item to append to the end of the vector
/// @returns true if the item was added, otherwise false.
bool add(const T& item) {
if (set.count(item) == 0) {
vector.emplace_back(item);
set.emplace(item);
bool Add(const T& item) {
if (set.Add(item)) {
vector.Push(item);
return true;
}
return false;
@@ -59,7 +56,7 @@ struct UniqueVector {
/// @returns true if the vector contains `item`
/// @param item the item
bool contains(const T& item) const { return set.count(item); }
bool Contains(const T& item) const { return set.Contains(item); }
/// @param i the index of the element to retrieve
/// @returns the element at the index `i`
@@ -70,48 +67,50 @@ struct UniqueVector {
const T& operator[](size_t i) const { return vector[i]; }
/// @returns true if the vector is empty
bool empty() const { return vector.empty(); }
bool IsEmpty() const { return vector.IsEmpty(); }
/// @returns the number of items in the vector
size_t size() const { return vector.size(); }
size_t Length() const { return vector.Length(); }
/// @returns the pointer to the first element in the vector, or nullptr if the vector is empty.
const T* data() const { return vector.empty() ? nullptr : vector.data(); }
const T* Data() const { return vector.IsEmpty() ? nullptr : &vector[0]; }
/// @returns an iterator to the beginning of the vector
ConstIterator begin() const { return vector.begin(); }
auto begin() const { return vector.begin(); }
/// @returns an iterator to the end of the vector
ConstIterator end() const { return vector.end(); }
auto end() const { return vector.end(); }
/// @returns an iterator to the beginning of the reversed vector
ConstReverseIterator rbegin() const { return vector.rbegin(); }
auto rbegin() const { return vector.rbegin(); }
/// @returns an iterator to the end of the reversed vector
ConstReverseIterator rend() const { return vector.rend(); }
auto rend() const { return vector.rend(); }
/// @returns a const reference to the internal vector
operator const std::vector<T>&() const { return vector; }
operator const Vector<T, N>&() const { return vector; }
/// @returns the std::move()'d vector.
/// @note The UniqueVector must not be used after calling this method
VectorRef<T> Release() { return std::move(vector); }
/// Pre-allocates `count` elements in the vector and set
/// @param count the number of elements to pre-allocate
void reserve(size_t count) {
vector.reserve(count);
set.reserve(count);
void Reserve(size_t count) {
vector.Reserve(count);
set.Reserve(count);
}
/// Removes the last element from the vector
/// @returns the popped element
T pop_back() {
auto el = std::move(vector.back());
set.erase(el);
vector.pop_back();
return el;
T Pop() {
set.Remove(vector.Back());
return vector.Pop();
}
private:
std::vector<T> vector;
std::unordered_set<T, HASH, EQUAL> set;
Vector<T, N> vector;
Hashset<T, N, HASH, EQUAL> set;
};
} // namespace tint::utils

View File

@@ -13,6 +13,9 @@
// limitations under the License.
#include "src/tint/utils/unique_vector.h"
#include <vector>
#include "src/tint/utils/reverse.h"
#include "gtest/gtest.h"
@@ -21,16 +24,16 @@ namespace tint::utils {
namespace {
TEST(UniqueVectorTest, Empty) {
UniqueVector<int> unique_vec;
EXPECT_EQ(unique_vec.size(), 0u);
EXPECT_EQ(unique_vec.empty(), true);
UniqueVector<int, 4> unique_vec;
EXPECT_EQ(unique_vec.Length(), 0u);
EXPECT_EQ(unique_vec.IsEmpty(), true);
EXPECT_EQ(unique_vec.begin(), unique_vec.end());
}
TEST(UniqueVectorTest, MoveConstructor) {
UniqueVector<int> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
EXPECT_EQ(unique_vec.size(), 4u);
EXPECT_EQ(unique_vec.empty(), false);
UniqueVector<int, 4> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
EXPECT_EQ(unique_vec.Length(), 4u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 3);
EXPECT_EQ(unique_vec[2], 2);
@@ -38,12 +41,12 @@ TEST(UniqueVectorTest, MoveConstructor) {
}
TEST(UniqueVectorTest, AddUnique) {
UniqueVector<int> unique_vec;
unique_vec.add(0);
unique_vec.add(1);
unique_vec.add(2);
EXPECT_EQ(unique_vec.size(), 3u);
EXPECT_EQ(unique_vec.empty(), false);
UniqueVector<int, 4> unique_vec;
unique_vec.Add(0);
unique_vec.Add(1);
unique_vec.Add(2);
EXPECT_EQ(unique_vec.Length(), 3u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : unique_vec) {
EXPECT_EQ(n, i);
@@ -59,15 +62,15 @@ TEST(UniqueVectorTest, AddUnique) {
}
TEST(UniqueVectorTest, AddDuplicates) {
UniqueVector<int> unique_vec;
unique_vec.add(0);
unique_vec.add(0);
unique_vec.add(0);
unique_vec.add(1);
unique_vec.add(1);
unique_vec.add(2);
EXPECT_EQ(unique_vec.size(), 3u);
EXPECT_EQ(unique_vec.empty(), false);
UniqueVector<int, 4> unique_vec;
unique_vec.Add(0);
unique_vec.Add(0);
unique_vec.Add(0);
unique_vec.Add(1);
unique_vec.Add(1);
unique_vec.Add(2);
EXPECT_EQ(unique_vec.Length(), 3u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : unique_vec) {
EXPECT_EQ(n, i);
@@ -83,17 +86,17 @@ TEST(UniqueVectorTest, AddDuplicates) {
}
TEST(UniqueVectorTest, AsVector) {
UniqueVector<int> unique_vec;
unique_vec.add(0);
unique_vec.add(0);
unique_vec.add(0);
unique_vec.add(1);
unique_vec.add(1);
unique_vec.add(2);
UniqueVector<int, 4> unique_vec;
unique_vec.Add(0);
unique_vec.Add(0);
unique_vec.Add(0);
unique_vec.Add(1);
unique_vec.Add(1);
unique_vec.Add(2);
const std::vector<int>& vec = unique_vec;
EXPECT_EQ(vec.size(), 3u);
EXPECT_EQ(unique_vec.empty(), false);
const utils::Vector<int, 4>& vec = unique_vec;
EXPECT_EQ(vec.Length(), 3u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
int i = 0;
for (auto n : vec) {
EXPECT_EQ(n, i);
@@ -106,46 +109,46 @@ TEST(UniqueVectorTest, AsVector) {
}
TEST(UniqueVectorTest, PopBack) {
UniqueVector<int> unique_vec;
unique_vec.add(0);
unique_vec.add(2);
unique_vec.add(1);
UniqueVector<int, 4> unique_vec;
unique_vec.Add(0);
unique_vec.Add(2);
unique_vec.Add(1);
EXPECT_EQ(unique_vec.pop_back(), 1);
EXPECT_EQ(unique_vec.size(), 2u);
EXPECT_EQ(unique_vec.empty(), false);
EXPECT_EQ(unique_vec.Pop(), 1);
EXPECT_EQ(unique_vec.Length(), 2u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 2);
EXPECT_EQ(unique_vec.pop_back(), 2);
EXPECT_EQ(unique_vec.size(), 1u);
EXPECT_EQ(unique_vec.empty(), false);
EXPECT_EQ(unique_vec.Pop(), 2);
EXPECT_EQ(unique_vec.Length(), 1u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
unique_vec.add(1);
unique_vec.Add(1);
EXPECT_EQ(unique_vec.size(), 2u);
EXPECT_EQ(unique_vec.empty(), false);
EXPECT_EQ(unique_vec.Length(), 2u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec[1], 1);
EXPECT_EQ(unique_vec.pop_back(), 1);
EXPECT_EQ(unique_vec.size(), 1u);
EXPECT_EQ(unique_vec.empty(), false);
EXPECT_EQ(unique_vec.Pop(), 1);
EXPECT_EQ(unique_vec.Length(), 1u);
EXPECT_EQ(unique_vec.IsEmpty(), false);
EXPECT_EQ(unique_vec[0], 0);
EXPECT_EQ(unique_vec.pop_back(), 0);
EXPECT_EQ(unique_vec.size(), 0u);
EXPECT_EQ(unique_vec.empty(), true);
EXPECT_EQ(unique_vec.Pop(), 0);
EXPECT_EQ(unique_vec.Length(), 0u);
EXPECT_EQ(unique_vec.IsEmpty(), true);
}
TEST(UniqueVectorTest, Data) {
UniqueVector<int> unique_vec;
EXPECT_EQ(unique_vec.data(), nullptr);
UniqueVector<int, 4> unique_vec;
EXPECT_EQ(unique_vec.Data(), nullptr);
unique_vec.add(42);
EXPECT_EQ(unique_vec.data(), &unique_vec[0]);
EXPECT_EQ(*unique_vec.data(), 42);
unique_vec.Add(42);
EXPECT_EQ(unique_vec.Data(), &unique_vec[0]);
EXPECT_EQ(*unique_vec.Data(), 42);
}
} // namespace