Add utils/unique_vector.h from TypeDeterminer

Add tests.

Change-Id: I064fbbe2387ebe980776ee99ed2ff48d6ea5d5b5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41621
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 008ce14..2a9376c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -269,6 +269,7 @@
   type/vector_type.h
   type/void_type.cc
   type/void_type.h
+  utils/unique_vector.h
   validator/validator.cc
   validator/validator.h
   validator/validator_impl.cc
@@ -492,6 +493,7 @@
     type/type_manager_test.cc
     type/u32_type_test.cc
     type/vector_type_test.cc
+    utils/unique_vector_test.cc
     validator/validator_builtins_test.cc
     validator/validator_control_block_test.cc
     validator/validator_function_test.cc
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index a72c3ab..3e0a797 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -125,9 +125,9 @@
     return;
   }
 
-  current_function_->referenced_module_vars.Add(var);
+  current_function_->referenced_module_vars.add(var);
   if (local) {
-    current_function_->local_referenced_module_vars.Add(var);
+    current_function_->local_referenced_module_vars.add(var);
   }
 }
 
@@ -172,7 +172,7 @@
 
 void TypeDeterminer::set_entry_points(const Symbol& fn_sym, Symbol ep_sym) {
   auto* info = symbol_to_function_.at(fn_sym);
-  info->ancestor_entry_points.Add(ep_sym);
+  info->ancestor_entry_points.add(ep_sym);
 
   for (const auto& callee : caller_to_callee_[fn_sym]) {
     set_entry_points(callee, ep_sym);
diff --git a/src/type_determiner.h b/src/type_determiner.h
index b03b1d5..f661c27 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -28,6 +28,7 @@
 #include "src/scope_stack.h"
 #include "src/semantic/intrinsic.h"
 #include "src/type/storage_texture_type.h"
+#include "src/utils/unique_vector.h"
 
 namespace tint {
 
@@ -78,26 +79,6 @@
   static semantic::IntrinsicType MatchIntrinsicType(const std::string& name);
 
  private:
-  template <typename T>
-  struct UniqueVector {
-    using ConstIterator = typename std::vector<T>::const_iterator;
-
-    void Add(const T& val) {
-      if (set.count(val) == 0) {
-        vector.emplace_back(val);
-        set.emplace(val);
-      }
-    }
-    size_t size() const { return vector.size(); }
-    ConstIterator begin() const { return vector.begin(); }
-    ConstIterator end() const { return vector.end(); }
-    operator const std::vector<T> &() const { return vector; }
-
-   private:
-    std::vector<T> vector;
-    std::unordered_set<T> set;
-  };
-
   /// Structure holding semantic information about a variable.
   /// Used to build the semantic::Variable nodes at the end of resolving.
   struct VariableInfo {
diff --git a/src/utils/unique_vector.h b/src/utils/unique_vector.h
new file mode 100644
index 0000000..36016ee
--- /dev/null
+++ b/src/utils/unique_vector.h
@@ -0,0 +1,59 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_UTILS_UNIQUE_VECTOR_H_
+#define SRC_UTILS_UNIQUE_VECTOR_H_
+
+#include <unordered_set>
+#include <vector>
+
+namespace tint {
+
+/// UniqueVector is an ordered container that only contains unique items.
+/// Attempting to add a duplicate is a no-op.
+template <typename T>
+struct UniqueVector {
+  /// The iterator returned by begin() and end()
+  using ConstIterator = typename std::vector<T>::const_iterator;
+
+  /// add appends the item to the end of the vector, if the vector does not
+  /// already contain the given item.
+  /// @param item the item to append to the end of the vector
+  void add(const T& item) {
+    if (set.count(item) == 0) {
+      vector.emplace_back(item);
+      set.emplace(item);
+    }
+  }
+
+  /// @returns the number of items in the vector
+  size_t size() const { return vector.size(); }
+
+  /// @returns an iterator to the beginning of the vector
+  ConstIterator begin() const { return vector.begin(); }
+
+  /// @returns an iterator to the end of the vector
+  ConstIterator end() const { return vector.end(); }
+
+  /// @returns a const reference to the internal vector
+  operator const std::vector<T> &() const { return vector; }
+
+ private:
+  std::vector<T> vector;
+  std::unordered_set<T> set;
+};
+
+}  // namespace tint
+
+#endif  //  SRC_UTILS_UNIQUE_VECTOR_H_
diff --git a/src/utils/unique_vector_test.cc b/src/utils/unique_vector_test.cc
new file mode 100644
index 0000000..83f19e5
--- /dev/null
+++ b/src/utils/unique_vector_test.cc
@@ -0,0 +1,76 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/unique_vector.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace {
+
+TEST(UniqueVectorTest, Empty) {
+  UniqueVector<int> unique_vec;
+  EXPECT_EQ(unique_vec.size(), 0u);
+  EXPECT_EQ(unique_vec.begin(), unique_vec.end());
+}
+
+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);
+  int i = 0;
+  for (auto n : unique_vec) {
+    EXPECT_EQ(n, i);
+    i++;
+  }
+}
+
+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);
+  int i = 0;
+  for (auto n : unique_vec) {
+    EXPECT_EQ(n, i);
+    i++;
+  }
+}
+
+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);
+
+  const std::vector<int>& vec = unique_vec;
+  EXPECT_EQ(vec.size(), 3u);
+  int i = 0;
+  for (auto n : vec) {
+    EXPECT_EQ(n, i);
+    i++;
+  }
+}
+
+}  // namespace
+}  // namespace tint