Relanding #128202 Adding support for enum class in RTC_CHECK and RTC_LOG.

This is a reland of: https://webrtc-review.googlesource.com/c/src/+/128202
Logging unit test has been fixed to unregister the log listener.

Bug: webrtc:10418
Change-Id: Idac9cb71807e16a585ccb7e3e4271aa45d69f547
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/128541
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Amit Hilbuch <amithi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27192}
diff --git a/rtc_base/checks.h b/rtc_base/checks.h
index 2694258..b351ad2 100644
--- a/rtc_base/checks.h
+++ b/rtc_base/checks.h
@@ -168,6 +168,16 @@
   return {x};
 }
 
+// The enum class types are not implicitly convertible to arithmetic types.
+template <
+    typename T,
+    typename std::enable_if<std::is_enum<T>::value &&
+                            !std::is_arithmetic<T>::value>::type* = nullptr>
+inline decltype(MakeVal(std::declval<typename std::underlying_type<T>::type>()))
+MakeVal(T x) {
+  return {static_cast<typename std::underlying_type<T>::type>(x)};
+}
+
 // Ephemeral type that represents the result of the logging << operator.
 template <typename... Ts>
 class LogStreamer;
@@ -176,18 +186,18 @@
 template <>
 class LogStreamer<> final {
  public:
-  template <
-      typename U,
-      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<std::is_arithmetic<U>::value ||
+                                    std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
       U arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
                                                              this);
   }
 
-  template <
-      typename U,
-      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<!std::is_arithmetic<U>::value &&
+                                    !std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
       const U& arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
@@ -222,18 +232,18 @@
   RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
       : arg_(arg), prior_(prior) {}
 
-  template <
-      typename U,
-      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<std::is_arithmetic<U>::value ||
+                                    std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
   operator<<(U arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
         MakeVal(arg), this);
   }
 
-  template <
-      typename U,
-      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<!std::is_arithmetic<U>::value &&
+                                    !std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
   operator<<(const U& arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index 5cd4f72..3f48eeb 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -248,6 +248,16 @@
   return {x};
 }
 
+// The enum class types are not implicitly convertible to arithmetic types.
+template <
+    typename T,
+    typename std::enable_if<std::is_enum<T>::value &&
+                            !std::is_arithmetic<T>::value>::type* = nullptr>
+inline decltype(MakeVal(std::declval<typename std::underlying_type<T>::type>()))
+MakeVal(T x) {
+  return {static_cast<typename std::underlying_type<T>::type>(x)};
+}
+
 #ifdef WEBRTC_ANDROID
 inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal(
     const LogMetadataTag& x) {
@@ -285,18 +295,18 @@
 template <>
 class LogStreamer<> final {
  public:
-  template <
-      typename U,
-      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<std::is_arithmetic<U>::value ||
+                                    std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
       U arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
                                                              this);
   }
 
-  template <
-      typename U,
-      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<!std::is_arithmetic<U>::value &&
+                                    !std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
       const U& arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
@@ -318,18 +328,18 @@
   RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
       : arg_(arg), prior_(prior) {}
 
-  template <
-      typename U,
-      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<std::is_arithmetic<U>::value ||
+                                    std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
   operator<<(U arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
         MakeVal(arg), this);
   }
 
-  template <
-      typename U,
-      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  template <typename U,
+            typename std::enable_if<!std::is_arithmetic<U>::value &&
+                                    !std::is_enum<U>::value>::type* = nullptr>
   RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
   operator<<(const U& arg) const {
     return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
diff --git a/rtc_base/logging_unittest.cc b/rtc_base/logging_unittest.cc
index e49440d..54f6549 100644
--- a/rtc_base/logging_unittest.cc
+++ b/rtc_base/logging_unittest.cc
@@ -368,4 +368,18 @@
                    << " total bytes logged: " << str.size();
 }
 
+TEST(LogTest, EnumsAreSupported) {
+  enum class TestEnum { kValue0 = 0, kValue1 = 1 };
+  std::string str;
+  LogSinkImpl<StringStream> stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+  RTC_LOG(LS_INFO) << "[" << TestEnum::kValue0 << "]";
+  EXPECT_NE(std::string::npos, str.find("[0]"));
+  EXPECT_EQ(std::string::npos, str.find("[1]"));
+  RTC_LOG(LS_INFO) << "[" << TestEnum::kValue1 << "]";
+  EXPECT_NE(std::string::npos, str.find("[1]"));
+  LogMessage::RemoveLogToStream(&stream);
+  stream.Close();
+}
+
 }  // namespace rtc