From 98b0da181b742dd6bdf50b8652b82a807bfed714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Bostr=C3=B6m?= Date: Tue, 9 Jan 2024 15:40:42 +0100 Subject: [PATCH] Move RTCStatsMember+Interface to a separate file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure move CL. Avoids circular dependency in a future CL. Bug: webrtc:15164 Change-Id: Ide423be95db30b7f3cfaea946e18e12980175f2b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/333920 Reviewed-by: Harald Alvestrand Commit-Queue: Henrik Boström Cr-Commit-Position: refs/heads/main@{#41496} --- api/BUILD.gn | 1 + api/stats/rtc_stats.h | 183 +------------------------- api/stats/rtc_stats_member.h | 207 ++++++++++++++++++++++++++++++ stats/BUILD.gn | 1 + stats/rtc_stats.cc | 224 -------------------------------- stats/rtc_stats_member.cc | 240 +++++++++++++++++++++++++++++++++++ 6 files changed, 450 insertions(+), 406 deletions(-) create mode 100644 api/stats/rtc_stats_member.h create mode 100644 stats/rtc_stats_member.cc diff --git a/api/BUILD.gn b/api/BUILD.gn index 341b39cdbe..f09b353eef 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -773,6 +773,7 @@ rtc_source_set("rtc_stats_api") { sources = [ "stats/rtc_stats.h", "stats/rtc_stats_collector_callback.h", + "stats/rtc_stats_member.h", "stats/rtc_stats_report.h", "stats/rtcstats_objects.h", ] diff --git a/api/stats/rtc_stats.h b/api/stats/rtc_stats.h index 6cc39a309f..d71b10d8e7 100644 --- a/api/stats/rtc_stats.h +++ b/api/stats/rtc_stats.h @@ -20,7 +20,7 @@ #include #include -#include "absl/types/optional.h" +#include "api/stats/rtc_stats_member.h" #include "api/units/timestamp.h" #include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" @@ -28,8 +28,6 @@ namespace webrtc { -class RTCStatsMemberInterface; - // Abstract base class for RTCStats-derived dictionaries, see // https://w3c.github.io/webrtc-stats/. // @@ -206,185 +204,6 @@ class RTC_EXPORT RTCStats { return parent_class::MembersOfThisObjectAndAncestors(0); \ } -// Interface for `RTCStats` members, which have a name and a value of a type -// defined in a subclass. Only the types listed in `Type` are supported, these -// are implemented by `RTCStatsMember`. The value of a member may be -// undefined, the value can only be read if `is_defined`. -class RTCStatsMemberInterface { - public: - // Member value types. - enum Type { - kBool, // bool - kInt32, // int32_t - kUint32, // uint32_t - kInt64, // int64_t - kUint64, // uint64_t - kDouble, // double - kString, // std::string - - kSequenceBool, // std::vector - kSequenceInt32, // std::vector - kSequenceUint32, // std::vector - kSequenceInt64, // std::vector - kSequenceUint64, // std::vector - kSequenceDouble, // std::vector - kSequenceString, // std::vector - - kMapStringUint64, // std::map - kMapStringDouble, // std::map - }; - - virtual ~RTCStatsMemberInterface() {} - - const char* name() const { return name_; } - virtual Type type() const = 0; - virtual bool is_sequence() const = 0; - virtual bool is_string() const = 0; - virtual bool is_defined() const = 0; - // Type and value comparator. The names are not compared. These operators are - // exposed for testing. - bool operator==(const RTCStatsMemberInterface& other) const { - return IsEqual(other); - } - bool operator!=(const RTCStatsMemberInterface& other) const { - return !(*this == other); - } - virtual std::string ValueToString() const = 0; - // This is the same as ValueToString except for kInt64 and kUint64 types, - // where the value is represented as a double instead of as an integer. - // Since JSON stores numbers as floating point numbers, very large integers - // cannot be accurately represented, so we prefer to display them as doubles - // instead. - virtual std::string ValueToJson() const = 0; - - template - const T& cast_to() const { - RTC_DCHECK_EQ(type(), T::StaticType()); - return static_cast(*this); - } - - protected: - explicit RTCStatsMemberInterface(const char* name) : name_(name) {} - - virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; - - const char* const name_; -}; - -// Template implementation of `RTCStatsMemberInterface`. -// The supported types are the ones described by -// `RTCStatsMemberInterface::Type`. -template -class RTCStatsMember : public RTCStatsMemberInterface { - public: - explicit RTCStatsMember(const char* name) - : RTCStatsMemberInterface(name), value_() {} - RTCStatsMember(const char* name, const T& value) - : RTCStatsMemberInterface(name), value_(value) {} - RTCStatsMember(const char* name, T&& value) - : RTCStatsMemberInterface(name), value_(std::move(value)) {} - explicit RTCStatsMember(const RTCStatsMember& other) - : RTCStatsMemberInterface(other.name_), value_(other.value_) {} - explicit RTCStatsMember(RTCStatsMember&& other) - : RTCStatsMemberInterface(other.name_), value_(std::move(other.value_)) {} - - static Type StaticType(); - Type type() const override { return StaticType(); } - bool is_sequence() const override; - bool is_string() const override; - bool is_defined() const override { return value_.has_value(); } - std::string ValueToString() const override; - std::string ValueToJson() const override; - - template - inline T ValueOrDefault(U default_value) const { - return value_.value_or(default_value); - } - - // Assignment operators. - T& operator=(const T& value) { - value_ = value; - return value_.value(); - } - T& operator=(const T&& value) { - value_ = std::move(value); - return value_.value(); - } - - // Getter methods that look the same as absl::optional. Please prefer these - // in order to unblock replacing RTCStatsMember with absl::optional in - // the future (https://crbug.com/webrtc/15164). - bool has_value() const { return value_.has_value(); } - const T& value() const { return value_.value(); } - T& value() { return value_.value(); } - T& operator*() { - RTC_DCHECK(value_); - return *value_; - } - const T& operator*() const { - RTC_DCHECK(value_); - return *value_; - } - T* operator->() { - RTC_DCHECK(value_); - return &(*value_); - } - const T* operator->() const { - RTC_DCHECK(value_); - return &(*value_); - } - - protected: - bool IsEqual(const RTCStatsMemberInterface& other) const override { - if (type() != other.type()) - return false; - const RTCStatsMember& other_t = - static_cast&>(other); - return value_ == other_t.value_; - } - - private: - absl::optional value_; -}; - -namespace rtc_stats_internal { - -typedef std::map MapStringUint64; -typedef std::map MapStringDouble; - -} // namespace rtc_stats_internal - -#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ - template <> \ - RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember::StaticType(); \ - template <> \ - RTC_EXPORT bool RTCStatsMember::is_sequence() const; \ - template <> \ - RTC_EXPORT bool RTCStatsMember::is_string() const; \ - template <> \ - RTC_EXPORT std::string RTCStatsMember::ValueToString() const; \ - template <> \ - RTC_EXPORT std::string RTCStatsMember::ValueToJson() const; \ - extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ - RTCStatsMember - -WEBRTC_DECLARE_RTCSTATSMEMBER(bool); -WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(double); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); - } // namespace webrtc #endif // API_STATS_RTC_STATS_H_ diff --git a/api/stats/rtc_stats_member.h b/api/stats/rtc_stats_member.h new file mode 100644 index 0000000000..09e3836359 --- /dev/null +++ b/api/stats/rtc_stats_member.h @@ -0,0 +1,207 @@ +/* + * Copyright 2023 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_STATS_RTC_STATS_MEMBER_H_ +#define API_STATS_RTC_STATS_MEMBER_H_ + +#include +#include +#include +#include + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/system/rtc_export_template.h" + +namespace webrtc { + +// Interface for `RTCStats` members, which have a name and a value of a type +// defined in a subclass. Only the types listed in `Type` are supported, these +// are implemented by `RTCStatsMember`. The value of a member may be +// undefined, the value can only be read if `is_defined`. +class RTCStatsMemberInterface { + public: + // Member value types. + enum Type { + kBool, // bool + kInt32, // int32_t + kUint32, // uint32_t + kInt64, // int64_t + kUint64, // uint64_t + kDouble, // double + kString, // std::string + + kSequenceBool, // std::vector + kSequenceInt32, // std::vector + kSequenceUint32, // std::vector + kSequenceInt64, // std::vector + kSequenceUint64, // std::vector + kSequenceDouble, // std::vector + kSequenceString, // std::vector + + kMapStringUint64, // std::map + kMapStringDouble, // std::map + }; + + virtual ~RTCStatsMemberInterface() {} + + const char* name() const { return name_; } + virtual Type type() const = 0; + virtual bool is_sequence() const = 0; + virtual bool is_string() const = 0; + virtual bool is_defined() const = 0; + // Type and value comparator. The names are not compared. These operators are + // exposed for testing. + bool operator==(const RTCStatsMemberInterface& other) const { + return IsEqual(other); + } + bool operator!=(const RTCStatsMemberInterface& other) const { + return !(*this == other); + } + virtual std::string ValueToString() const = 0; + // This is the same as ValueToString except for kInt64 and kUint64 types, + // where the value is represented as a double instead of as an integer. + // Since JSON stores numbers as floating point numbers, very large integers + // cannot be accurately represented, so we prefer to display them as doubles + // instead. + virtual std::string ValueToJson() const = 0; + + template + const T& cast_to() const { + RTC_DCHECK_EQ(type(), T::StaticType()); + return static_cast(*this); + } + + protected: + explicit RTCStatsMemberInterface(const char* name) : name_(name) {} + + virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; + + const char* const name_; +}; + +// Template implementation of `RTCStatsMemberInterface`. +// The supported types are the ones described by +// `RTCStatsMemberInterface::Type`. +template +class RTCStatsMember : public RTCStatsMemberInterface { + public: + explicit RTCStatsMember(const char* name) + : RTCStatsMemberInterface(name), value_() {} + RTCStatsMember(const char* name, const T& value) + : RTCStatsMemberInterface(name), value_(value) {} + RTCStatsMember(const char* name, T&& value) + : RTCStatsMemberInterface(name), value_(std::move(value)) {} + explicit RTCStatsMember(const RTCStatsMember& other) + : RTCStatsMemberInterface(other.name_), value_(other.value_) {} + explicit RTCStatsMember(RTCStatsMember&& other) + : RTCStatsMemberInterface(other.name_), value_(std::move(other.value_)) {} + + static Type StaticType(); + Type type() const override { return StaticType(); } + bool is_sequence() const override; + bool is_string() const override; + bool is_defined() const override { return value_.has_value(); } + std::string ValueToString() const override; + std::string ValueToJson() const override; + + template + inline T ValueOrDefault(U default_value) const { + return value_.value_or(default_value); + } + + // Assignment operators. + T& operator=(const T& value) { + value_ = value; + return value_.value(); + } + T& operator=(const T&& value) { + value_ = std::move(value); + return value_.value(); + } + + // Getter methods that look the same as absl::optional. Please prefer these + // in order to unblock replacing RTCStatsMember with absl::optional in + // the future (https://crbug.com/webrtc/15164). + bool has_value() const { return value_.has_value(); } + const T& value() const { return value_.value(); } + T& value() { return value_.value(); } + T& operator*() { + RTC_DCHECK(value_); + return *value_; + } + const T& operator*() const { + RTC_DCHECK(value_); + return *value_; + } + T* operator->() { + RTC_DCHECK(value_); + return &(*value_); + } + const T* operator->() const { + RTC_DCHECK(value_); + return &(*value_); + } + + protected: + bool IsEqual(const RTCStatsMemberInterface& other) const override { + if (type() != other.type()) + return false; + const RTCStatsMember& other_t = + static_cast&>(other); + return value_ == other_t.value_; + } + + private: + absl::optional value_; +}; + +namespace rtc_stats_internal { + +typedef std::map MapStringUint64; +typedef std::map MapStringDouble; + +} // namespace rtc_stats_internal + +#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ + template <> \ + RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember::StaticType(); \ + template <> \ + RTC_EXPORT bool RTCStatsMember::is_sequence() const; \ + template <> \ + RTC_EXPORT bool RTCStatsMember::is_string() const; \ + template <> \ + RTC_EXPORT std::string RTCStatsMember::ValueToString() const; \ + template <> \ + RTC_EXPORT std::string RTCStatsMember::ValueToJson() const; \ + extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ + RTCStatsMember + +WEBRTC_DECLARE_RTCSTATSMEMBER(bool); +WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(double); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); +WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); + +} // namespace webrtc + +#endif // API_STATS_RTC_STATS_MEMBER_H_ diff --git a/stats/BUILD.gn b/stats/BUILD.gn index b2a0c20473..5890149477 100644 --- a/stats/BUILD.gn +++ b/stats/BUILD.gn @@ -17,6 +17,7 @@ rtc_library("rtc_stats") { cflags = [] sources = [ "rtc_stats.cc", + "rtc_stats_member.cc", "rtc_stats_report.cc", "rtcstats_objects.cc", ] diff --git a/stats/rtc_stats.cc b/stats/rtc_stats.cc index 25bde289c2..21e5d05f43 100644 --- a/stats/rtc_stats.cc +++ b/stats/rtc_stats.cc @@ -12,112 +12,10 @@ #include -#include "rtc_base/arraysize.h" -#include "rtc_base/string_encode.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { -namespace { - -// Produces "[a,b,c]". Works for non-vector `RTCStatsMemberInterface::Type` -// types. -template -std::string VectorToString(const std::vector& vector) { - rtc::StringBuilder sb; - sb << "["; - const char* separator = ""; - for (const T& element : vector) { - sb << separator << rtc::ToString(element); - separator = ","; - } - sb << "]"; - return sb.Release(); -} - -// This overload is required because std::vector range loops don't -// return references but objects, causing -Wrange-loop-analysis diagnostics. -std::string VectorToString(const std::vector& vector) { - rtc::StringBuilder sb; - sb << "["; - const char* separator = ""; - for (bool element : vector) { - sb << separator << rtc::ToString(element); - separator = ","; - } - sb << "]"; - return sb.Release(); -} - -// Produces "[\"a\",\"b\",\"c\"]". Works for vectors of both const char* and -// std::string element types. -template -std::string VectorOfStringsToString(const std::vector& strings) { - rtc::StringBuilder sb; - sb << "["; - const char* separator = ""; - for (const T& element : strings) { - sb << separator << "\"" << rtc::ToString(element) << "\""; - separator = ","; - } - sb << "]"; - return sb.Release(); -} - -template -std::string MapToString(const std::map& map) { - rtc::StringBuilder sb; - sb << "{"; - const char* separator = ""; - for (const auto& element : map) { - sb << separator << rtc::ToString(element.first) << ":" - << rtc::ToString(element.second); - separator = ","; - } - sb << "}"; - return sb.Release(); -} - -template -std::string ToStringAsDouble(const T value) { - // JSON represents numbers as floating point numbers with about 15 decimal - // digits of precision. - char buf[32]; - const int len = std::snprintf(&buf[0], arraysize(buf), "%.16g", - static_cast(value)); - RTC_DCHECK_LE(len, arraysize(buf)); - return std::string(&buf[0], len); -} - -template -std::string VectorToStringAsDouble(const std::vector& vector) { - rtc::StringBuilder sb; - sb << "["; - const char* separator = ""; - for (const T& element : vector) { - sb << separator << ToStringAsDouble(element); - separator = ","; - } - sb << "]"; - return sb.Release(); -} - -template -std::string MapToStringAsDouble(const std::map& map) { - rtc::StringBuilder sb; - sb << "{"; - const char* separator = ""; - for (const auto& element : map) { - sb << separator << "\"" << rtc::ToString(element.first) - << "\":" << ToStringAsDouble(element.second); - separator = ","; - } - sb << "}"; - return sb.Release(); -} - -} // namespace - bool RTCStats::operator==(const RTCStats& other) const { if (type() != other.type() || id() != other.id()) return false; @@ -172,126 +70,4 @@ RTCStats::MembersOfThisObjectAndAncestors(size_t additional_capacity) const { return members; } -#define WEBRTC_DEFINE_RTCSTATSMEMBER(T, type, is_seq, is_str, to_str, to_json) \ - template <> \ - RTCStatsMemberInterface::Type RTCStatsMember::StaticType() { \ - return type; \ - } \ - template <> \ - bool RTCStatsMember::is_sequence() const { \ - return is_seq; \ - } \ - template <> \ - bool RTCStatsMember::is_string() const { \ - return is_str; \ - } \ - template <> \ - std::string RTCStatsMember::ValueToString() const { \ - RTC_DCHECK(value_.has_value()); \ - return to_str; \ - } \ - template <> \ - std::string RTCStatsMember::ValueToJson() const { \ - RTC_DCHECK(value_.has_value()); \ - return to_json; \ - } \ - template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCStatsMember - -WEBRTC_DEFINE_RTCSTATSMEMBER(bool, - kBool, - false, - false, - rtc::ToString(*value_), - rtc::ToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(int32_t, - kInt32, - false, - false, - rtc::ToString(*value_), - rtc::ToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(uint32_t, - kUint32, - false, - false, - rtc::ToString(*value_), - rtc::ToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(int64_t, - kInt64, - false, - false, - rtc::ToString(*value_), - ToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(uint64_t, - kUint64, - false, - false, - rtc::ToString(*value_), - ToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(double, - kDouble, - false, - false, - rtc::ToString(*value_), - ToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::string, - kString, - false, - true, - *value_, - *value_); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceBool, - true, - false, - VectorToString(*value_), - VectorToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceInt32, - true, - false, - VectorToString(*value_), - VectorToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceUint32, - true, - false, - VectorToString(*value_), - VectorToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceInt64, - true, - false, - VectorToString(*value_), - VectorToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceUint64, - true, - false, - VectorToString(*value_), - VectorToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceDouble, - true, - false, - VectorToString(*value_), - VectorToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, - kSequenceString, - true, - false, - VectorOfStringsToString(*value_), - VectorOfStringsToString(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64, - kMapStringUint64, - false, - false, - MapToString(*value_), - MapToStringAsDouble(*value_)); -WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble, - kMapStringDouble, - false, - false, - MapToString(*value_), - MapToStringAsDouble(*value_)); - } // namespace webrtc diff --git a/stats/rtc_stats_member.cc b/stats/rtc_stats_member.cc new file mode 100644 index 0000000000..d7a3f6ccd2 --- /dev/null +++ b/stats/rtc_stats_member.cc @@ -0,0 +1,240 @@ +/* + * Copyright 2023 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/stats/rtc_stats_member.h" + +#include "rtc_base/arraysize.h" +#include "rtc_base/strings/string_builder.h" + +namespace webrtc { + +namespace { + +// Produces "[a,b,c]". Works for non-vector `RTCStatsMemberInterface::Type` +// types. +template +std::string VectorToString(const std::vector& vector) { + rtc::StringBuilder sb; + sb << "["; + const char* separator = ""; + for (const T& element : vector) { + sb << separator << rtc::ToString(element); + separator = ","; + } + sb << "]"; + return sb.Release(); +} + +// This overload is required because std::vector range loops don't +// return references but objects, causing -Wrange-loop-analysis diagnostics. +std::string VectorToString(const std::vector& vector) { + rtc::StringBuilder sb; + sb << "["; + const char* separator = ""; + for (bool element : vector) { + sb << separator << rtc::ToString(element); + separator = ","; + } + sb << "]"; + return sb.Release(); +} + +// Produces "[\"a\",\"b\",\"c\"]". Works for vectors of both const char* and +// std::string element types. +template +std::string VectorOfStringsToString(const std::vector& strings) { + rtc::StringBuilder sb; + sb << "["; + const char* separator = ""; + for (const T& element : strings) { + sb << separator << "\"" << rtc::ToString(element) << "\""; + separator = ","; + } + sb << "]"; + return sb.Release(); +} + +template +std::string MapToString(const std::map& map) { + rtc::StringBuilder sb; + sb << "{"; + const char* separator = ""; + for (const auto& element : map) { + sb << separator << rtc::ToString(element.first) << ":" + << rtc::ToString(element.second); + separator = ","; + } + sb << "}"; + return sb.Release(); +} + +template +std::string ToStringAsDouble(const T value) { + // JSON represents numbers as floating point numbers with about 15 decimal + // digits of precision. + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%.16g", + static_cast(value)); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +template +std::string VectorToStringAsDouble(const std::vector& vector) { + rtc::StringBuilder sb; + sb << "["; + const char* separator = ""; + for (const T& element : vector) { + sb << separator << ToStringAsDouble(element); + separator = ","; + } + sb << "]"; + return sb.Release(); +} + +template +std::string MapToStringAsDouble(const std::map& map) { + rtc::StringBuilder sb; + sb << "{"; + const char* separator = ""; + for (const auto& element : map) { + sb << separator << "\"" << rtc::ToString(element.first) + << "\":" << ToStringAsDouble(element.second); + separator = ","; + } + sb << "}"; + return sb.Release(); +} + +} // namespace + +#define WEBRTC_DEFINE_RTCSTATSMEMBER(T, type, is_seq, is_str, to_str, to_json) \ + template <> \ + RTCStatsMemberInterface::Type RTCStatsMember::StaticType() { \ + return type; \ + } \ + template <> \ + bool RTCStatsMember::is_sequence() const { \ + return is_seq; \ + } \ + template <> \ + bool RTCStatsMember::is_string() const { \ + return is_str; \ + } \ + template <> \ + std::string RTCStatsMember::ValueToString() const { \ + RTC_DCHECK(value_.has_value()); \ + return to_str; \ + } \ + template <> \ + std::string RTCStatsMember::ValueToJson() const { \ + RTC_DCHECK(value_.has_value()); \ + return to_json; \ + } \ + template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCStatsMember + +WEBRTC_DEFINE_RTCSTATSMEMBER(bool, + kBool, + false, + false, + rtc::ToString(*value_), + rtc::ToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(int32_t, + kInt32, + false, + false, + rtc::ToString(*value_), + rtc::ToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(uint32_t, + kUint32, + false, + false, + rtc::ToString(*value_), + rtc::ToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(int64_t, + kInt64, + false, + false, + rtc::ToString(*value_), + ToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(uint64_t, + kUint64, + false, + false, + rtc::ToString(*value_), + ToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(double, + kDouble, + false, + false, + rtc::ToString(*value_), + ToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::string, + kString, + false, + true, + *value_, + *value_); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceBool, + true, + false, + VectorToString(*value_), + VectorToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceInt32, + true, + false, + VectorToString(*value_), + VectorToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceUint32, + true, + false, + VectorToString(*value_), + VectorToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceInt64, + true, + false, + VectorToString(*value_), + VectorToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceUint64, + true, + false, + VectorToString(*value_), + VectorToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceDouble, + true, + false, + VectorToString(*value_), + VectorToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceString, + true, + false, + VectorOfStringsToString(*value_), + VectorOfStringsToString(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64, + kMapStringUint64, + false, + false, + MapToString(*value_), + MapToStringAsDouble(*value_)); +WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble, + kMapStringDouble, + false, + false, + MapToString(*value_), + MapToStringAsDouble(*value_)); + +} // namespace webrtc