googletest: Add universal printer for `std::span`
Fixes #4318
PiperOrigin-RevId: 560089120
Change-Id: I9d0d098140033520266747a1689e953ee8307c47
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h
index d1766e6..9ccbff7 100644
--- a/googletest/include/gtest/gtest-printers.h
+++ b/googletest/include/gtest/gtest-printers.h
@@ -122,6 +122,10 @@
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-port.h"
+#if GTEST_INTERNAL_HAS_STD_SPAN
+#include <span> // NOLINT
+#endif // GTEST_INTERNAL_HAS_STD_SPAN
+
namespace testing {
// Definitions in the internal* namespaces are subject to change without notice.
@@ -131,13 +135,32 @@
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os);
+template <typename T>
+struct IsStdSpan {
+ static constexpr bool value = false;
+};
+
+#if GTEST_INTERNAL_HAS_STD_SPAN
+template <typename E>
+struct IsStdSpan<std::span<E>> {
+ static constexpr bool value = true;
+};
+#endif // GTEST_INTERNAL_HAS_STD_SPAN
+
// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
+//
+// NOTE: Since std::span does not have const_iterator until C++23, it would
+// fail IsContainerTest before C++23. However, IsContainerTest only uses
+// the presence of const_iterator to avoid treating iterators as containers
+// because of iterator::iterator. Which means std::span satisfies the *intended*
+// condition of IsContainerTest.
struct ContainerPrinter {
template <typename T,
typename = typename std::enable_if<
- (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
- !IsRecursiveContainer<T>::value>::type>
+ ((sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
+ !IsRecursiveContainer<T>::value) ||
+ IsStdSpan<T>::value>::type>
static void PrintValue(const T& container, std::ostream* os) {
const size_t kMaxCount = 32; // The maximum number of elements to print.
*os << '{';
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index b5570b8..35544a0 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -208,6 +208,8 @@
// or
// UniversalPrinter<absl::optional>
// specializations. Always defined to 0 or 1.
+// GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter<std::span>
+// specializations. Always defined to 0 or 1
// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
// Matcher<absl::string_view>
// specializations. Always defined to 0 or 1.
@@ -2407,6 +2409,16 @@
#define GTEST_INTERNAL_HAS_OPTIONAL 0
#endif
+#ifdef __has_include
+#if __has_include(<span>) && GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#define GTEST_INTERNAL_HAS_STD_SPAN 1
+#endif // __has_include(<span>) && GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#endif // __has_include
+
+#ifndef GTEST_INTERNAL_HAS_STD_SPAN
+#define GTEST_INTERNAL_HAS_STD_SPAN 0
+#endif
+
#ifdef GTEST_HAS_ABSL
// Always use absl::string_view for Matcher<> specializations if googletest
// is built with absl support.
diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc
index bee0ca4..d5061be 100644
--- a/googletest/test/googletest-printers-test.cc
+++ b/googletest/test/googletest-printers-test.cc
@@ -54,11 +54,16 @@
#include "gtest/gtest-printers.h"
#include "gtest/gtest.h"
+#include "gtest/internal/gtest-port.h"
#ifdef GTEST_HAS_ABSL
#include "absl/strings/str_format.h"
#endif
+#if GTEST_INTERNAL_HAS_STD_SPAN
+#include <span> // NOLINT
+#endif // GTEST_INTERNAL_HAS_STD_SPAN
+
// Some user-defined types for testing the universal value printer.
// An anonymous enum type.
@@ -1179,6 +1184,17 @@
EXPECT_EQ("{ 1, 2 }", Print(v));
}
+TEST(PrintStlContainerTest, StdSpan) {
+#if GTEST_INTERNAL_HAS_STD_SPAN
+ int a[] = {3, 6, 5};
+ std::span<int> s = a;
+
+ EXPECT_EQ("{ 3, 6, 5 }", Print(s));
+#else
+ GTEST_SKIP() << "Does not have std::span.";
+#endif // GTEST_INTERNAL_HAS_STD_SPAN
+}
+
TEST(PrintStlContainerTest, LongSequence) {
const int a[100] = {1, 2, 3};
const vector<int> v(a, a + 100);