diff --git a/api/BUILD.gn b/api/BUILD.gn index 2dba446a98..6af4fa5517 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -774,6 +774,7 @@ rtc_source_set("rtc_stats_api") { "stats/attribute.h", "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/attribute.h b/api/stats/attribute.h index d5fb290750..09211f469c 100644 --- a/api/stats/attribute.h +++ b/api/stats/attribute.h @@ -16,41 +16,37 @@ #include #include -#include "absl/types/optional.h" #include "absl/types/variant.h" -#include "rtc_base/checks.h" +#include "api/stats/rtc_stats_member.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { -// TODO(https://crbug.com/webrtc/15164): Migrate all uses of RTCStatsMember to -// absl::optional and delete this type alias. -template -using RTCStatsMember = absl::optional; - // A light-weight wrapper of an RTCStats attribute (an individual metric). class RTC_EXPORT Attribute { public: - typedef absl::variant*, - const absl::optional*, - const absl::optional*, - const absl::optional*, - const absl::optional*, - const absl::optional*, - const absl::optional*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*, - const absl::optional>*> + // TODO(https://crbug.com/webrtc/15164): Replace uses of RTCStatsMember + // with absl::optional and update these pointer types. + typedef absl::variant*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*> StatVariant; template - Attribute(const char* name, const absl::optional* attribute) + explicit Attribute(const char* name, const RTCStatsMember* attribute) : name_(name), attribute_(attribute) {} const char* name() const; @@ -59,18 +55,21 @@ class RTC_EXPORT Attribute { bool has_value() const; template bool holds_alternative() const { - return absl::holds_alternative*>(attribute_); + return absl::holds_alternative*>(attribute_); } template - const absl::optional& as_optional() const { + absl::optional as_optional() const { RTC_CHECK(holds_alternative()); - return *absl::get*>(attribute_); + if (!has_value()) { + return absl::nullopt; + } + return absl::optional(get()); } template const T& get() const { RTC_CHECK(holds_alternative()); RTC_CHECK(has_value()); - return absl::get*>(attribute_)->value(); + return absl::get*>(attribute_)->value(); } bool is_sequence() const; diff --git a/api/stats/rtc_stats.h b/api/stats/rtc_stats.h index 678108109a..edd293f5c9 100644 --- a/api/stats/rtc_stats.h +++ b/api/stats/rtc_stats.h @@ -21,6 +21,7 @@ #include #include "api/stats/attribute.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" diff --git a/api/stats/rtc_stats_member.h b/api/stats/rtc_stats_member.h new file mode 100644 index 0000000000..9039569ede --- /dev/null +++ b/api/stats/rtc_stats_member.h @@ -0,0 +1,185 @@ +/* + * 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() {} + + virtual Type type() const = 0; + virtual bool is_sequence() const = 0; + virtual bool is_string() const = 0; + virtual bool has_value() 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 const RTCStatsMemberInterface* member_ptr() const { return this; } + template + const T& cast_to() const { + RTC_DCHECK_EQ(type(), T::StaticType()); + return static_cast(*member_ptr()); + } + + protected: + virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; +}; + +// Template implementation of `RTCStatsMemberInterface`. +// The supported types are the ones described by +// `RTCStatsMemberInterface::Type`. +template +class RTCStatsMember : public RTCStatsMemberInterface { + public: + RTCStatsMember() {} + explicit RTCStatsMember(const T& value) : value_(value) {} + + static Type StaticType(); + Type type() const override { return StaticType(); } + bool is_sequence() const override; + bool is_string() const override; + + template + inline T value_or(U default_value) const { + return value_.value_or(default_value); + } + // TODO(https://crbug.com/webrtc/15164): Migrate to value_or() and delete. + template + inline T ValueOrDefault(U default_value) const { + return 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 override { 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_); + } + + 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; \ + 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 76edc441cb..8993272921 100644 --- a/stats/BUILD.gn +++ b/stats/BUILD.gn @@ -18,6 +18,7 @@ rtc_library("rtc_stats") { sources = [ "attribute.cc", "rtc_stats.cc", + "rtc_stats_member.cc", "rtc_stats_report.cc", "rtcstats_objects.cc", ] diff --git a/stats/attribute.cc b/stats/attribute.cc index cf49cb2311..fab948b1bd 100644 --- a/stats/attribute.cc +++ b/stats/attribute.cc @@ -25,12 +25,12 @@ namespace { struct VisitIsSequence { // Any type of vector is a sequence. template - bool operator()(const absl::optional>* attribute) { + bool operator()(const RTCStatsMember>* attribute) { return true; } // Any other type is not. template - bool operator()(const absl::optional* attribute) { + bool operator()(const RTCStatsMember* attribute) { return false; } }; @@ -62,7 +62,7 @@ struct VisitToString { // Vector attributes. template - std::string operator()(const absl::optional>* attribute) { + std::string operator()(const RTCStatsMember>* attribute) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; @@ -84,7 +84,7 @@ struct VisitToString { // Map attributes. template std::string operator()( - const absl::optional>* attribute) { + const RTCStatsMember>* attribute) { rtc::StringBuilder sb; sb << "{"; const char* separator = ""; @@ -106,18 +106,21 @@ struct VisitToString { } // Simple attributes. template - std::string operator()(const absl::optional* attribute) { + std::string operator()(const RTCStatsMember* attribute) { return ValueToString(attribute->value()); } }; struct VisitIsEqual { template - bool operator()(const absl::optional* attribute) { + bool operator()(const RTCStatsMember* attribute) { if (!other.holds_alternative()) { return false; } - return *attribute == other.as_optional(); + absl::optional attribute_as_optional = + attribute->has_value() ? absl::optional(attribute->value()) + : absl::nullopt; + return attribute_as_optional == other.as_optional(); } const Attribute& other; @@ -143,7 +146,7 @@ bool Attribute::is_sequence() const { } bool Attribute::is_string() const { - return absl::holds_alternative*>( + return absl::holds_alternative*>( attribute_); } diff --git a/stats/rtc_stats_member.cc b/stats/rtc_stats_member.cc new file mode 100644 index 0000000000..3f91988ed0 --- /dev/null +++ b/stats/rtc_stats_member.cc @@ -0,0 +1,62 @@ +/* + * 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" + +namespace webrtc { + +#define WEBRTC_DEFINE_RTCSTATSMEMBER(T, type, is_seq, is_str) \ + 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 class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCStatsMember + +WEBRTC_DEFINE_RTCSTATSMEMBER(bool, kBool, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(int32_t, kInt32, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(uint32_t, kUint32, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(int64_t, kInt64, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(uint64_t, kUint64, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(double, kDouble, false, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::string, kString, false, true); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceBool, true, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceInt32, true, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceUint32, + true, + false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceInt64, true, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceUint64, + true, + false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceDouble, true, false); +WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, + kSequenceString, + true, + false); +WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64, + kMapStringUint64, + false, + false); +WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble, + kMapStringDouble, + false, + false); + +} // namespace webrtc diff --git a/stats/rtc_stats_unittest.cc b/stats/rtc_stats_unittest.cc index 1098f04b65..fd90692875 100644 --- a/stats/rtc_stats_unittest.cc +++ b/stats/rtc_stats_unittest.cc @@ -166,8 +166,7 @@ TEST(RTCStatsTest, EqualityOperator) { stats_with_all_values.m_map_string_double = std::map(); EXPECT_NE(stats_with_all_values, empty_stats); EXPECT_EQ(stats_with_all_values, stats_with_all_values); - EXPECT_NE(stats_with_all_values.GetAttribute(stats_with_all_values.m_int32), - stats_with_all_values.GetAttribute(stats_with_all_values.m_uint32)); + EXPECT_NE(stats_with_all_values.m_int32, stats_with_all_values.m_uint32); RTCTestStats one_member_different[] = { stats_with_all_values, stats_with_all_values, stats_with_all_values, @@ -393,42 +392,71 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) { TEST(RTCStatsTest, IsSequence) { RTCTestStats stats("statsId", Timestamp::Micros(42)); - EXPECT_FALSE(stats.GetAttribute(stats.m_bool).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_int32).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_uint32).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_int64).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_uint64).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_double).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_string).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_bool).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_int32).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_uint32).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_int64).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_uint64).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_double).is_sequence()); - EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_string).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_uint64).is_sequence()); - EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_double).is_sequence()); + EXPECT_FALSE(stats.m_bool.is_sequence()); + EXPECT_FALSE(stats.m_int32.is_sequence()); + EXPECT_FALSE(stats.m_uint32.is_sequence()); + EXPECT_FALSE(stats.m_int64.is_sequence()); + EXPECT_FALSE(stats.m_uint64.is_sequence()); + EXPECT_FALSE(stats.m_double.is_sequence()); + EXPECT_FALSE(stats.m_string.is_sequence()); + EXPECT_TRUE(stats.m_sequence_bool.is_sequence()); + EXPECT_TRUE(stats.m_sequence_int32.is_sequence()); + EXPECT_TRUE(stats.m_sequence_uint32.is_sequence()); + EXPECT_TRUE(stats.m_sequence_int64.is_sequence()); + EXPECT_TRUE(stats.m_sequence_uint64.is_sequence()); + EXPECT_TRUE(stats.m_sequence_double.is_sequence()); + EXPECT_TRUE(stats.m_sequence_string.is_sequence()); + EXPECT_FALSE(stats.m_map_string_uint64.is_sequence()); + EXPECT_FALSE(stats.m_map_string_double.is_sequence()); +} + +TEST(RTCStatsTest, Type) { + RTCTestStats stats("statsId", Timestamp::Micros(42)); + EXPECT_EQ(RTCStatsMemberInterface::kBool, stats.m_bool.type()); + EXPECT_EQ(RTCStatsMemberInterface::kInt32, stats.m_int32.type()); + EXPECT_EQ(RTCStatsMemberInterface::kUint32, stats.m_uint32.type()); + EXPECT_EQ(RTCStatsMemberInterface::kInt64, stats.m_int64.type()); + EXPECT_EQ(RTCStatsMemberInterface::kUint64, stats.m_uint64.type()); + EXPECT_EQ(RTCStatsMemberInterface::kDouble, stats.m_double.type()); + EXPECT_EQ(RTCStatsMemberInterface::kString, stats.m_string.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceBool, + stats.m_sequence_bool.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceInt32, + stats.m_sequence_int32.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceUint32, + stats.m_sequence_uint32.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceInt64, + stats.m_sequence_int64.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceUint64, + stats.m_sequence_uint64.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceDouble, + stats.m_sequence_double.type()); + EXPECT_EQ(RTCStatsMemberInterface::kSequenceString, + stats.m_sequence_string.type()); + EXPECT_EQ(RTCStatsMemberInterface::kMapStringUint64, + stats.m_map_string_uint64.type()); + EXPECT_EQ(RTCStatsMemberInterface::kMapStringDouble, + stats.m_map_string_double.type()); } TEST(RTCStatsTest, IsString) { RTCTestStats stats("statsId", Timestamp::Micros(42)); - EXPECT_TRUE(stats.GetAttribute(stats.m_string).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_bool).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_int32).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_uint32).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_int64).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_uint64).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_double).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_bool).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_int32).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_uint32).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_int64).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_uint64).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_double).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_string).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_uint64).is_string()); - EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_double).is_string()); + EXPECT_TRUE(stats.m_string.is_string()); + EXPECT_FALSE(stats.m_bool.is_string()); + EXPECT_FALSE(stats.m_int32.is_string()); + EXPECT_FALSE(stats.m_uint32.is_string()); + EXPECT_FALSE(stats.m_int64.is_string()); + EXPECT_FALSE(stats.m_uint64.is_string()); + EXPECT_FALSE(stats.m_double.is_string()); + EXPECT_FALSE(stats.m_sequence_bool.is_string()); + EXPECT_FALSE(stats.m_sequence_int32.is_string()); + EXPECT_FALSE(stats.m_sequence_uint32.is_string()); + EXPECT_FALSE(stats.m_sequence_int64.is_string()); + EXPECT_FALSE(stats.m_sequence_uint64.is_string()); + EXPECT_FALSE(stats.m_sequence_double.is_string()); + EXPECT_FALSE(stats.m_sequence_string.is_string()); + EXPECT_FALSE(stats.m_map_string_uint64.is_string()); + EXPECT_FALSE(stats.m_map_string_double.is_string()); } TEST(RTCStatsTest, AttributeToString) {