diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index d1766e640f..9ccbff7da4 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 // NOLINT +#endif // GTEST_INTERNAL_HAS_STD_SPAN + namespace testing { // Definitions in the internal* namespaces are subject to change without notice. @@ -131,13 +135,32 @@ namespace internal { template void UniversalPrint(const T& value, ::std::ostream* os); +template +struct IsStdSpan { + static constexpr bool value = false; +}; + +#if GTEST_INTERNAL_HAS_STD_SPAN +template +struct IsStdSpan> { + 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 (0)) == sizeof(IsContainer)) && - !IsRecursiveContainer::value>::type> + ((sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value) || + IsStdSpan::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 b5570b8bc9..35544a08a6 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -208,6 +208,8 @@ // or // UniversalPrinter // specializations. Always defined to 0 or 1. +// GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter +// specializations. Always defined to 0 or 1 // GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or // Matcher // specializations. Always defined to 0 or 1. @@ -2407,6 +2409,16 @@ inline ::std::nullopt_t Nullopt() { return ::std::nullopt; } #define GTEST_INTERNAL_HAS_OPTIONAL 0 #endif +#ifdef __has_include +#if __has_include() && GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L +#define GTEST_INTERNAL_HAS_STD_SPAN 1 +#endif // __has_include() && 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 bee0ca4abe..d5061bef26 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 // 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 @@ TEST(PrintStlContainerTest, Vector) { EXPECT_EQ("{ 1, 2 }", Print(v)); } +TEST(PrintStlContainerTest, StdSpan) { +#if GTEST_INTERNAL_HAS_STD_SPAN + int a[] = {3, 6, 5}; + std::span 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 v(a, a + 100);