Index: webrtc/base/optional.h |
diff --git a/webrtc/base/optional.h b/webrtc/base/optional.h |
index f5354ee0f25fdb6eabcf6fa367e3db64152681ee..c8ed069d55570b1f6bf5e7191bcf121626dd0a0b 100644 |
--- a/webrtc/base/optional.h |
+++ b/webrtc/base/optional.h |
@@ -15,6 +15,11 @@ |
#include <memory> |
#include <utility> |
+#ifdef UNIT_TEST |
+#include <iomanip> |
+#include <ostream> |
+#endif // UNIT_TEST |
+ |
#include "webrtc/base/array_view.h" |
#include "webrtc/base/checks.h" |
#include "webrtc/base/sanitizer.h" |
@@ -25,7 +30,9 @@ namespace optional_internal { |
#if RTC_HAS_ASAN |
-// This is a non-inlined function. The optimizer can't see inside it. |
+// This is a non-inlined function. The optimizer can't see inside it. It |
+// prevents the compiler from generating optimized code that reads value_ even |
+// if it is unset. Although safe, this causes memory sanitizers to complain. |
void* FunctionThatDoesNothingImpl(void*); |
template <typename T> |
@@ -296,6 +303,98 @@ class Optional final { |
}; |
}; |
+#ifdef UNIT_TEST |
+namespace optional_internal { |
+ |
+// Checks if there's a valid PrintTo(const T&, std::ostream*) call for T. |
+template <typename T> |
+struct HasPrintTo { |
+ private: |
+ struct No {}; |
+ |
+ template <typename T2> |
+ static auto Test(const T2& obj) |
+ -> decltype(PrintTo(obj, std::declval<std::ostream*>())); |
+ |
+ template <typename> |
+ static No Test(...); |
+ |
+ public: |
+ static constexpr bool value = |
+ !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value; |
+}; |
+ |
+// Checks if there's a valid operator<<(std::ostream&, const T&) call for T. |
+template <typename T> |
+struct HasOstreamOperator { |
+ private: |
+ struct No {}; |
+ |
+ template <typename T2> |
+ static auto Test(const T2& obj) |
+ -> decltype(std::declval<std::ostream&>() << obj); |
+ |
+ template <typename> |
+ static No Test(...); |
+ |
+ public: |
+ static constexpr bool value = |
+ !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value; |
+}; |
+ |
+// Prefer using PrintTo to print the object. |
+template <typename T> |
+typename std::enable_if<HasPrintTo<T>::value, void>::type OptionalPrintToHelper( |
+ const T& value, |
+ std::ostream* os) { |
+ PrintTo(value, os); |
+} |
+ |
+// Fall back to operator<<(std::ostream&, ...) if it exists. |
+template <typename T> |
+typename std::enable_if<HasOstreamOperator<T>::value && !HasPrintTo<T>::value, |
+ void>::type |
+OptionalPrintToHelper(const T& value, std::ostream* os) { |
+ *os << value; |
+} |
+ |
+inline void OptionalPrintObjectBytes(const unsigned char* bytes, |
+ size_t size, |
+ std::ostream* os) { |
+ *os << "<optional with " << size << "-byte object ["; |
+ for (size_t i = 0; i != size; ++i) { |
+ *os << (i == 0 ? "" : ((i & 1) ? "-" : " ")); |
+ *os << std::hex << std::setw(2) << std::setfill('0') |
+ << static_cast<int>(bytes[i]); |
+ } |
+ *os << "]>"; |
+} |
+ |
+// As a final back-up, just print the contents of the objcets byte-wise. |
+template <typename T> |
+typename std::enable_if<!HasOstreamOperator<T>::value && !HasPrintTo<T>::value, |
+ void>::type |
+OptionalPrintToHelper(const T& value, std::ostream* os) { |
+ OptionalPrintObjectBytes(reinterpret_cast<const unsigned char*>(&value), |
+ sizeof(value), os); |
+} |
+ |
+} // namespace optional_internal |
+ |
+// PrintTo is used by gtest to print out the results of tests. We want to ensure |
+// the object contained in an Optional can be printed out if it's set, while |
+// avoiding touching the object's storage if it is undefined. |
+template <typename T> |
+void PrintTo(const rtc::Optional<T>& opt, std::ostream* os) { |
+ if (opt) { |
+ optional_internal::OptionalPrintToHelper(*opt, os); |
+ } else { |
+ *os << "<empty optional>"; |
+ } |
+} |
+ |
+#endif // UNIT_TEST |
+ |
} // namespace rtc |
#endif // WEBRTC_BASE_OPTIONAL_H_ |