diff --git a/api/units/BUILD.gn b/api/units/BUILD.gn index 4f809b1e6c..e86999d666 100644 --- a/api/units/BUILD.gn +++ b/api/units/BUILD.gn @@ -85,6 +85,7 @@ if (rtc_include_tests) { ":data_size", ":time_delta", ":timestamp", + "../../rtc_base:logging", "../../test:test_support", ] } diff --git a/api/units/data_rate.h b/api/units/data_rate.h index 9b09aa92cd..ccbebdcba2 100644 --- a/api/units/data_rate.h +++ b/api/units/data_rate.h @@ -107,6 +107,9 @@ inline DataSize operator*(const TimeDelta duration, const DataRate rate) { } std::string ToString(DataRate value); +inline std::string ToLogString(DataRate value) { + return ToString(value); +} #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) diff --git a/api/units/data_rate_unittest.cc b/api/units/data_rate_unittest.cc index 996298c1fc..e5bfc573d9 100644 --- a/api/units/data_rate_unittest.cc +++ b/api/units/data_rate_unittest.cc @@ -9,11 +9,19 @@ */ #include "api/units/data_rate.h" +#include "rtc_base/logging.h" #include "test/gtest.h" namespace webrtc { namespace test { +TEST(DataRateTest, CompilesWithChecksAndLogs) { + DataRate a = DataRate::kbps(300); + DataRate b = DataRate::kbps(210); + RTC_CHECK_GT(a, b); + RTC_LOG(LS_INFO) << a; +} + TEST(DataRateTest, ConstExpr) { constexpr int64_t kValue = 12345; constexpr DataRate kDataRateZero = DataRate::Zero(); diff --git a/api/units/data_size.h b/api/units/data_size.h index 90ef00da52..24a1351104 100644 --- a/api/units/data_size.h +++ b/api/units/data_size.h @@ -52,6 +52,9 @@ class DataSize final : public rtc_units_impl::RelativeUnit { }; std::string ToString(DataSize value); +inline std::string ToLogString(DataSize value) { + return ToString(value); +} #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) diff --git a/api/units/time_delta.h b/api/units/time_delta.h index e5172f4048..f8c6af457e 100644 --- a/api/units/time_delta.h +++ b/api/units/time_delta.h @@ -95,6 +95,9 @@ class TimeDelta final : public rtc_units_impl::RelativeUnit { }; std::string ToString(TimeDelta value); +inline std::string ToLogString(TimeDelta value) { + return ToString(value); +} #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) diff --git a/api/units/timestamp.h b/api/units/timestamp.h index 370a091f28..ed757af668 100644 --- a/api/units/timestamp.h +++ b/api/units/timestamp.h @@ -133,6 +133,9 @@ class Timestamp final : public rtc_units_impl::UnitBase { }; std::string ToString(Timestamp value); +inline std::string ToLogString(Timestamp value) { + return ToString(value); +} #ifdef UNIT_TEST inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) diff --git a/rtc_base/checks.h b/rtc_base/checks.h index b351ad2e21..dbdc004433 100644 --- a/rtc_base/checks.h +++ b/rtc_base/checks.h @@ -125,6 +125,15 @@ struct Val { T val; }; +// Case for when we need to construct a temp string and then print that. +// (We can't use Val +// because we need somewhere to store the temp string.) +struct ToStringVal { + static constexpr CheckArgType Type() { return CheckArgType::kStdString; } + const std::string* GetVal() const { return &val; } + std::string val; +}; + inline Val MakeVal(int x) { return {x}; } @@ -178,6 +187,15 @@ MakeVal(T x) { return {static_cast::type>(x)}; } +template ::type, + typename T2 = decltype(ToLogString(std::declval())), + typename std::enable_if::value>::type* = + nullptr> +ToStringVal MakeVal(const T& x) { + return {ToLogString(x)}; +} + // Ephemeral type that represents the result of the logging << operator. template class LogStreamer; diff --git a/rtc_base/logging.h b/rtc_base/logging.h index 3f48eeb0de..362aeae73c 100644 --- a/rtc_base/logging.h +++ b/rtc_base/logging.h @@ -186,11 +186,10 @@ struct Val { T val; }; -// TODO(bugs.webrtc.org/9278): Get rid of this specialization when callers -// don't need it anymore. No in-tree caller does, but some external callers -// still do. -template <> -struct Val { +// Case for when we need to construct a temp string and then print that. +// (We can't use Val +// because we need somewhere to store the temp string.) +struct ToStringVal { static constexpr LogArgType Type() { return LogArgType::kStdString; } const std::string* GetVal() const { return &val; } std::string val; @@ -265,26 +264,45 @@ inline Val MakeVal( } #endif +template +struct has_to_log_string : std::false_type {}; +template +struct has_to_log_string< + T, + typename std::enable_if< + std::is_same()))>::value>::type> + : std::true_type {}; + // Handle arbitrary types other than the above by falling back to stringstream. // TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need // it anymore. No in-tree caller does, but some external callers still do. template < typename T, - typename T1 = - typename std::remove_cv::type>::type, + typename T1 = typename std::decay::type, typename std::enable_if< std::is_class::value && !std::is_same::value && !std::is_same::value && + !has_to_log_string::value && #ifdef WEBRTC_ANDROID !std::is_same::value && #endif !std::is_same::value>::type* = nullptr> -Val MakeVal(const T& x) { +ToStringVal MakeVal(const T& x) { std::ostringstream os; // no-presubmit-check TODO(webrtc:8982) os << x; return {os.str()}; } +template < + typename T, + typename T1 = typename std::decay::type, + typename std::enable_if::value && + has_to_log_string::value>::type* = nullptr> +ToStringVal MakeVal(const T& x) { + return {ToLogString(x)}; +} + void Log(const LogArgType* fmt, ...); // Ephemeral type that represents the result of the logging << operator.