tint/utils: Add operator<<() support to vector

Helpful for tests and the like.

Change-Id: I07f8c59af6db4d6a5629dca2dc985398b75eccf9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/111760
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/sem/binding_point.h b/src/tint/sem/binding_point.h
index b779b73..78403ab 100644
--- a/src/tint/sem/binding_point.h
+++ b/src/tint/sem/binding_point.h
@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include <functional>
+#include <ostream>
 
 #include "src/tint/reflection.h"
 #include "src/tint/utils/hash.h"
@@ -47,6 +48,14 @@
     inline bool operator!=(const BindingPoint& rhs) const { return !(*this == rhs); }
 };
 
+/// Prints the BindingPoint @p bp to @p o
+/// @param o the std::ostream to write to
+/// @param bp the BindingPoint
+/// @return the std::ostream so calls can be chained
+inline std::ostream& operator<<(std::ostream& o, const BindingPoint& bp) {
+    return o << "[group: " << bp.group << ", binding: " << bp.binding << "]";
+}
+
 }  // namespace tint::sem
 
 namespace std {
diff --git a/src/tint/sem/sampler_texture_pair.h b/src/tint/sem/sampler_texture_pair.h
index 71f3e3c..b3cf4f2 100644
--- a/src/tint/sem/sampler_texture_pair.h
+++ b/src/tint/sem/sampler_texture_pair.h
@@ -17,6 +17,7 @@
 
 #include <cstdint>
 #include <functional>
+#include <ostream>
 
 #include "src/tint/sem/binding_point.h"
 
@@ -43,6 +44,15 @@
     inline bool operator!=(const SamplerTexturePair& rhs) const { return !(*this == rhs); }
 };
 
+/// Prints the SamplerTexturePair @p stp to @p o
+/// @param o the std::ostream to write to
+/// @param stp the SamplerTexturePair
+/// @return the std::ostream so calls can be chained
+inline std::ostream& operator<<(std::ostream& o, const SamplerTexturePair& stp) {
+    return o << "[sampler: " << stp.sampler_binding_point
+             << ", texture: " << stp.sampler_binding_point << "]";
+}
+
 }  // namespace tint::sem
 
 namespace std {
diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h
index dd37396..abfe51a 100644
--- a/src/tint/utils/string.h
+++ b/src/tint/utils/string.h
@@ -17,6 +17,7 @@
 
 #include <sstream>
 #include <string>
+#include <variant>
 
 namespace tint::utils {
 
@@ -44,6 +45,15 @@
     return s.str();
 }
 
+/// @param value the variant to be printed as a string
+/// @returns value printed as a string via the std::ostream `<<` operator
+template <typename... TYs>
+std::string ToString(const std::variant<TYs...>& value) {
+    std::stringstream s;
+    s << std::visit([&](auto& v) { return ToString(v); }, value);
+    return s.str();
+}
+
 /// @param str the input string
 /// @param prefix the prefix string
 /// @returns true iff @p str has the prefix @p prefix
diff --git a/src/tint/utils/vector.h b/src/tint/utils/vector.h
index 705817a..ecee170 100644
--- a/src/tint/utils/vector.h
+++ b/src/tint/utils/vector.h
@@ -20,12 +20,14 @@
 #include <algorithm>
 #include <array>
 #include <iterator>
+#include <ostream>
 #include <utility>
 #include <vector>
 
 #include "src/tint/castable.h"
 #include "src/tint/traits.h"
 #include "src/tint/utils/bitcast.h"
+#include "src/tint/utils/string.h"
 
 namespace tint::utils {
 
@@ -832,6 +834,44 @@
     return out;
 }
 
+/// Prints the vector @p vec to @p o
+/// @param o the std::ostream to write to
+/// @param vec the vector
+/// @return the std::ostream so calls can be chained
+template <typename T, size_t N>
+inline std::ostream& operator<<(std::ostream& o, const utils::Vector<T, N>& vec) {
+    o << "[";
+    bool first = true;
+    for (auto& el : vec) {
+        if (!first) {
+            o << ", ";
+        }
+        first = false;
+        o << ToString(el);
+    }
+    o << "]";
+    return o;
+}
+
+/// Prints the vector @p vec to @p o
+/// @param o the std::ostream to write to
+/// @param vec the vector reference
+/// @return the std::ostream so calls can be chained
+template <typename T>
+inline std::ostream& operator<<(std::ostream& o, const utils::VectorRef<T>& vec) {
+    o << "[";
+    bool first = true;
+    for (auto& el : vec) {
+        if (!first) {
+            o << ", ";
+        }
+        first = false;
+        o << ToString(el);
+    }
+    o << "]";
+    return o;
+}
+
 }  // namespace tint::utils
 
 #endif  // SRC_TINT_UTILS_VECTOR_H_
diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc
index a3cc1f7..9a9bb4b 100644
--- a/src/tint/utils/vector_test.cc
+++ b/src/tint/utils/vector_test.cc
@@ -1795,6 +1795,21 @@
     EXPECT_EQ(vec.end(), &vec[0] + 3);
 }
 
+TEST(TintVectorTest, Equality) {
+    EXPECT_EQ((Vector<int, 2>{1, 2}), (Vector<int, 2>{1, 2}));
+    EXPECT_EQ((Vector<int, 1>{1, 2}), (Vector<int, 3>{1, 2}));
+    EXPECT_NE((Vector{1, 2}), (Vector{1}));
+    EXPECT_NE((Vector{1}), (Vector{1, 2}));
+    EXPECT_NE((Vector{1, 2}), (Vector{2, 1}));
+    EXPECT_NE((Vector{2, 1}), (Vector{1, 2}));
+}
+
+TEST(TintVectorTest, ostream) {
+    std::stringstream ss;
+    ss << Vector{1, 2, 3};
+    EXPECT_EQ(ss.str(), "[1, 2, 3]");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TintVectorRefTest
 ////////////////////////////////////////////////////////////////////////////////
@@ -2060,15 +2075,13 @@
     EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
 }
 
-TEST(TintVectorTest, Equality) {
-    EXPECT_EQ((Vector<int, 2>{1, 2}), (Vector<int, 2>{1, 2}));
-    EXPECT_EQ((Vector<int, 1>{1, 2}), (Vector<int, 3>{1, 2}));
-    EXPECT_NE((Vector{1, 2}), (Vector{1}));
-    EXPECT_NE((Vector{1}), (Vector{1, 2}));
-    EXPECT_NE((Vector{1, 2}), (Vector{2, 1}));
-    EXPECT_NE((Vector{2, 1}), (Vector{1, 2}));
+TEST(TintVectorRefTest, ostream) {
+    std::stringstream ss;
+    Vector vec{1, 2, 3};
+    const VectorRef<int> vec_ref(vec);
+    ss << vec_ref;
+    EXPECT_EQ(ss.str(), "[1, 2, 3]");
 }
-
 }  // namespace
 }  // namespace tint::utils