[tint] Make LHS of operator << generic.
Breaks a circular dependency in utils, and allows for << to work with
other stream types.
Change-Id: Ia001def89fb1db9dd4aa582ae516911ba8aa71f1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/143383
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/include/tint/binding_point.h b/include/tint/binding_point.h
index e5d3d14..11c47d5 100644
--- a/include/tint/binding_point.h
+++ b/include/tint/binding_point.h
@@ -65,7 +65,8 @@
/// @param o the stream to write to
/// @param bp the BindingPoint
/// @return the stream so calls can be chained
-inline StringStream& operator<<(StringStream& o, const BindingPoint& bp) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const BindingPoint& bp) {
return o << "[group: " << bp.group << ", binding: " << bp.binding << "]";
}
diff --git a/src/tint/lang/core/builtin/access.cc b/src/tint/lang/core/builtin/access.cc
index 01b1604..9ef6629 100644
--- a/src/tint/lang/core/builtin/access.cc
+++ b/src/tint/lang/core/builtin/access.cc
@@ -40,18 +40,18 @@
return Access::kUndefined;
}
-StringStream& operator<<(StringStream& out, Access value) {
+std::string_view ToString(Access value) {
switch (value) {
case Access::kUndefined:
- return out << "undefined";
+ return "undefined";
case Access::kRead:
- return out << "read";
+ return "read";
case Access::kReadWrite:
- return out << "read_write";
+ return "read_write";
case Access::kWrite:
- return out << "write";
+ return "write";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/access.h b/src/tint/lang/core/builtin/access.h
index 1b52fec..ab98a42 100644
--- a/src/tint/lang/core/builtin/access.h
+++ b/src/tint/lang/core/builtin/access.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ACCESS_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ACCESS_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -35,10 +35,17 @@
kWrite,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(Access value);
+
/// @param out the stream to write to
/// @param value the Access
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, Access value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Access value) {
+ return out << ToString(value);
+}
/// ParseAccess parses a Access from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/access.h.tmpl b/src/tint/lang/core/builtin/access.h.tmpl
index e655b3a..8d28e7d 100644
--- a/src/tint/lang/core/builtin/access.h.tmpl
+++ b/src/tint/lang/core/builtin/access.h.tmpl
@@ -17,7 +17,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ACCESS_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ACCESS_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/address_space.cc b/src/tint/lang/core/builtin/address_space.cc
index 7081cab..ad41f1d 100644
--- a/src/tint/lang/core/builtin/address_space.cc
+++ b/src/tint/lang/core/builtin/address_space.cc
@@ -55,30 +55,30 @@
return AddressSpace::kUndefined;
}
-StringStream& operator<<(StringStream& out, AddressSpace value) {
+std::string_view ToString(AddressSpace value) {
switch (value) {
case AddressSpace::kUndefined:
- return out << "undefined";
+ return "undefined";
case AddressSpace::kIn:
- return out << "__in";
+ return "__in";
case AddressSpace::kOut:
- return out << "__out";
+ return "__out";
case AddressSpace::kFunction:
- return out << "function";
+ return "function";
case AddressSpace::kHandle:
- return out << "handle";
+ return "handle";
case AddressSpace::kPrivate:
- return out << "private";
+ return "private";
case AddressSpace::kPushConstant:
- return out << "push_constant";
+ return "push_constant";
case AddressSpace::kStorage:
- return out << "storage";
+ return "storage";
case AddressSpace::kUniform:
- return out << "uniform";
+ return "uniform";
case AddressSpace::kWorkgroup:
- return out << "workgroup";
+ return "workgroup";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/address_space.h b/src/tint/lang/core/builtin/address_space.h
index 1ac2c21..2f5e350 100644
--- a/src/tint/lang/core/builtin/address_space.h
+++ b/src/tint/lang/core/builtin/address_space.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ADDRESS_SPACE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ADDRESS_SPACE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -41,10 +41,17 @@
kWorkgroup,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(AddressSpace value);
+
/// @param out the stream to write to
/// @param value the AddressSpace
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, AddressSpace value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, AddressSpace value) {
+ return out << ToString(value);
+}
/// ParseAddressSpace parses a AddressSpace from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/address_space.h.tmpl b/src/tint/lang/core/builtin/address_space.h.tmpl
index 6c80473..8c9c918 100644
--- a/src/tint/lang/core/builtin/address_space.h.tmpl
+++ b/src/tint/lang/core/builtin/address_space.h.tmpl
@@ -17,7 +17,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ADDRESS_SPACE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ADDRESS_SPACE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/attribute.cc b/src/tint/lang/core/builtin/attribute.cc
index f7c7596..de547f7 100644
--- a/src/tint/lang/core/builtin/attribute.cc
+++ b/src/tint/lang/core/builtin/attribute.cc
@@ -79,44 +79,44 @@
return Attribute::kUndefined;
}
-StringStream& operator<<(StringStream& out, Attribute value) {
+std::string_view ToString(Attribute value) {
switch (value) {
case Attribute::kUndefined:
- return out << "undefined";
+ return "undefined";
case Attribute::kAlign:
- return out << "align";
+ return "align";
case Attribute::kBinding:
- return out << "binding";
+ return "binding";
case Attribute::kBuiltin:
- return out << "builtin";
+ return "builtin";
case Attribute::kCompute:
- return out << "compute";
+ return "compute";
case Attribute::kDiagnostic:
- return out << "diagnostic";
+ return "diagnostic";
case Attribute::kFragment:
- return out << "fragment";
+ return "fragment";
case Attribute::kGroup:
- return out << "group";
+ return "group";
case Attribute::kId:
- return out << "id";
+ return "id";
case Attribute::kIndex:
- return out << "index";
+ return "index";
case Attribute::kInterpolate:
- return out << "interpolate";
+ return "interpolate";
case Attribute::kInvariant:
- return out << "invariant";
+ return "invariant";
case Attribute::kLocation:
- return out << "location";
+ return "location";
case Attribute::kMustUse:
- return out << "must_use";
+ return "must_use";
case Attribute::kSize:
- return out << "size";
+ return "size";
case Attribute::kVertex:
- return out << "vertex";
+ return "vertex";
case Attribute::kWorkgroupSize:
- return out << "workgroup_size";
+ return "workgroup_size";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/attribute.h b/src/tint/lang/core/builtin/attribute.h
index 1914f41..df411f1 100644
--- a/src/tint/lang/core/builtin/attribute.h
+++ b/src/tint/lang/core/builtin/attribute.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ATTRIBUTE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ATTRIBUTE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
/// \cond DO_NOT_DOCUMENT
/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
@@ -51,10 +51,17 @@
kWorkgroupSize,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(Attribute value);
+
/// @param out the stream to write to
/// @param value the Attribute
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, Attribute value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Attribute value) {
+ return out << ToString(value);
+}
/// ParseAttribute parses a Attribute from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/attribute.h.tmpl b/src/tint/lang/core/builtin/attribute.h.tmpl
index 34954d1..02def09 100644
--- a/src/tint/lang/core/builtin/attribute.h.tmpl
+++ b/src/tint/lang/core/builtin/attribute.h.tmpl
@@ -17,7 +17,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_ATTRIBUTE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_ATTRIBUTE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
/// \cond DO_NOT_DOCUMENT
/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
diff --git a/src/tint/lang/core/builtin/builtin.cc b/src/tint/lang/core/builtin/builtin.cc
index 3cd8fb6..6c9f0e9 100644
--- a/src/tint/lang/core/builtin/builtin.cc
+++ b/src/tint/lang/core/builtin/builtin.cc
@@ -319,204 +319,204 @@
return Builtin::kUndefined;
}
-StringStream& operator<<(StringStream& out, Builtin value) {
+std::string_view ToString(Builtin value) {
switch (value) {
case Builtin::kUndefined:
- return out << "undefined";
+ return "undefined";
case Builtin::kAtomicCompareExchangeResultI32:
- return out << "__atomic_compare_exchange_result_i32";
+ return "__atomic_compare_exchange_result_i32";
case Builtin::kAtomicCompareExchangeResultU32:
- return out << "__atomic_compare_exchange_result_u32";
+ return "__atomic_compare_exchange_result_u32";
case Builtin::kFrexpResultAbstract:
- return out << "__frexp_result_abstract";
+ return "__frexp_result_abstract";
case Builtin::kFrexpResultF16:
- return out << "__frexp_result_f16";
+ return "__frexp_result_f16";
case Builtin::kFrexpResultF32:
- return out << "__frexp_result_f32";
+ return "__frexp_result_f32";
case Builtin::kFrexpResultVec2Abstract:
- return out << "__frexp_result_vec2_abstract";
+ return "__frexp_result_vec2_abstract";
case Builtin::kFrexpResultVec2F16:
- return out << "__frexp_result_vec2_f16";
+ return "__frexp_result_vec2_f16";
case Builtin::kFrexpResultVec2F32:
- return out << "__frexp_result_vec2_f32";
+ return "__frexp_result_vec2_f32";
case Builtin::kFrexpResultVec3Abstract:
- return out << "__frexp_result_vec3_abstract";
+ return "__frexp_result_vec3_abstract";
case Builtin::kFrexpResultVec3F16:
- return out << "__frexp_result_vec3_f16";
+ return "__frexp_result_vec3_f16";
case Builtin::kFrexpResultVec3F32:
- return out << "__frexp_result_vec3_f32";
+ return "__frexp_result_vec3_f32";
case Builtin::kFrexpResultVec4Abstract:
- return out << "__frexp_result_vec4_abstract";
+ return "__frexp_result_vec4_abstract";
case Builtin::kFrexpResultVec4F16:
- return out << "__frexp_result_vec4_f16";
+ return "__frexp_result_vec4_f16";
case Builtin::kFrexpResultVec4F32:
- return out << "__frexp_result_vec4_f32";
+ return "__frexp_result_vec4_f32";
case Builtin::kModfResultAbstract:
- return out << "__modf_result_abstract";
+ return "__modf_result_abstract";
case Builtin::kModfResultF16:
- return out << "__modf_result_f16";
+ return "__modf_result_f16";
case Builtin::kModfResultF32:
- return out << "__modf_result_f32";
+ return "__modf_result_f32";
case Builtin::kModfResultVec2Abstract:
- return out << "__modf_result_vec2_abstract";
+ return "__modf_result_vec2_abstract";
case Builtin::kModfResultVec2F16:
- return out << "__modf_result_vec2_f16";
+ return "__modf_result_vec2_f16";
case Builtin::kModfResultVec2F32:
- return out << "__modf_result_vec2_f32";
+ return "__modf_result_vec2_f32";
case Builtin::kModfResultVec3Abstract:
- return out << "__modf_result_vec3_abstract";
+ return "__modf_result_vec3_abstract";
case Builtin::kModfResultVec3F16:
- return out << "__modf_result_vec3_f16";
+ return "__modf_result_vec3_f16";
case Builtin::kModfResultVec3F32:
- return out << "__modf_result_vec3_f32";
+ return "__modf_result_vec3_f32";
case Builtin::kModfResultVec4Abstract:
- return out << "__modf_result_vec4_abstract";
+ return "__modf_result_vec4_abstract";
case Builtin::kModfResultVec4F16:
- return out << "__modf_result_vec4_f16";
+ return "__modf_result_vec4_f16";
case Builtin::kModfResultVec4F32:
- return out << "__modf_result_vec4_f32";
+ return "__modf_result_vec4_f32";
case Builtin::kPackedVec3:
- return out << "__packed_vec3";
+ return "__packed_vec3";
case Builtin::kArray:
- return out << "array";
+ return "array";
case Builtin::kAtomic:
- return out << "atomic";
+ return "atomic";
case Builtin::kBool:
- return out << "bool";
+ return "bool";
case Builtin::kF16:
- return out << "f16";
+ return "f16";
case Builtin::kF32:
- return out << "f32";
+ return "f32";
case Builtin::kI32:
- return out << "i32";
+ return "i32";
case Builtin::kMat2X2:
- return out << "mat2x2";
+ return "mat2x2";
case Builtin::kMat2X2F:
- return out << "mat2x2f";
+ return "mat2x2f";
case Builtin::kMat2X2H:
- return out << "mat2x2h";
+ return "mat2x2h";
case Builtin::kMat2X3:
- return out << "mat2x3";
+ return "mat2x3";
case Builtin::kMat2X3F:
- return out << "mat2x3f";
+ return "mat2x3f";
case Builtin::kMat2X3H:
- return out << "mat2x3h";
+ return "mat2x3h";
case Builtin::kMat2X4:
- return out << "mat2x4";
+ return "mat2x4";
case Builtin::kMat2X4F:
- return out << "mat2x4f";
+ return "mat2x4f";
case Builtin::kMat2X4H:
- return out << "mat2x4h";
+ return "mat2x4h";
case Builtin::kMat3X2:
- return out << "mat3x2";
+ return "mat3x2";
case Builtin::kMat3X2F:
- return out << "mat3x2f";
+ return "mat3x2f";
case Builtin::kMat3X2H:
- return out << "mat3x2h";
+ return "mat3x2h";
case Builtin::kMat3X3:
- return out << "mat3x3";
+ return "mat3x3";
case Builtin::kMat3X3F:
- return out << "mat3x3f";
+ return "mat3x3f";
case Builtin::kMat3X3H:
- return out << "mat3x3h";
+ return "mat3x3h";
case Builtin::kMat3X4:
- return out << "mat3x4";
+ return "mat3x4";
case Builtin::kMat3X4F:
- return out << "mat3x4f";
+ return "mat3x4f";
case Builtin::kMat3X4H:
- return out << "mat3x4h";
+ return "mat3x4h";
case Builtin::kMat4X2:
- return out << "mat4x2";
+ return "mat4x2";
case Builtin::kMat4X2F:
- return out << "mat4x2f";
+ return "mat4x2f";
case Builtin::kMat4X2H:
- return out << "mat4x2h";
+ return "mat4x2h";
case Builtin::kMat4X3:
- return out << "mat4x3";
+ return "mat4x3";
case Builtin::kMat4X3F:
- return out << "mat4x3f";
+ return "mat4x3f";
case Builtin::kMat4X3H:
- return out << "mat4x3h";
+ return "mat4x3h";
case Builtin::kMat4X4:
- return out << "mat4x4";
+ return "mat4x4";
case Builtin::kMat4X4F:
- return out << "mat4x4f";
+ return "mat4x4f";
case Builtin::kMat4X4H:
- return out << "mat4x4h";
+ return "mat4x4h";
case Builtin::kPtr:
- return out << "ptr";
+ return "ptr";
case Builtin::kSampler:
- return out << "sampler";
+ return "sampler";
case Builtin::kSamplerComparison:
- return out << "sampler_comparison";
+ return "sampler_comparison";
case Builtin::kTexture1D:
- return out << "texture_1d";
+ return "texture_1d";
case Builtin::kTexture2D:
- return out << "texture_2d";
+ return "texture_2d";
case Builtin::kTexture2DArray:
- return out << "texture_2d_array";
+ return "texture_2d_array";
case Builtin::kTexture3D:
- return out << "texture_3d";
+ return "texture_3d";
case Builtin::kTextureCube:
- return out << "texture_cube";
+ return "texture_cube";
case Builtin::kTextureCubeArray:
- return out << "texture_cube_array";
+ return "texture_cube_array";
case Builtin::kTextureDepth2D:
- return out << "texture_depth_2d";
+ return "texture_depth_2d";
case Builtin::kTextureDepth2DArray:
- return out << "texture_depth_2d_array";
+ return "texture_depth_2d_array";
case Builtin::kTextureDepthCube:
- return out << "texture_depth_cube";
+ return "texture_depth_cube";
case Builtin::kTextureDepthCubeArray:
- return out << "texture_depth_cube_array";
+ return "texture_depth_cube_array";
case Builtin::kTextureDepthMultisampled2D:
- return out << "texture_depth_multisampled_2d";
+ return "texture_depth_multisampled_2d";
case Builtin::kTextureExternal:
- return out << "texture_external";
+ return "texture_external";
case Builtin::kTextureMultisampled2D:
- return out << "texture_multisampled_2d";
+ return "texture_multisampled_2d";
case Builtin::kTextureStorage1D:
- return out << "texture_storage_1d";
+ return "texture_storage_1d";
case Builtin::kTextureStorage2D:
- return out << "texture_storage_2d";
+ return "texture_storage_2d";
case Builtin::kTextureStorage2DArray:
- return out << "texture_storage_2d_array";
+ return "texture_storage_2d_array";
case Builtin::kTextureStorage3D:
- return out << "texture_storage_3d";
+ return "texture_storage_3d";
case Builtin::kU32:
- return out << "u32";
+ return "u32";
case Builtin::kVec2:
- return out << "vec2";
+ return "vec2";
case Builtin::kVec2F:
- return out << "vec2f";
+ return "vec2f";
case Builtin::kVec2H:
- return out << "vec2h";
+ return "vec2h";
case Builtin::kVec2I:
- return out << "vec2i";
+ return "vec2i";
case Builtin::kVec2U:
- return out << "vec2u";
+ return "vec2u";
case Builtin::kVec3:
- return out << "vec3";
+ return "vec3";
case Builtin::kVec3F:
- return out << "vec3f";
+ return "vec3f";
case Builtin::kVec3H:
- return out << "vec3h";
+ return "vec3h";
case Builtin::kVec3I:
- return out << "vec3i";
+ return "vec3i";
case Builtin::kVec3U:
- return out << "vec3u";
+ return "vec3u";
case Builtin::kVec4:
- return out << "vec4";
+ return "vec4";
case Builtin::kVec4F:
- return out << "vec4f";
+ return "vec4f";
case Builtin::kVec4H:
- return out << "vec4h";
+ return "vec4h";
case Builtin::kVec4I:
- return out << "vec4i";
+ return "vec4i";
case Builtin::kVec4U:
- return out << "vec4u";
+ return "vec4u";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/builtin.h b/src/tint/lang/core/builtin/builtin.h
index e22855d..e2bd05a 100644
--- a/src/tint/lang/core/builtin/builtin.h
+++ b/src/tint/lang/core/builtin/builtin.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_H_
#define SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -128,10 +128,17 @@
kVec4U,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(Builtin value);
+
/// @param out the stream to write to
/// @param value the Builtin
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, Builtin value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Builtin value) {
+ return out << ToString(value);
+}
/// ParseBuiltin parses a Builtin from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/builtin.h.tmpl b/src/tint/lang/core/builtin/builtin.h.tmpl
index 3ceeb2e..308fdbb 100644
--- a/src/tint/lang/core/builtin/builtin.h.tmpl
+++ b/src/tint/lang/core/builtin/builtin.h.tmpl
@@ -18,7 +18,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_H_
#define SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/builtin_value.cc b/src/tint/lang/core/builtin/builtin_value.cc
index 8107369..644a217 100644
--- a/src/tint/lang/core/builtin/builtin_value.cc
+++ b/src/tint/lang/core/builtin/builtin_value.cc
@@ -70,38 +70,38 @@
return BuiltinValue::kUndefined;
}
-StringStream& operator<<(StringStream& out, BuiltinValue value) {
+std::string_view ToString(BuiltinValue value) {
switch (value) {
case BuiltinValue::kUndefined:
- return out << "undefined";
+ return "undefined";
case BuiltinValue::kPointSize:
- return out << "__point_size";
+ return "__point_size";
case BuiltinValue::kFragDepth:
- return out << "frag_depth";
+ return "frag_depth";
case BuiltinValue::kFrontFacing:
- return out << "front_facing";
+ return "front_facing";
case BuiltinValue::kGlobalInvocationId:
- return out << "global_invocation_id";
+ return "global_invocation_id";
case BuiltinValue::kInstanceIndex:
- return out << "instance_index";
+ return "instance_index";
case BuiltinValue::kLocalInvocationId:
- return out << "local_invocation_id";
+ return "local_invocation_id";
case BuiltinValue::kLocalInvocationIndex:
- return out << "local_invocation_index";
+ return "local_invocation_index";
case BuiltinValue::kNumWorkgroups:
- return out << "num_workgroups";
+ return "num_workgroups";
case BuiltinValue::kPosition:
- return out << "position";
+ return "position";
case BuiltinValue::kSampleIndex:
- return out << "sample_index";
+ return "sample_index";
case BuiltinValue::kSampleMask:
- return out << "sample_mask";
+ return "sample_mask";
case BuiltinValue::kVertexIndex:
- return out << "vertex_index";
+ return "vertex_index";
case BuiltinValue::kWorkgroupId:
- return out << "workgroup_id";
+ return "workgroup_id";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/builtin_value.h b/src/tint/lang/core/builtin/builtin_value.h
index 5d33d96..ef527f3 100644
--- a/src/tint/lang/core/builtin/builtin_value.h
+++ b/src/tint/lang/core/builtin/builtin_value.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_VALUE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_VALUE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -45,10 +45,17 @@
kWorkgroupId,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(BuiltinValue value);
+
/// @param out the stream to write to
/// @param value the BuiltinValue
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, BuiltinValue value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, BuiltinValue value) {
+ return out << ToString(value);
+}
/// ParseBuiltinValue parses a BuiltinValue from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/builtin_value.h.tmpl b/src/tint/lang/core/builtin/builtin_value.h.tmpl
index e3b0ccc..96643ed 100644
--- a/src/tint/lang/core/builtin/builtin_value.h.tmpl
+++ b/src/tint/lang/core/builtin/builtin_value.h.tmpl
@@ -14,7 +14,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_VALUE_H_
#define SRC_TINT_LANG_CORE_BUILTIN_BUILTIN_VALUE_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/diagnostic_rule.cc b/src/tint/lang/core/builtin/diagnostic_rule.cc
index 496bf0d..0d1f0e7 100644
--- a/src/tint/lang/core/builtin/diagnostic_rule.cc
+++ b/src/tint/lang/core/builtin/diagnostic_rule.cc
@@ -24,7 +24,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -38,14 +38,14 @@
return CoreDiagnosticRule::kUndefined;
}
-StringStream& operator<<(StringStream& out, CoreDiagnosticRule value) {
+std::string_view ToString(CoreDiagnosticRule value) {
switch (value) {
case CoreDiagnosticRule::kUndefined:
- return out << "undefined";
+ return "undefined";
case CoreDiagnosticRule::kDerivativeUniformity:
- return out << "derivative_uniformity";
+ return "derivative_uniformity";
}
- return out << "<unknown>";
+ return "<unknown>";
}
/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
@@ -59,14 +59,14 @@
return ChromiumDiagnosticRule::kUndefined;
}
-StringStream& operator<<(StringStream& out, ChromiumDiagnosticRule value) {
+std::string_view ToString(ChromiumDiagnosticRule value) {
switch (value) {
case ChromiumDiagnosticRule::kUndefined:
- return out << "undefined";
+ return "undefined";
case ChromiumDiagnosticRule::kUnreachableCode:
- return out << "unreachable_code";
+ return "unreachable_code";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/diagnostic_rule.cc.tmpl b/src/tint/lang/core/builtin/diagnostic_rule.cc.tmpl
index 0094bef..5f40e7c 100644
--- a/src/tint/lang/core/builtin/diagnostic_rule.cc.tmpl
+++ b/src/tint/lang/core/builtin/diagnostic_rule.cc.tmpl
@@ -14,7 +14,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/diagnostic_rule.h b/src/tint/lang/core/builtin/diagnostic_rule.h
index 63d2839..83d0ff1 100644
--- a/src/tint/lang/core/builtin/diagnostic_rule.h
+++ b/src/tint/lang/core/builtin/diagnostic_rule.h
@@ -26,7 +26,7 @@
#include <string>
#include <variant>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -36,10 +36,17 @@
kDerivativeUniformity,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(CoreDiagnosticRule value);
+
/// @param out the stream to write to
/// @param value the CoreDiagnosticRule
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, CoreDiagnosticRule value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, CoreDiagnosticRule value) {
+ return out << ToString(value);
+}
/// ParseCoreDiagnosticRule parses a CoreDiagnosticRule from a string.
/// @param str the string to parse
@@ -56,10 +63,17 @@
kUnreachableCode,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(ChromiumDiagnosticRule value);
+
/// @param out the stream to write to
/// @param value the ChromiumDiagnosticRule
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, ChromiumDiagnosticRule value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, ChromiumDiagnosticRule value) {
+ return out << ToString(value);
+}
/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/diagnostic_rule.h.tmpl b/src/tint/lang/core/builtin/diagnostic_rule.h.tmpl
index 58ac3a4..8b6de0e 100644
--- a/src/tint/lang/core/builtin/diagnostic_rule.h.tmpl
+++ b/src/tint/lang/core/builtin/diagnostic_rule.h.tmpl
@@ -16,7 +16,7 @@
#include <string>
#include <variant>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/diagnostic_severity.cc b/src/tint/lang/core/builtin/diagnostic_severity.cc
index 543ccc8..fb2621a 100644
--- a/src/tint/lang/core/builtin/diagnostic_severity.cc
+++ b/src/tint/lang/core/builtin/diagnostic_severity.cc
@@ -58,20 +58,20 @@
return DiagnosticSeverity::kUndefined;
}
-StringStream& operator<<(StringStream& out, DiagnosticSeverity value) {
+std::string_view ToString(DiagnosticSeverity value) {
switch (value) {
case DiagnosticSeverity::kUndefined:
- return out << "undefined";
+ return "undefined";
case DiagnosticSeverity::kError:
- return out << "error";
+ return "error";
case DiagnosticSeverity::kInfo:
- return out << "info";
+ return "info";
case DiagnosticSeverity::kOff:
- return out << "off";
+ return "off";
case DiagnosticSeverity::kWarning:
- return out << "warning";
+ return "warning";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/diagnostic_severity.h b/src/tint/lang/core/builtin/diagnostic_severity.h
index e866a29..e0a22eb 100644
--- a/src/tint/lang/core/builtin/diagnostic_severity.h
+++ b/src/tint/lang/core/builtin/diagnostic_severity.h
@@ -28,7 +28,7 @@
#include "src/tint/lang/core/builtin/diagnostic_rule.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -41,10 +41,17 @@
kWarning,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(DiagnosticSeverity value);
+
/// @param out the stream to write to
/// @param value the DiagnosticSeverity
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, DiagnosticSeverity value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, DiagnosticSeverity value) {
+ return out << ToString(value);
+}
/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/diagnostic_severity.h.tmpl b/src/tint/lang/core/builtin/diagnostic_severity.h.tmpl
index 7e03cad..f7433bf 100644
--- a/src/tint/lang/core/builtin/diagnostic_severity.h.tmpl
+++ b/src/tint/lang/core/builtin/diagnostic_severity.h.tmpl
@@ -16,7 +16,7 @@
#include <string>
#include <unordered_map>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
#include "src/tint/lang/core/builtin/diagnostic_rule.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
diff --git a/src/tint/lang/core/builtin/extension.cc b/src/tint/lang/core/builtin/extension.cc
index 568743d..5ee7e10 100644
--- a/src/tint/lang/core/builtin/extension.cc
+++ b/src/tint/lang/core/builtin/extension.cc
@@ -52,26 +52,26 @@
return Extension::kUndefined;
}
-StringStream& operator<<(StringStream& out, Extension value) {
+std::string_view ToString(Extension value) {
switch (value) {
case Extension::kUndefined:
- return out << "undefined";
+ return "undefined";
case Extension::kChromiumDisableUniformityAnalysis:
- return out << "chromium_disable_uniformity_analysis";
+ return "chromium_disable_uniformity_analysis";
case Extension::kChromiumExperimentalDp4A:
- return out << "chromium_experimental_dp4a";
+ return "chromium_experimental_dp4a";
case Extension::kChromiumExperimentalFullPtrParameters:
- return out << "chromium_experimental_full_ptr_parameters";
+ return "chromium_experimental_full_ptr_parameters";
case Extension::kChromiumExperimentalPushConstant:
- return out << "chromium_experimental_push_constant";
+ return "chromium_experimental_push_constant";
case Extension::kChromiumInternalDualSourceBlending:
- return out << "chromium_internal_dual_source_blending";
+ return "chromium_internal_dual_source_blending";
case Extension::kChromiumInternalRelaxedUniformLayout:
- return out << "chromium_internal_relaxed_uniform_layout";
+ return "chromium_internal_relaxed_uniform_layout";
case Extension::kF16:
- return out << "f16";
+ return "f16";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/extension.h b/src/tint/lang/core/builtin/extension.h
index cb9f52d..a2640ed 100644
--- a/src/tint/lang/core/builtin/extension.h
+++ b/src/tint/lang/core/builtin/extension.h
@@ -24,7 +24,7 @@
#define SRC_TINT_LANG_CORE_BUILTIN_EXTENSION_H_
#include "src/tint/utils/containers/unique_vector.h"
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -41,10 +41,17 @@
kF16,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(Extension value);
+
/// @param out the stream to write to
/// @param value the Extension
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, Extension value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Extension value) {
+ return out << ToString(value);
+}
/// ParseExtension parses a Extension from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/extension.h.tmpl b/src/tint/lang/core/builtin/extension.h.tmpl
index 860acc1..8d301b9 100644
--- a/src/tint/lang/core/builtin/extension.h.tmpl
+++ b/src/tint/lang/core/builtin/extension.h.tmpl
@@ -14,7 +14,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_EXTENSION_H_
#define SRC_TINT_LANG_CORE_BUILTIN_EXTENSION_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
#include "src/tint/utils/containers/unique_vector.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/function.cc b/src/tint/lang/core/builtin/function.cc
index d194a6e..3d67b07 100644
--- a/src/tint/lang/core/builtin/function.cc
+++ b/src/tint/lang/core/builtin/function.cc
@@ -606,11 +606,6 @@
return "<unknown>";
}
-StringStream& operator<<(StringStream& out, Function i) {
- out << str(i);
- return out;
-}
-
bool IsCoarseDerivativeBuiltin(Function f) {
return f == Function::kDpdxCoarse || f == Function::kDpdyCoarse || f == Function::kFwidthCoarse;
}
diff --git a/src/tint/lang/core/builtin/function.cc.tmpl b/src/tint/lang/core/builtin/function.cc.tmpl
index c98af1e..3e765d5 100644
--- a/src/tint/lang/core/builtin/function.cc.tmpl
+++ b/src/tint/lang/core/builtin/function.cc.tmpl
@@ -36,11 +36,6 @@
return "<unknown>";
}
-StringStream& operator<<(StringStream& out, Function i) {
- out << str(i);
- return out;
-}
-
bool IsCoarseDerivativeBuiltin(Function f) {
return f == Function::kDpdxCoarse || f == Function::kDpdyCoarse ||
f == Function::kFwidthCoarse;
diff --git a/src/tint/lang/core/builtin/function.h b/src/tint/lang/core/builtin/function.h
index d1f45df..1ead560 100644
--- a/src/tint/lang/core/builtin/function.h
+++ b/src/tint/lang/core/builtin/function.h
@@ -25,7 +25,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
// \cond DO_NOT_DOCUMENT
namespace tint::builtin {
@@ -161,7 +161,10 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-StringStream& operator<<(StringStream& out, Function i);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, Function i) {
+ return o << str(i);
+}
/// All builtin functions
constexpr Function kFunctions[] = {
diff --git a/src/tint/lang/core/builtin/function.h.tmpl b/src/tint/lang/core/builtin/function.h.tmpl
index 78d82c4..d6b8fee 100644
--- a/src/tint/lang/core/builtin/function.h.tmpl
+++ b/src/tint/lang/core/builtin/function.h.tmpl
@@ -16,7 +16,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
// \cond DO_NOT_DOCUMENT
namespace tint::builtin {
@@ -41,7 +41,10 @@
/// Emits the name of the builtin function type. The spelling, including case,
/// matches the name in the WGSL spec.
-StringStream& operator<<(StringStream& out, Function i);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, Function i) {
+ return o << str(i);
+}
/// All builtin functions
constexpr Function kFunctions[] = {
diff --git a/src/tint/lang/core/builtin/interpolation_sampling.cc b/src/tint/lang/core/builtin/interpolation_sampling.cc
index e3cf02d..8ffc391 100644
--- a/src/tint/lang/core/builtin/interpolation_sampling.cc
+++ b/src/tint/lang/core/builtin/interpolation_sampling.cc
@@ -43,18 +43,18 @@
return InterpolationSampling::kUndefined;
}
-StringStream& operator<<(StringStream& out, InterpolationSampling value) {
+std::string_view ToString(InterpolationSampling value) {
switch (value) {
case InterpolationSampling::kUndefined:
- return out << "undefined";
+ return "undefined";
case InterpolationSampling::kCenter:
- return out << "center";
+ return "center";
case InterpolationSampling::kCentroid:
- return out << "centroid";
+ return "centroid";
case InterpolationSampling::kSample:
- return out << "sample";
+ return "sample";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/interpolation_sampling.h b/src/tint/lang/core/builtin/interpolation_sampling.h
index 15ef048..e257935 100644
--- a/src/tint/lang/core/builtin/interpolation_sampling.h
+++ b/src/tint/lang/core/builtin/interpolation_sampling.h
@@ -25,7 +25,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -37,10 +37,17 @@
kSample,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(InterpolationSampling value);
+
/// @param out the stream to write to
/// @param value the InterpolationSampling
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, InterpolationSampling value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, InterpolationSampling value) {
+ return out << ToString(value);
+}
/// ParseInterpolationSampling parses a InterpolationSampling from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/interpolation_sampling.h.tmpl b/src/tint/lang/core/builtin/interpolation_sampling.h.tmpl
index eeb51ce..c510fe0 100644
--- a/src/tint/lang/core/builtin/interpolation_sampling.h.tmpl
+++ b/src/tint/lang/core/builtin/interpolation_sampling.h.tmpl
@@ -15,7 +15,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/interpolation_type.cc b/src/tint/lang/core/builtin/interpolation_type.cc
index e236701..144263c 100644
--- a/src/tint/lang/core/builtin/interpolation_type.cc
+++ b/src/tint/lang/core/builtin/interpolation_type.cc
@@ -42,18 +42,18 @@
return InterpolationType::kUndefined;
}
-StringStream& operator<<(StringStream& out, InterpolationType value) {
+std::string_view ToString(InterpolationType value) {
switch (value) {
case InterpolationType::kUndefined:
- return out << "undefined";
+ return "undefined";
case InterpolationType::kFlat:
- return out << "flat";
+ return "flat";
case InterpolationType::kLinear:
- return out << "linear";
+ return "linear";
case InterpolationType::kPerspective:
- return out << "perspective";
+ return "perspective";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/interpolation_type.h b/src/tint/lang/core/builtin/interpolation_type.h
index 9957ec1..c742299 100644
--- a/src/tint/lang/core/builtin/interpolation_type.h
+++ b/src/tint/lang/core/builtin/interpolation_type.h
@@ -25,7 +25,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -37,10 +37,17 @@
kPerspective,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(InterpolationType value);
+
/// @param out the stream to write to
/// @param value the InterpolationType
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, InterpolationType value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, InterpolationType value) {
+ return out << ToString(value);
+}
/// ParseInterpolationType parses a InterpolationType from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/interpolation_type.h.tmpl b/src/tint/lang/core/builtin/interpolation_type.h.tmpl
index d537c0d..f8946c3 100644
--- a/src/tint/lang/core/builtin/interpolation_type.h.tmpl
+++ b/src/tint/lang/core/builtin/interpolation_type.h.tmpl
@@ -15,7 +15,7 @@
#include <string>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/builtin/number.cc b/src/tint/lang/core/builtin/number.cc
index 5c48960..a1ee952 100644
--- a/src/tint/lang/core/builtin/number.cc
+++ b/src/tint/lang/core/builtin/number.cc
@@ -50,16 +50,6 @@
} // namespace
-StringStream& operator<<(StringStream& out, ConversionFailure failure) {
- switch (failure) {
- case ConversionFailure::kExceedsPositiveLimit:
- return out << "value exceeds positive limit for type";
- case ConversionFailure::kExceedsNegativeLimit:
- return out << "value exceeds negative limit for type";
- }
- return out << "<unknown>";
-}
-
f16::type f16::Quantize(f16::type value) {
if (value > kHighestValue) {
return std::numeric_limits<f16::type>::infinity();
diff --git a/src/tint/lang/core/builtin/number.h b/src/tint/lang/core/builtin/number.h
index 3bf71b0..8c99b89 100644
--- a/src/tint/lang/core/builtin/number.h
+++ b/src/tint/lang/core/builtin/number.h
@@ -178,8 +178,8 @@
/// @param out the stream to write to
/// @param num the Number
/// @return the stream so calls can be chained
-template <typename T>
-inline StringStream& operator<<(StringStream& out, Number<T> num) {
+template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Number<T> num) {
return out << num.value;
}
@@ -324,7 +324,16 @@
/// @param out the stream to write to
/// @param failure the ConversionFailure
/// @return the stream so calls can be chained
-StringStream& operator<<(StringStream& out, ConversionFailure failure);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, ConversionFailure failure) {
+ switch (failure) {
+ case ConversionFailure::kExceedsPositiveLimit:
+ return out << "value exceeds positive limit for type";
+ case ConversionFailure::kExceedsNegativeLimit:
+ return out << "value exceeds negative limit for type";
+ }
+ return out << "<unknown>";
+}
/// Converts a number from one type to another, checking that the value fits in the target type.
/// @param num the value to convert
diff --git a/src/tint/lang/core/builtin/texel_format.cc b/src/tint/lang/core/builtin/texel_format.cc
index b3e3665..57dec1f 100644
--- a/src/tint/lang/core/builtin/texel_format.cc
+++ b/src/tint/lang/core/builtin/texel_format.cc
@@ -82,46 +82,46 @@
return TexelFormat::kUndefined;
}
-StringStream& operator<<(StringStream& out, TexelFormat value) {
+std::string_view ToString(TexelFormat value) {
switch (value) {
case TexelFormat::kUndefined:
- return out << "undefined";
+ return "undefined";
case TexelFormat::kBgra8Unorm:
- return out << "bgra8unorm";
+ return "bgra8unorm";
case TexelFormat::kR32Float:
- return out << "r32float";
+ return "r32float";
case TexelFormat::kR32Sint:
- return out << "r32sint";
+ return "r32sint";
case TexelFormat::kR32Uint:
- return out << "r32uint";
+ return "r32uint";
case TexelFormat::kRg32Float:
- return out << "rg32float";
+ return "rg32float";
case TexelFormat::kRg32Sint:
- return out << "rg32sint";
+ return "rg32sint";
case TexelFormat::kRg32Uint:
- return out << "rg32uint";
+ return "rg32uint";
case TexelFormat::kRgba16Float:
- return out << "rgba16float";
+ return "rgba16float";
case TexelFormat::kRgba16Sint:
- return out << "rgba16sint";
+ return "rgba16sint";
case TexelFormat::kRgba16Uint:
- return out << "rgba16uint";
+ return "rgba16uint";
case TexelFormat::kRgba32Float:
- return out << "rgba32float";
+ return "rgba32float";
case TexelFormat::kRgba32Sint:
- return out << "rgba32sint";
+ return "rgba32sint";
case TexelFormat::kRgba32Uint:
- return out << "rgba32uint";
+ return "rgba32uint";
case TexelFormat::kRgba8Sint:
- return out << "rgba8sint";
+ return "rgba8sint";
case TexelFormat::kRgba8Snorm:
- return out << "rgba8snorm";
+ return "rgba8snorm";
case TexelFormat::kRgba8Uint:
- return out << "rgba8uint";
+ return "rgba8uint";
case TexelFormat::kRgba8Unorm:
- return out << "rgba8unorm";
+ return "rgba8unorm";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::builtin
diff --git a/src/tint/lang/core/builtin/texel_format.h b/src/tint/lang/core/builtin/texel_format.h
index 63ebeb3..85662c5 100644
--- a/src/tint/lang/core/builtin/texel_format.h
+++ b/src/tint/lang/core/builtin/texel_format.h
@@ -23,7 +23,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_TEXEL_FORMAT_H_
#define SRC_TINT_LANG_CORE_BUILTIN_TEXEL_FORMAT_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
@@ -49,10 +49,17 @@
kRgba8Unorm,
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(TexelFormat value);
+
/// @param out the stream to write to
/// @param value the TexelFormat
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, TexelFormat value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, TexelFormat value) {
+ return out << ToString(value);
+}
/// ParseTexelFormat parses a TexelFormat from a string.
/// @param str the string to parse
diff --git a/src/tint/lang/core/builtin/texel_format.h.tmpl b/src/tint/lang/core/builtin/texel_format.h.tmpl
index 3a71306..e4b1125 100644
--- a/src/tint/lang/core/builtin/texel_format.h.tmpl
+++ b/src/tint/lang/core/builtin/texel_format.h.tmpl
@@ -14,7 +14,7 @@
#ifndef SRC_TINT_LANG_CORE_BUILTIN_TEXEL_FORMAT_H_
#define SRC_TINT_LANG_CORE_BUILTIN_TEXEL_FORMAT_H_
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::builtin {
diff --git a/src/tint/lang/core/ir/function.cc b/src/tint/lang/core/ir/function.cc
index 408daf8..dbee758 100644
--- a/src/tint/lang/core/ir/function.cc
+++ b/src/tint/lang/core/ir/function.cc
@@ -42,30 +42,30 @@
TINT_ASSERT(!params_.Any(IsNull));
}
-StringStream& operator<<(StringStream& out, Function::PipelineStage value) {
+std::string_view ToString(Function::PipelineStage value) {
switch (value) {
case Function::PipelineStage::kVertex:
- return out << "vertex";
+ return "vertex";
case Function::PipelineStage::kFragment:
- return out << "fragment";
+ return "fragment";
case Function::PipelineStage::kCompute:
- return out << "compute";
+ return "compute";
default:
break;
}
- return out << "<unknown>";
+ return "<unknown>";
}
-StringStream& operator<<(StringStream& out, enum Function::ReturnBuiltin value) {
+std::string_view ToString(enum Function::ReturnBuiltin value) {
switch (value) {
case Function::ReturnBuiltin::kFragDepth:
- return out << "frag_depth";
+ return "frag_depth";
case Function::ReturnBuiltin::kSampleMask:
- return out << "sample_mask";
+ return "sample_mask";
case Function::ReturnBuiltin::kPosition:
- return out << "position";
+ return "position";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::ir
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index 660440f..061fbab 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -152,8 +152,29 @@
ir::Block* block_ = nullptr;
};
-StringStream& operator<<(StringStream& out, Function::PipelineStage value);
-StringStream& operator<<(StringStream& out, enum Function::ReturnBuiltin value);
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(Function::PipelineStage value);
+
+/// @param out the stream to write to
+/// @param value the Function::PipelineStage
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Function::PipelineStage value) {
+ return out << ToString(value);
+}
+
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(enum Function::ReturnBuiltin value);
+
+/// @param out the stream to write to
+/// @param value the Function::ReturnBuiltin
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, enum Function::ReturnBuiltin value) {
+ return out << ToString(value);
+}
} // namespace tint::ir
diff --git a/src/tint/lang/core/ir/function_param.cc b/src/tint/lang/core/ir/function_param.cc
index 1dc8930..5d9dbbe 100644
--- a/src/tint/lang/core/ir/function_param.cc
+++ b/src/tint/lang/core/ir/function_param.cc
@@ -26,43 +26,32 @@
FunctionParam::~FunctionParam() = default;
-StringStream& operator<<(StringStream& out, enum FunctionParam::Builtin value) {
+std::string_view ToString(enum FunctionParam::Builtin value) {
switch (value) {
case FunctionParam::Builtin::kVertexIndex:
- out << "vertex_index";
- break;
+ return "vertex_index";
case FunctionParam::Builtin::kInstanceIndex:
- out << "instance_index";
- break;
+ return "instance_index";
case FunctionParam::Builtin::kPosition:
- out << "position";
- break;
+ return "position";
case FunctionParam::Builtin::kFrontFacing:
- out << "front_facing";
- break;
+ return "front_facing";
case FunctionParam::Builtin::kLocalInvocationId:
- out << "local_invocation_id";
- break;
+ return "local_invocation_id";
case FunctionParam::Builtin::kLocalInvocationIndex:
- out << "local_invocation_index";
- break;
+ return "local_invocation_index";
case FunctionParam::Builtin::kGlobalInvocationId:
- out << "global_invocation_id";
- break;
+ return "global_invocation_id";
case FunctionParam::Builtin::kWorkgroupId:
- out << "workgroup_id";
- break;
+ return "workgroup_id";
case FunctionParam::Builtin::kNumWorkgroups:
- out << "num_workgroups";
- break;
+ return "num_workgroups";
case FunctionParam::Builtin::kSampleIndex:
- out << "sample_index";
- break;
+ return "sample_index";
case FunctionParam::Builtin::kSampleMask:
- out << "sample_mask";
- break;
+ return "sample_mask";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::ir
diff --git a/src/tint/lang/core/ir/function_param.h b/src/tint/lang/core/ir/function_param.h
index 44ad9a5..6571438 100644
--- a/src/tint/lang/core/ir/function_param.h
+++ b/src/tint/lang/core/ir/function_param.h
@@ -106,7 +106,17 @@
bool invariant_ = false;
};
-StringStream& operator<<(StringStream& out, enum FunctionParam::Builtin value);
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(enum FunctionParam::Builtin value);
+
+/// @param out the stream to write to
+/// @param value the FunctionParam::Builtin
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, enum FunctionParam::Builtin value) {
+ return out << ToString(value);
+}
} // namespace tint::ir
diff --git a/src/tint/lang/core/ir/intrinsic_call.cc b/src/tint/lang/core/ir/intrinsic_call.cc
index 5ab9663..091076a 100644
--- a/src/tint/lang/core/ir/intrinsic_call.cc
+++ b/src/tint/lang/core/ir/intrinsic_call.cc
@@ -28,106 +28,74 @@
IntrinsicCall::~IntrinsicCall() = default;
-StringStream& operator<<(StringStream& out, enum IntrinsicCall::Kind kind) {
+std::string_view ToString(enum IntrinsicCall::Kind kind) {
switch (kind) {
case IntrinsicCall::Kind::kSpirvArrayLength:
- out << "spirv.array_length";
- break;
+ return "spirv.array_length";
case IntrinsicCall::Kind::kSpirvAtomicIAdd:
- out << "spirv.atomic_iadd";
- break;
+ return "spirv.atomic_iadd";
case IntrinsicCall::Kind::kSpirvAtomicISub:
- out << "spirv.atomic_isub";
- break;
+ return "spirv.atomic_isub";
case IntrinsicCall::Kind::kSpirvAtomicAnd:
- out << "spirv.atomic_and";
- break;
+ return "spirv.atomic_and";
case IntrinsicCall::Kind::kSpirvAtomicCompareExchange:
- out << "spirv.atomic_compare_exchange";
- break;
+ return "spirv.atomic_compare_exchange";
case IntrinsicCall::Kind::kSpirvAtomicExchange:
- out << "spirv.atomic_exchange";
- break;
+ return "spirv.atomic_exchange";
case IntrinsicCall::Kind::kSpirvAtomicLoad:
- out << "spirv.atomic_load";
- break;
+ return "spirv.atomic_load";
case IntrinsicCall::Kind::kSpirvAtomicOr:
- out << "spirv.atomic_or";
- break;
+ return "spirv.atomic_or";
case IntrinsicCall::Kind::kSpirvAtomicSMax:
- out << "spirv.atomic_smax";
- break;
+ return "spirv.atomic_smax";
case IntrinsicCall::Kind::kSpirvAtomicSMin:
- out << "spirv.atomic_smin";
- break;
+ return "spirv.atomic_smin";
case IntrinsicCall::Kind::kSpirvAtomicStore:
- out << "spirv.atomic_store";
- break;
+ return "spirv.atomic_store";
case IntrinsicCall::Kind::kSpirvAtomicUMax:
- out << "spirv.atomic_umax";
- break;
+ return "spirv.atomic_umax";
case IntrinsicCall::Kind::kSpirvAtomicUMin:
- out << "spirv.atomic_umin";
- break;
+ return "spirv.atomic_umin";
case IntrinsicCall::Kind::kSpirvAtomicXor:
- out << "spirv.atomic_xor";
- break;
+ return "spirv.atomic_xor";
case IntrinsicCall::Kind::kSpirvDot:
- out << "spirv.dot";
- break;
+ return "spirv.dot";
case IntrinsicCall::Kind::kSpirvImageFetch:
- out << "spirv.image_fetch";
- break;
+ return "spirv.image_fetch";
case IntrinsicCall::Kind::kSpirvImageGather:
- out << "spirv.image_gather";
- break;
+ return "spirv.image_gather";
case IntrinsicCall::Kind::kSpirvImageDrefGather:
- out << "spirv.image_dref_gather";
- break;
+ return "spirv.image_dref_gather";
case IntrinsicCall::Kind::kSpirvImageQuerySize:
- out << "spirv.image_query_size";
- break;
+ return "spirv.image_query_size";
case IntrinsicCall::Kind::kSpirvImageQuerySizeLod:
- out << "spirv.image_query_size_lod";
- break;
+ return "spirv.image_query_size_lod";
case IntrinsicCall::Kind::kSpirvImageSampleImplicitLod:
- out << "spirv.image_sample_implicit_lod";
- break;
+ return "spirv.image_sample_implicit_lod";
case IntrinsicCall::Kind::kSpirvImageSampleExplicitLod:
- out << "spirv.image_sample_explicit_lod";
- break;
+ return "spirv.image_sample_explicit_lod";
case IntrinsicCall::Kind::kSpirvImageSampleDrefImplicitLod:
- out << "spirv.image_sample_dref_implicit_lod";
- break;
+ return "spirv.image_sample_dref_implicit_lod";
case IntrinsicCall::Kind::kSpirvImageSampleDrefExplicitLod:
- out << "spirv.image_sample_dref_implicit_lod";
- break;
+ return "spirv.image_sample_dref_implicit_lod";
case IntrinsicCall::Kind::kSpirvImageWrite:
- out << "spirv.image_write";
- break;
+ return "spirv.image_write";
case IntrinsicCall::Kind::kSpirvMatrixTimesMatrix:
- out << "spirv.matrix_times_matrix";
- break;
+ return "spirv.matrix_times_matrix";
case IntrinsicCall::Kind::kSpirvMatrixTimesScalar:
- out << "spirv.matrix_times_scalar";
- break;
+ return "spirv.matrix_times_scalar";
case IntrinsicCall::Kind::kSpirvMatrixTimesVector:
- out << "spirv.matrix_times_vector";
- break;
+ return "spirv.matrix_times_vector";
case IntrinsicCall::Kind::kSpirvSampledImage:
- out << "spirv.sampled_image";
- break;
+ return "spirv.sampled_image";
case IntrinsicCall::Kind::kSpirvSelect:
- out << "spirv.select";
- break;
+ return "spirv.select";
case IntrinsicCall::Kind::kSpirvVectorTimesScalar:
- out << "spirv.vector_times_scalar";
- break;
+ return "spirv.vector_times_scalar";
case IntrinsicCall::Kind::kSpirvVectorTimesMatrix:
- out << "spirv.vector_times_matrix";
- break;
+ return "spirv.vector_times_matrix";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::ir
diff --git a/src/tint/lang/core/ir/intrinsic_call.h b/src/tint/lang/core/ir/intrinsic_call.h
index 9a01acf..a04b3ef 100644
--- a/src/tint/lang/core/ir/intrinsic_call.h
+++ b/src/tint/lang/core/ir/intrinsic_call.h
@@ -80,8 +80,15 @@
enum Kind kind_;
};
+/// @param kind the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(enum IntrinsicCall::Kind kind);
+
/// Emits the name of the intrinsic type.
-StringStream& operator<<(StringStream& out, enum IntrinsicCall::Kind kind);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, enum IntrinsicCall::Kind kind) {
+ return out << ToString(kind);
+}
} // namespace tint::ir
diff --git a/src/tint/lang/core/type/sampler_kind.cc b/src/tint/lang/core/type/sampler_kind.cc
index 0780929..17e950c 100644
--- a/src/tint/lang/core/type/sampler_kind.cc
+++ b/src/tint/lang/core/type/sampler_kind.cc
@@ -16,16 +16,14 @@
namespace tint::type {
-StringStream& operator<<(StringStream& out, SamplerKind kind) {
+std::string_view ToString(SamplerKind kind) {
switch (kind) {
case SamplerKind::kSampler:
- out << "sampler";
- break;
+ return "sampler";
case SamplerKind::kComparisonSampler:
- out << "comparison_sampler";
- break;
+ return "comparison_sampler";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::type
diff --git a/src/tint/lang/core/type/sampler_kind.h b/src/tint/lang/core/type/sampler_kind.h
index 33d766e..fed81c2 100644
--- a/src/tint/lang/core/type/sampler_kind.h
+++ b/src/tint/lang/core/type/sampler_kind.h
@@ -16,6 +16,7 @@
#define SRC_TINT_LANG_CORE_TYPE_SAMPLER_KIND_H_
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::type {
@@ -27,10 +28,17 @@
kComparisonSampler
};
+/// @param kind the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(enum SamplerKind kind);
+
/// @param out the stream to write to
/// @param kind the SamplerKind
/// @return the stream so calls can be chained
-StringStream& operator<<(StringStream& out, SamplerKind kind);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, SamplerKind kind) {
+ return out << ToString(kind);
+}
} // namespace tint::type
diff --git a/src/tint/lang/core/type/texture_dimension.cc b/src/tint/lang/core/type/texture_dimension.cc
index ecabdb2..dc2ce79 100644
--- a/src/tint/lang/core/type/texture_dimension.cc
+++ b/src/tint/lang/core/type/texture_dimension.cc
@@ -16,31 +16,24 @@
namespace tint::type {
-StringStream& operator<<(StringStream& out, type::TextureDimension dim) {
+std::string_view ToString(type::TextureDimension dim) {
switch (dim) {
case type::TextureDimension::kNone:
- out << "None";
- break;
+ return "None";
case type::TextureDimension::k1d:
- out << "1d";
- break;
+ return "1d";
case type::TextureDimension::k2d:
- out << "2d";
- break;
+ return "2d";
case type::TextureDimension::k2dArray:
- out << "2d_array";
- break;
+ return "2d_array";
case type::TextureDimension::k3d:
- out << "3d";
- break;
+ return "3d";
case type::TextureDimension::kCube:
- out << "cube";
- break;
+ return "cube";
case type::TextureDimension::kCubeArray:
- out << "cube_array";
- break;
+ return "cube_array";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::type
diff --git a/src/tint/lang/core/type/texture_dimension.h b/src/tint/lang/core/type/texture_dimension.h
index 9bcd724..1d5fd44 100644
--- a/src/tint/lang/core/type/texture_dimension.h
+++ b/src/tint/lang/core/type/texture_dimension.h
@@ -16,6 +16,7 @@
#define SRC_TINT_LANG_CORE_TYPE_TEXTURE_DIMENSION_H_
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::type {
@@ -37,10 +38,17 @@
kCubeArray,
};
+/// @param dim the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(enum type::TextureDimension dim);
+
/// @param out the stream to write to
/// @param dim the type::TextureDimension
/// @return the stream so calls can be chained
-StringStream& operator<<(StringStream& out, type::TextureDimension dim);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, type::TextureDimension dim) {
+ return out << ToString(dim);
+}
} // namespace tint::type
diff --git a/src/tint/lang/spirv/reader/ast_parser/construct.h b/src/tint/lang/spirv/reader/ast_parser/construct.h
index bcc35a3..59f6010 100644
--- a/src/tint/lang/spirv/reader/ast_parser/construct.h
+++ b/src/tint/lang/spirv/reader/ast_parser/construct.h
@@ -184,7 +184,8 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-inline StringStream& operator<<(StringStream& o, const Construct& c) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const Construct& c) {
o << "Construct{ " << ToString(c.kind) << " [" << c.begin_pos << "," << c.end_pos << ")"
<< " begin_id:" << c.begin_id << " end_id:" << c.end_id << " depth:" << c.depth;
@@ -215,7 +216,8 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-inline StringStream& operator<<(StringStream& o, const std::unique_ptr<Construct>& c) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const std::unique_ptr<Construct>& c) {
return o << *(c.get());
}
@@ -246,7 +248,8 @@
/// @param o the stream
/// @param cl the construct list
/// @returns the stream
-inline StringStream& operator<<(StringStream& o, const ConstructList& cl) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const ConstructList& cl) {
o << "ConstructList{\n";
for (const auto& c : cl) {
o << " " << c << "\n";
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.h b/src/tint/lang/spirv/reader/ast_parser/function.h
index 29ad3da..5658690 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.h
+++ b/src/tint/lang/spirv/reader/ast_parser/function.h
@@ -183,7 +183,8 @@
/// @param o the stream
/// @param bi the BlockInfo
/// @returns the stream so calls can be chained
-inline StringStream& operator<<(StringStream& o, const BlockInfo& bi) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const BlockInfo& bi) {
o << "BlockInfo{"
<< " id: " << bi.id << " pos: " << bi.pos << " merge_for_header: " << bi.merge_for_header
<< " continue_for_header: " << bi.continue_for_header
@@ -358,7 +359,8 @@
/// @param o the stream
/// @param di the DefInfo
/// @returns the stream so calls can be chained
-inline StringStream& operator<<(StringStream& o, const DefInfo& di) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const DefInfo& di) {
o << "DefInfo{"
<< " inst.result_id: " << di.inst.result_id();
if (di.local.has_value()) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/usage.h b/src/tint/lang/spirv/reader/ast_parser/usage.h
index 4d7fbb5..144abe4 100644
--- a/src/tint/lang/spirv/reader/ast_parser/usage.h
+++ b/src/tint/lang/spirv/reader/ast_parser/usage.h
@@ -18,6 +18,7 @@
#include <string>
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::spirv::reader {
@@ -128,7 +129,8 @@
/// @param out the stream
/// @param u the Usage
/// @returns the stream so calls can be chained
-inline StringStream& operator<<(StringStream& out, const Usage& u) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const Usage& u) {
return u.operator<<(out);
}
diff --git a/src/tint/lang/spirv/writer/test_helper.h b/src/tint/lang/spirv/writer/test_helper.h
index d4d6ae9..e8c1ab6 100644
--- a/src/tint/lang/spirv/writer/test_helper.h
+++ b/src/tint/lang/spirv/writer/test_helper.h
@@ -47,7 +47,8 @@
kF32,
kF16,
};
-inline StringStream& operator<<(StringStream& out, TestElementType type) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, TestElementType type) {
switch (type) {
case kBool:
out << "bool";
diff --git a/src/tint/lang/spirv/writer/texture_builtin_test.cc b/src/tint/lang/spirv/writer/texture_builtin_test.cc
index 3df9f72..b1fbb11 100644
--- a/src/tint/lang/spirv/writer/texture_builtin_test.cc
+++ b/src/tint/lang/spirv/writer/texture_builtin_test.cc
@@ -62,7 +62,8 @@
Vector<const char*, 2> instructions;
};
-inline StringStream& operator<<(StringStream& out, TextureType type) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, TextureType type) {
switch (type) {
case kSampledTexture:
out << "SampleTexture";
diff --git a/src/tint/lang/wgsl/ast/binary_expression.h b/src/tint/lang/wgsl/ast/binary_expression.h
index 7f90d6f..2b9cd2c 100644
--- a/src/tint/lang/wgsl/ast/binary_expression.h
+++ b/src/tint/lang/wgsl/ast/binary_expression.h
@@ -300,7 +300,8 @@
/// @param out the stream to write to
/// @param op the BinaryOp
/// @return the stream so calls can be chained
-inline StringStream& operator<<(StringStream& out, BinaryOp op) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, BinaryOp op) {
out << FriendlyName(op);
return out;
}
diff --git a/src/tint/lang/wgsl/ast/float_literal_expression.cc b/src/tint/lang/wgsl/ast/float_literal_expression.cc
index 36dd37c..9fb7cbf 100644
--- a/src/tint/lang/wgsl/ast/float_literal_expression.cc
+++ b/src/tint/lang/wgsl/ast/float_literal_expression.cc
@@ -37,14 +37,14 @@
return ctx->dst->create<FloatLiteralExpression>(src, value, suffix);
}
-StringStream& operator<<(StringStream& out, FloatLiteralExpression::Suffix suffix) {
+std::string_view ToString(FloatLiteralExpression::Suffix suffix) {
switch (suffix) {
default:
- return out;
+ return "";
case FloatLiteralExpression::Suffix::kF:
- return out << "f";
+ return "f";
case FloatLiteralExpression::Suffix::kH:
- return out << "h";
+ return "h";
}
}
diff --git a/src/tint/lang/wgsl/ast/float_literal_expression.h b/src/tint/lang/wgsl/ast/float_literal_expression.h
index 964106a..679d3f2 100644
--- a/src/tint/lang/wgsl/ast/float_literal_expression.h
+++ b/src/tint/lang/wgsl/ast/float_literal_expression.h
@@ -56,11 +56,18 @@
const Suffix suffix;
};
+/// @param suffix the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(FloatLiteralExpression::Suffix suffix);
+
/// Writes the float literal suffix to the stream.
/// @param out the stream to write to
/// @param suffix the suffix to write
/// @returns out so calls can be chained
-StringStream& operator<<(StringStream& out, FloatLiteralExpression::Suffix suffix);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, FloatLiteralExpression::Suffix suffix) {
+ return out << ToString(suffix);
+}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/int_literal_expression.cc b/src/tint/lang/wgsl/ast/int_literal_expression.cc
index 74e99db..6858bf7 100644
--- a/src/tint/lang/wgsl/ast/int_literal_expression.cc
+++ b/src/tint/lang/wgsl/ast/int_literal_expression.cc
@@ -35,14 +35,14 @@
return ctx->dst->create<IntLiteralExpression>(src, value, suffix);
}
-StringStream& operator<<(StringStream& out, IntLiteralExpression::Suffix suffix) {
+std::string_view ToString(IntLiteralExpression::Suffix suffix) {
switch (suffix) {
default:
- return out;
+ return "";
case IntLiteralExpression::Suffix::kI:
- return out << "i";
+ return "i";
case IntLiteralExpression::Suffix::kU:
- return out << "u";
+ return "u";
}
}
diff --git a/src/tint/lang/wgsl/ast/int_literal_expression.h b/src/tint/lang/wgsl/ast/int_literal_expression.h
index c0ae78d..f6399db 100644
--- a/src/tint/lang/wgsl/ast/int_literal_expression.h
+++ b/src/tint/lang/wgsl/ast/int_literal_expression.h
@@ -55,11 +55,18 @@
const Suffix suffix;
};
+/// @param suffix the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(IntLiteralExpression::Suffix suffix);
+
/// Writes the integer literal suffix to the stream.
/// @param out the stream to write to
/// @param suffix the suffix to write
/// @returns out so calls can be chained
-StringStream& operator<<(StringStream& out, IntLiteralExpression::Suffix suffix);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, IntLiteralExpression::Suffix suffix) {
+ return out << ToString(suffix);
+}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/pipeline_stage.cc b/src/tint/lang/wgsl/ast/pipeline_stage.cc
index 4d00143..2b1fa2e 100644
--- a/src/tint/lang/wgsl/ast/pipeline_stage.cc
+++ b/src/tint/lang/wgsl/ast/pipeline_stage.cc
@@ -16,26 +16,18 @@
namespace tint::ast {
-StringStream& operator<<(StringStream& out, PipelineStage stage) {
+std::string_view ToString(PipelineStage stage) {
switch (stage) {
- case PipelineStage::kNone: {
- out << "none";
- break;
- }
- case PipelineStage::kVertex: {
- out << "vertex";
- break;
- }
- case PipelineStage::kFragment: {
- out << "fragment";
- break;
- }
- case PipelineStage::kCompute: {
- out << "compute";
- break;
- }
+ case PipelineStage::kNone:
+ return "none";
+ case PipelineStage::kVertex:
+ return "vertex";
+ case PipelineStage::kFragment:
+ return "fragment";
+ case PipelineStage::kCompute:
+ return "compute";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/pipeline_stage.h b/src/tint/lang/wgsl/ast/pipeline_stage.h
index 456a8b3..8d0c7c3 100644
--- a/src/tint/lang/wgsl/ast/pipeline_stage.h
+++ b/src/tint/lang/wgsl/ast/pipeline_stage.h
@@ -16,16 +16,24 @@
#define SRC_TINT_LANG_WGSL_AST_PIPELINE_STAGE_H_
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::ast {
/// The pipeline stage
enum class PipelineStage { kNone = -1, kVertex, kFragment, kCompute };
+/// @param stage the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(PipelineStage stage);
+
/// @param out the stream to write to
/// @param stage the PipelineStage
/// @return the stream so calls can be chained
-StringStream& operator<<(StringStream& out, PipelineStage stage);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, PipelineStage stage) {
+ return out << ToString(stage);
+}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/unary_op.cc b/src/tint/lang/wgsl/ast/unary_op.cc
index 35f28f7..1c1843d 100644
--- a/src/tint/lang/wgsl/ast/unary_op.cc
+++ b/src/tint/lang/wgsl/ast/unary_op.cc
@@ -16,30 +16,20 @@
namespace tint::ast {
-StringStream& operator<<(StringStream& out, UnaryOp mod) {
+std::string_view ToString(UnaryOp mod) {
switch (mod) {
- case UnaryOp::kAddressOf: {
- out << "address-of";
- break;
- }
- case UnaryOp::kComplement: {
- out << "complement";
- break;
- }
- case UnaryOp::kIndirection: {
- out << "indirection";
- break;
- }
- case UnaryOp::kNegation: {
- out << "negation";
- break;
- }
- case UnaryOp::kNot: {
- out << "not";
- break;
- }
+ case UnaryOp::kAddressOf:
+ return "address-of";
+ case UnaryOp::kComplement:
+ return "complement";
+ case UnaryOp::kIndirection:
+ return "indirection";
+ case UnaryOp::kNegation:
+ return "negation";
+ case UnaryOp::kNot:
+ return "not";
}
- return out;
+ return "<unknown>";
}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/unary_op.h b/src/tint/lang/wgsl/ast/unary_op.h
index 2dda746..9d9bee6 100644
--- a/src/tint/lang/wgsl/ast/unary_op.h
+++ b/src/tint/lang/wgsl/ast/unary_op.h
@@ -16,6 +16,7 @@
#define SRC_TINT_LANG_WGSL_AST_UNARY_OP_H_
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::ast {
@@ -28,10 +29,17 @@
kNot, // !EXPR
};
+/// @param mod the enum value
+/// @returns the string for the given enum value
+std::string_view ToString(UnaryOp mod);
+
/// @param out the stream to write to
/// @param mod the UnaryOp
/// @return the stream so calls can be chained
-StringStream& operator<<(StringStream& out, UnaryOp mod);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, UnaryOp mod) {
+ return out << ToString(mod);
+}
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/reader/parser/token.h b/src/tint/lang/wgsl/reader/parser/token.h
index 2523c91..536bb35 100644
--- a/src/tint/lang/wgsl/reader/parser/token.h
+++ b/src/tint/lang/wgsl/reader/parser/token.h
@@ -359,7 +359,8 @@
std::variant<int64_t, double, std::string, std::string_view> value_;
};
-inline StringStream& operator<<(StringStream& out, Token::Type type) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Token::Type type) {
out << Token::TypeToName(type);
return out;
}
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index ddfa96d..0ccd6e9 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -2071,7 +2071,8 @@
namespace texture_builtin_tests {
enum class Texture { kF32, kI32, kU32 };
-inline StringStream& operator<<(StringStream& out, Texture data) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Texture data) {
if (data == Texture::kF32) {
out << "f32";
} else if (data == Texture::kI32) {
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index f6399fd..f2077b6 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -666,7 +666,7 @@
[&](const ast::ConstAssert*) { return "const_assert"; }, //
[&](Default) {
UnhandledNode(node);
- return "<error>";
+ return "<unknown>";
});
}
diff --git a/src/tint/lang/wgsl/sem/behavior.cc b/src/tint/lang/wgsl/sem/behavior.cc
index f47070c..e1c007c 100644
--- a/src/tint/lang/wgsl/sem/behavior.cc
+++ b/src/tint/lang/wgsl/sem/behavior.cc
@@ -16,18 +16,18 @@
namespace tint::sem {
-StringStream& operator<<(StringStream& out, Behavior behavior) {
+std::string_view ToString(Behavior behavior) {
switch (behavior) {
case Behavior::kReturn:
- return out << "Return";
+ return "Return";
case Behavior::kBreak:
- return out << "Break";
+ return "Break";
case Behavior::kContinue:
- return out << "Continue";
+ return "Continue";
case Behavior::kNext:
- return out << "Next";
+ return "Next";
}
- return out << "<unknown>";
+ return "<unknown>";
}
} // namespace tint::sem
diff --git a/src/tint/lang/wgsl/sem/behavior.h b/src/tint/lang/wgsl/sem/behavior.h
index dc0df58..b77614a 100644
--- a/src/tint/lang/wgsl/sem/behavior.h
+++ b/src/tint/lang/wgsl/sem/behavior.h
@@ -16,6 +16,7 @@
#define SRC_TINT_LANG_WGSL_SEM_BEHAVIOR_H_
#include "src/tint/utils/containers/enum_set.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint::sem {
@@ -31,11 +32,18 @@
/// Behaviors is a set of Behavior
using Behaviors = tint::EnumSet<Behavior>;
+/// @param behavior the behavior
+/// @returns the string for the given enumerator
+std::string_view ToString(Behavior behavior);
+
/// Writes the Behavior to the stream.
/// @param out the stream to write to
/// @param behavior the Behavior to write
/// @returns out so calls can be chained
-StringStream& operator<<(StringStream& out, Behavior behavior);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Behavior behavior) {
+ return out << ToString(behavior);
+}
} // namespace tint::sem
diff --git a/src/tint/lang/wgsl/sem/sampler_texture_pair.h b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
index 516a050..51e3dc2 100644
--- a/src/tint/lang/wgsl/sem/sampler_texture_pair.h
+++ b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
@@ -48,7 +48,8 @@
/// @param o the stream to write to
/// @param stp the SamplerTexturePair
/// @return the stream so calls can be chained
-inline StringStream& operator<<(StringStream& o, const SamplerTexturePair& stp) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const SamplerTexturePair& stp) {
return o << "[sampler: " << stp.sampler_binding_point
<< ", texture: " << stp.sampler_binding_point << "]";
}
diff --git a/src/tint/utils/containers/enum_set.h b/src/tint/utils/containers/enum_set.h
index 2e3fd15..488a230 100644
--- a/src/tint/utils/containers/enum_set.h
+++ b/src/tint/utils/containers/enum_set.h
@@ -20,7 +20,7 @@
#include <type_traits>
#include <utility>
-#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint {
@@ -227,8 +227,8 @@
/// @param out the stream to write to
/// @param set the EnumSet to write
/// @returns out so calls can be chained
-template <typename ENUM>
-inline StringStream& operator<<(StringStream& out, EnumSet<ENUM> set) {
+template <typename STREAM, typename ENUM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, EnumSet<ENUM> set) {
out << "{";
bool first = true;
for (auto e : set) {
diff --git a/src/tint/utils/containers/hashmap_base.h b/src/tint/utils/containers/hashmap_base.h
index 753564d..e1ea31e 100644
--- a/src/tint/utils/containers/hashmap_base.h
+++ b/src/tint/utils/containers/hashmap_base.h
@@ -24,6 +24,7 @@
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/traits/traits.h"
#define TINT_ASSERT_ITERATORS_NOT_INVALIDATED
@@ -97,8 +98,11 @@
/// @param out the stream to write to
/// @param key_value the KeyValue to write
/// @returns out so calls can be chained
-template <typename KEY, typename VALUE>
-StringStream& operator<<(StringStream& out, const KeyValue<KEY, VALUE>& key_value) {
+template <typename STREAM,
+ typename KEY,
+ typename VALUE,
+ typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const KeyValue<KEY, VALUE>& key_value) {
return out << "[" << key_value.key << ": " << key_value.value << "]";
}
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index dc29721..4760cb5 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -27,16 +27,11 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/memory/bitcast.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint {
/// Forward declarations
+namespace tint {
template <typename>
class VectorRef;
-template <typename>
-class VectorRef;
-
} // namespace tint
namespace tint {
@@ -834,8 +829,8 @@
/// @param o the stream to write to
/// @param vec the vector
/// @return the stream so calls can be chained
-template <typename T, size_t N>
-inline StringStream& operator<<(StringStream& o, const Vector<T, N>& vec) {
+template <typename STREAM, typename T, size_t N, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, const Vector<T, N>& vec) {
o << "[";
bool first = true;
for (auto& el : vec) {
@@ -853,8 +848,8 @@
/// @param o the stream to write to
/// @param vec the vector reference
/// @return the stream so calls can be chained
-template <typename T>
-inline StringStream& operator<<(StringStream& o, VectorRef<T> vec) {
+template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, VectorRef<T> vec) {
o << "[";
bool first = true;
for (auto& el : vec) {
diff --git a/src/tint/utils/containers/vector_test.cc b/src/tint/utils/containers/vector_test.cc
index ab8a3e2..602bc25 100644
--- a/src/tint/utils/containers/vector_test.cc
+++ b/src/tint/utils/containers/vector_test.cc
@@ -21,7 +21,6 @@
#include "src/tint/utils/containers/predicates.h"
#include "src/tint/utils/memory/bitcast.h"
-#include "src/tint/utils/text/string_stream.h"
namespace tint {
namespace {
diff --git a/src/tint/utils/diagnostic/source.h b/src/tint/utils/diagnostic/source.h
index a377e61..d1ac0b3 100644
--- a/src/tint/utils/diagnostic/source.h
+++ b/src/tint/utils/diagnostic/source.h
@@ -22,6 +22,7 @@
#include <vector>
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint {
@@ -196,7 +197,8 @@
/// @param out the stream to write to
/// @param loc the location to write
/// @returns out so calls can be chained
-inline StringStream& operator<<(StringStream& out, const Source::Location& loc) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const Source::Location& loc) {
out << loc.line << ":" << loc.column;
return out;
}
@@ -205,7 +207,8 @@
/// @param out the stream to write to
/// @param range the range to write
/// @returns out so calls can be chained
-inline StringStream& operator<<(StringStream& out, const Source::Range& range) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const Source::Range& range) {
out << "[" << range.begin << ", " << range.end << "]";
return out;
}
@@ -220,7 +223,8 @@
/// @param out the stream to write to
/// @param content the file content to write
/// @returns out so calls can be chained
-inline StringStream& operator<<(StringStream& out, const Source::FileContent& content) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const Source::FileContent& content) {
out << content.data;
return out;
}
diff --git a/src/tint/utils/generation_id.h b/src/tint/utils/generation_id.h
index 6a9249b..16ee56d 100644
--- a/src/tint/utils/generation_id.h
+++ b/src/tint/utils/generation_id.h
@@ -20,6 +20,7 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint {
@@ -75,7 +76,8 @@
/// @param out the stream to write to
/// @param id the generation identifier to write
/// @returns out so calls can be chained
-inline StringStream& operator<<(StringStream& out, GenerationID id) {
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, GenerationID id) {
out << "Generation<" << id.Value() << ">";
return out;
}
diff --git a/src/tint/utils/result/result.h b/src/tint/utils/result/result.h
index aab5048..f79468b 100644
--- a/src/tint/utils/result/result.h
+++ b/src/tint/utils/result/result.h
@@ -20,6 +20,7 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/text/string_stream.h"
+#include "src/tint/utils/traits/traits.h"
namespace tint {
@@ -163,8 +164,11 @@
/// @param out the stream to write to
/// @param res the result
/// @return the stream so calls can be chained
-template <typename SUCCESS, typename FAILURE>
-inline StringStream& operator<<(StringStream& out, Result<SUCCESS, FAILURE> res) {
+template <typename STREAM,
+ typename SUCCESS,
+ typename FAILURE,
+ typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, Result<SUCCESS, FAILURE> res) {
return res ? (out << "success: " << res.Get()) : (out << "failure: " << res.Failure());
}
diff --git a/src/tint/utils/templates/enums.tmpl.inc b/src/tint/utils/templates/enums.tmpl.inc
index 73db9f7..47a3435 100644
--- a/src/tint/utils/templates/enums.tmpl.inc
+++ b/src/tint/utils/templates/enums.tmpl.inc
@@ -47,10 +47,17 @@
{{- end }}
};
+/// @param value the enum value
+/// @returns the string for the given enum value
+std::string_view ToString({{$enum}} value);
+
/// @param out the stream to write to
/// @param value the {{$enum}}
-/// @returns `out` so calls can be chained
-StringStream& operator<<(StringStream& out, {{$enum}} value);
+/// @returns @p out so calls can be chained
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, {{$enum}} value) {
+ return out << ToString(value);
+}
/// Parse{{$enum}} parses a {{$enum}} from a string.
/// @param str the string to parse
@@ -94,16 +101,16 @@
{{- /* provided sem.Enum. */ -}}
{{- /* ------------------------------------------------------------------ */ -}}
{{- $enum := Eval "EnumName" $ -}}
- StringStream& operator<<(StringStream& out, {{$enum}} value) {
+std::string_view ToString({{$enum}} value) {
switch (value) {
case {{$enum}}::kUndefined:
- return out << "undefined";
+ return "undefined";
{{- range $entry := $.Entries }}
case {{template "EnumCase" $entry}}:
- return out << "{{$entry.Name}}";
+ return "{{$entry.Name}}";
{{- end }}
}
- return out << "<unknown>";
+ return "<unknown>";
}
{{- end -}}
diff --git a/src/tint/utils/text/string_stream.h b/src/tint/utils/text/string_stream.h
index 360f4b1..4e88f8f 100644
--- a/src/tint/utils/text/string_stream.h
+++ b/src/tint/utils/text/string_stream.h
@@ -41,6 +41,9 @@
std::is_same_v<SetFillRetTy, std::decay_t<T>>;
public:
+ /// @see tint::traits::IsOStream
+ static constexpr bool IsStreamWriter = true;
+
/// Constructor
StringStream();
/// Destructor
diff --git a/src/tint/utils/traits/traits.h b/src/tint/utils/traits/traits.h
index 6516c06..62071c7 100644
--- a/src/tint/utils/traits/traits.h
+++ b/src/tint/utils/traits/traits.h
@@ -15,6 +15,7 @@
#ifndef SRC_TINT_UTILS_TRAITS_TRAITS_H_
#define SRC_TINT_UTILS_TRAITS_TRAITS_H_
+#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
@@ -100,10 +101,9 @@
static constexpr bool IsTypeOrDerived =
std::is_base_of<BASE, Decay<T>>::value || std::is_same<BASE, Decay<T>>::value;
-/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
-/// invalid type.
+/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an invalid type.
template <bool CONDITION, typename T = void>
-using EnableIf = typename std::enable_if<CONDITION, T>::type;
+using EnableIf = std::enable_if_t<CONDITION, T>;
/// If `T` is of type `BASE`, or derives from `BASE`, then EnableIfIsType
/// resolves to type `T`, otherwise an invalid type.
@@ -209,6 +209,36 @@
template <typename T>
using CharArrayToCharPtr = typename traits::detail::CharArrayToCharPtrImpl<T>::type;
+namespace detail {
+/// Helper for determining whether the type T can be used as a stream writer
+template <typename T, typename ENABLE = void>
+struct IsOStream : std::false_type {};
+
+/// Specialization for types that declare a `static constexpr bool IsStreamWriter` member
+template <typename T>
+struct IsOStream<T, std::void_t<decltype(T::IsStreamWriter)>> {
+ /// Equal to T::IsStreamWriter
+ static constexpr bool value = T::IsStreamWriter;
+};
+
+/// Specialization for std::ostream
+template <typename T>
+struct IsOStream<T, std::enable_if_t<std::is_same_v<T, std::ostream>>> : std::true_type {};
+
+/// Specialization for std::stringstream
+template <typename T>
+struct IsOStream<T, std::enable_if_t<std::is_same_v<T, std::stringstream>>> : std::true_type {};
+
+} // namespace detail
+
+/// Is true if the class T can be treated as an output stream
+template <typename T>
+static constexpr bool IsOStream = detail::IsOStream<T>::value;
+
+/// If `CONDITION` is true then EnableIfIsOStream resolves to type T, otherwise an invalid type.
+template <typename T = void>
+using EnableIfIsOStream = EnableIf<IsOStream<T>, T>;
+
} // namespace tint::traits
#endif // SRC_TINT_UTILS_TRAITS_TRAITS_H_
diff --git a/src/tint/utils/traits/traits_test.cc b/src/tint/utils/traits/traits_test.cc
index 348415f..417b7c2 100644
--- a/src/tint/utils/traits/traits_test.cc
+++ b/src/tint/utils/traits/traits_test.cc
@@ -14,12 +14,17 @@
#include "src/tint/utils/traits/traits.h"
+#include <ostream>
+
#include "gtest/gtest.h"
namespace tint::traits {
namespace {
+static_assert(traits::IsOStream<std::ostream>);
+static_assert(traits::IsOStream<std::stringstream>);
+
static_assert(std::is_same_v<PtrElTy<int*>, int>);
static_assert(std::is_same_v<PtrElTy<int const*>, int>);
static_assert(std::is_same_v<PtrElTy<int const* const>, int>);