Support for map of string keys to uint64_t / double values in RTCStats
Bug: webrtc:10685 Change-Id: I047d784bd20c3fca8b96391653f90fd8803140d8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219141 Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Kári Helgason <kthelgason@webrtc.org> Reviewed-by: Xavier Lepaul <xalep@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34121}
This commit is contained in:
parent
cbeff55a6a
commit
0a52ede821
@ -14,6 +14,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@ -237,6 +238,9 @@ class RTCStatsMemberInterface {
|
||||
kSequenceUint64, // std::vector<uint64_t>
|
||||
kSequenceDouble, // std::vector<double>
|
||||
kSequenceString, // std::vector<std::string>
|
||||
|
||||
kMapStringUint64, // std::map<std::string, uint64_t>
|
||||
kMapStringDouble, // std::map<std::string, double>
|
||||
};
|
||||
|
||||
virtual ~RTCStatsMemberInterface() {}
|
||||
@ -363,6 +367,13 @@ class RTCStatsMember : public RTCStatsMemberInterface {
|
||||
T value_;
|
||||
};
|
||||
|
||||
namespace rtc_stats_internal {
|
||||
|
||||
typedef std::map<std::string, uint64_t> MapStringUint64;
|
||||
typedef std::map<std::string, double> MapStringDouble;
|
||||
|
||||
} // namespace rtc_stats_internal
|
||||
|
||||
#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \
|
||||
template <> \
|
||||
RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType(); \
|
||||
@ -391,6 +402,8 @@ WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int64_t>);
|
||||
WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint64_t>);
|
||||
WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<double>);
|
||||
WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>);
|
||||
WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64);
|
||||
WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble);
|
||||
|
||||
// Using inheritance just so that it's obvious from the member's declaration
|
||||
// whether it's standardized or not.
|
||||
@ -455,6 +468,10 @@ extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
|
||||
RTCNonStandardStatsMember<std::vector<double>>;
|
||||
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
|
||||
RTCNonStandardStatsMember<std::vector<std::string>>;
|
||||
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
|
||||
RTCNonStandardStatsMember<std::map<std::string, uint64_t>>;
|
||||
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
|
||||
RTCNonStandardStatsMember<std::map<std::string, double>>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@ public class RTCStats {
|
||||
* - Double
|
||||
* - String
|
||||
* - The array form of any of the above (e.g., Integer[])
|
||||
* - Map of String keys to BigInteger / Double values
|
||||
*/
|
||||
public Map<String, Object> getMembers() {
|
||||
return members;
|
||||
|
||||
@ -94,6 +94,23 @@ ScopedJavaLocalRef<jobject> MemberToJava(
|
||||
case RTCStatsMemberInterface::kSequenceString:
|
||||
return NativeToJavaStringArray(
|
||||
env, *member.cast_to<RTCStatsMember<std::vector<std::string>>>());
|
||||
|
||||
case RTCStatsMemberInterface::kMapStringUint64:
|
||||
return NativeToJavaMap(
|
||||
env,
|
||||
*member.cast_to<RTCStatsMember<std::map<std::string, uint64_t>>>(),
|
||||
[](JNIEnv* env, const auto& entry) {
|
||||
return std::make_pair(NativeToJavaString(env, entry.first),
|
||||
NativeToJavaBigInteger(env, entry.second));
|
||||
});
|
||||
|
||||
case RTCStatsMemberInterface::kMapStringDouble:
|
||||
return NativeToJavaMap(
|
||||
env, *member.cast_to<RTCStatsMember<std::map<std::string, double>>>(),
|
||||
[](JNIEnv* env, const auto& entry) {
|
||||
return std::make_pair(NativeToJavaString(env, entry.first),
|
||||
NativeToJavaDouble(env, entry.second));
|
||||
});
|
||||
}
|
||||
RTC_NOTREACHED();
|
||||
return nullptr;
|
||||
|
||||
@ -44,8 +44,8 @@ RTC_OBJC_EXPORT
|
||||
@property(nonatomic, readonly) NSString *type;
|
||||
|
||||
/** The keys and values of the subreport, e.g. "totalFramesDuration = 5.551".
|
||||
The values are either NSNumbers or NSStrings, or NSArrays encapsulating NSNumbers
|
||||
or NSStrings. */
|
||||
The values are either NSNumbers or NSStrings or NSArrays encapsulating NSNumbers
|
||||
or NSStrings, or NSDictionary of NSString keys to NSNumber values. */
|
||||
@property(nonatomic, readonly) NSDictionary<NSString *, NSObject *> *values;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
namespace webrtc {
|
||||
|
||||
/** Converts a single value to a suitable NSNumber, NSString or NSArray containing NSNumbers
|
||||
or NSStrings.*/
|
||||
or NSStrings, or NSDictionary of NSString keys to NSNumber values.*/
|
||||
NSObject *ValueFromStatsMember(const RTCStatsMemberInterface *member) {
|
||||
if (member->is_defined()) {
|
||||
switch (member->type()) {
|
||||
@ -91,6 +91,26 @@ NSObject *ValueFromStatsMember(const RTCStatsMemberInterface *member) {
|
||||
}
|
||||
return [array copy];
|
||||
}
|
||||
case RTCStatsMemberInterface::kMapStringUint64: {
|
||||
std::map<std::string, uint64_t> map =
|
||||
*member->cast_to<RTCStatsMember<std::map<std::string, uint64_t>>>();
|
||||
NSMutableDictionary<NSString *, NSNumber *> *dictionary =
|
||||
[NSMutableDictionary dictionaryWithCapacity:map.size()];
|
||||
for (const auto &item : map) {
|
||||
dictionary[[NSString stringForStdString:item.first]] = @(item.second);
|
||||
}
|
||||
return [dictionary copy];
|
||||
}
|
||||
case RTCStatsMemberInterface::kMapStringDouble: {
|
||||
std::map<std::string, double> map =
|
||||
*member->cast_to<RTCStatsMember<std::map<std::string, double>>>();
|
||||
NSMutableDictionary<NSString *, NSNumber *> *dictionary =
|
||||
[NSMutableDictionary dictionaryWithCapacity:map.size()];
|
||||
for (const auto &item : map) {
|
||||
dictionary[[NSString stringForStdString:item.first]] = @(item.second);
|
||||
}
|
||||
return [dictionary copy];
|
||||
}
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
@ -64,6 +64,20 @@ std::string VectorOfStringsToString(const std::vector<T>& strings) {
|
||||
return sb.Release();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string MapToString(const std::map<std::string, T>& 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 <typename T>
|
||||
std::string ToStringAsDouble(const T value) {
|
||||
// JSON represents numbers as floating point numbers with about 15 decimal
|
||||
@ -88,6 +102,20 @@ std::string VectorToStringAsDouble(const std::vector<T>& vector) {
|
||||
return sb.Release();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string MapToStringAsDouble(const std::map<std::string, T>& 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 {
|
||||
@ -248,6 +276,18 @@ WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<std::string>,
|
||||
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_));
|
||||
|
||||
template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT)
|
||||
RTCNonStandardStatsMember<bool>;
|
||||
|
||||
@ -71,7 +71,7 @@ TEST(RTCStatsTest, RTCStatsAndMembers) {
|
||||
EXPECT_EQ(stats.id(), "testId");
|
||||
EXPECT_EQ(stats.timestamp_us(), static_cast<int64_t>(42));
|
||||
std::vector<const RTCStatsMemberInterface*> members = stats.Members();
|
||||
EXPECT_EQ(members.size(), static_cast<size_t>(14));
|
||||
EXPECT_EQ(members.size(), static_cast<size_t>(16));
|
||||
for (const RTCStatsMemberInterface* member : members) {
|
||||
EXPECT_FALSE(member->is_defined());
|
||||
}
|
||||
@ -98,6 +98,9 @@ TEST(RTCStatsTest, RTCStatsAndMembers) {
|
||||
std::vector<std::string> sequence_string;
|
||||
sequence_string.push_back(std::string("six"));
|
||||
|
||||
std::map<std::string, uint64_t> map_string_uint64{{"seven", 8}};
|
||||
std::map<std::string, double> map_string_double{{"nine", 10.0}};
|
||||
|
||||
stats.m_sequence_bool = sequence_bool;
|
||||
stats.m_sequence_int32 = sequence_int32;
|
||||
stats.m_sequence_uint32 = sequence_uint32;
|
||||
@ -106,6 +109,8 @@ TEST(RTCStatsTest, RTCStatsAndMembers) {
|
||||
stats.m_sequence_uint64 = sequence_uint64;
|
||||
stats.m_sequence_double = sequence_double;
|
||||
stats.m_sequence_string = sequence_string;
|
||||
stats.m_map_string_uint64 = map_string_uint64;
|
||||
stats.m_map_string_double = map_string_double;
|
||||
for (const RTCStatsMemberInterface* member : members) {
|
||||
EXPECT_TRUE(member->is_defined());
|
||||
}
|
||||
@ -123,6 +128,8 @@ TEST(RTCStatsTest, RTCStatsAndMembers) {
|
||||
EXPECT_EQ(*stats.m_sequence_uint64, sequence_uint64);
|
||||
EXPECT_EQ(*stats.m_sequence_double, sequence_double);
|
||||
EXPECT_EQ(*stats.m_sequence_string, sequence_string);
|
||||
EXPECT_EQ(*stats.m_map_string_uint64, map_string_uint64);
|
||||
EXPECT_EQ(*stats.m_map_string_double, map_string_double);
|
||||
|
||||
int32_t numbers[] = {4, 8, 15, 16, 23, 42};
|
||||
std::vector<int32_t> numbers_sequence(&numbers[0], &numbers[6]);
|
||||
@ -152,6 +159,8 @@ TEST(RTCStatsTest, EqualityOperator) {
|
||||
stats_with_all_values.m_sequence_uint64 = std::vector<uint64_t>();
|
||||
stats_with_all_values.m_sequence_double = std::vector<double>();
|
||||
stats_with_all_values.m_sequence_string = std::vector<std::string>();
|
||||
stats_with_all_values.m_map_string_uint64 = std::map<std::string, uint64_t>();
|
||||
stats_with_all_values.m_map_string_double = std::map<std::string, double>();
|
||||
EXPECT_NE(stats_with_all_values, empty_stats);
|
||||
EXPECT_EQ(stats_with_all_values, stats_with_all_values);
|
||||
EXPECT_NE(stats_with_all_values.m_int32, stats_with_all_values.m_uint32);
|
||||
@ -180,6 +189,8 @@ TEST(RTCStatsTest, EqualityOperator) {
|
||||
one_member_different[11].m_sequence_uint64->push_back(321);
|
||||
one_member_different[12].m_sequence_double->push_back(321.0);
|
||||
one_member_different[13].m_sequence_string->push_back("321");
|
||||
(*one_member_different[13].m_map_string_uint64)["321"] = 321;
|
||||
(*one_member_different[13].m_map_string_double)["321"] = 321.0;
|
||||
for (size_t i = 0; i < 14; ++i) {
|
||||
EXPECT_NE(stats_with_all_values, one_member_different[i]);
|
||||
}
|
||||
@ -238,6 +249,11 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
std::vector<std::string> sequence_string;
|
||||
sequence_string.push_back(std::string("four"));
|
||||
|
||||
std::map<std::string, uint64_t> map_string_uint64{
|
||||
{"long", static_cast<uint64_t>(1234567890123456499L)}};
|
||||
std::map<std::string, double> map_string_double{
|
||||
{"three", 123.4567890123456499}, {"thirteen", 123.4567890123456499}};
|
||||
|
||||
RTCTestStats stats(id, timestamp);
|
||||
stats.m_bool = m_bool;
|
||||
stats.m_int32 = m_int32;
|
||||
@ -249,6 +265,8 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
stats.m_sequence_int64 = sequence_int64;
|
||||
stats.m_sequence_double = sequence_double;
|
||||
stats.m_sequence_string = sequence_string;
|
||||
stats.m_map_string_uint64 = map_string_uint64;
|
||||
stats.m_map_string_double = map_string_double;
|
||||
|
||||
Json::Value json_output;
|
||||
EXPECT_TRUE(Json::Reader().parse(stats.ToJson(), json_output));
|
||||
@ -278,6 +296,16 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
rtc::GetValueFromJsonObject(json_output, "mSequenceString", &json_array));
|
||||
EXPECT_TRUE(rtc::JsonArrayToStringVector(json_array, &sequence_string));
|
||||
|
||||
Json::Value json_map;
|
||||
EXPECT_TRUE(
|
||||
rtc::GetValueFromJsonObject(json_output, "mMapStringDouble", &json_map));
|
||||
for (const auto& entry : map_string_double) {
|
||||
double double_output = 0.0;
|
||||
EXPECT_TRUE(
|
||||
rtc::GetDoubleFromJsonObject(json_map, entry.first, &double_output));
|
||||
EXPECT_NEAR(double_output, entry.second, GetExpectedError(entry.second));
|
||||
}
|
||||
|
||||
EXPECT_EQ(id, stats.id());
|
||||
EXPECT_EQ(timestamp, stats.timestamp_us());
|
||||
EXPECT_EQ(m_bool, *stats.m_bool);
|
||||
@ -286,6 +314,7 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
EXPECT_EQ(sequence_bool, *stats.m_sequence_bool);
|
||||
EXPECT_EQ(sequence_int32, *stats.m_sequence_int32);
|
||||
EXPECT_EQ(sequence_string, *stats.m_sequence_string);
|
||||
EXPECT_EQ(map_string_double, *stats.m_map_string_double);
|
||||
|
||||
EXPECT_NEAR(m_double, *stats.m_double, GetExpectedError(*stats.m_double));
|
||||
|
||||
@ -295,6 +324,13 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
GetExpectedError(stats.m_sequence_double->at(i)));
|
||||
}
|
||||
|
||||
EXPECT_EQ(map_string_double.size(), stats.m_map_string_double->size());
|
||||
for (const auto& entry : map_string_double) {
|
||||
auto it = stats.m_map_string_double->find(entry.first);
|
||||
EXPECT_NE(it, stats.m_map_string_double->end());
|
||||
EXPECT_NEAR(entry.second, it->second, GetExpectedError(it->second));
|
||||
}
|
||||
|
||||
// We read mInt64 as double since JSON stores all numbers as doubles, so there
|
||||
// is not enough precision to represent large numbers.
|
||||
double m_int64_as_double;
|
||||
@ -320,6 +356,19 @@ TEST(RTCStatsTest, RTCStatsPrintsValidJson) {
|
||||
GetExpectedError(stats_value_as_double));
|
||||
}
|
||||
|
||||
// Similarly, read Uint64 as double
|
||||
EXPECT_TRUE(
|
||||
rtc::GetValueFromJsonObject(json_output, "mMapStringUint64", &json_map));
|
||||
for (const auto& entry : map_string_uint64) {
|
||||
const double stats_value_as_double =
|
||||
static_cast<double>((*stats.m_map_string_uint64)[entry.first]);
|
||||
double double_output = 0.0;
|
||||
EXPECT_TRUE(
|
||||
rtc::GetDoubleFromJsonObject(json_map, entry.first, &double_output));
|
||||
EXPECT_NEAR(double_output, stats_value_as_double,
|
||||
GetExpectedError(stats_value_as_double));
|
||||
}
|
||||
|
||||
// Neither stats.m_uint32 nor stats.m_uint64 are defined, so "mUint64" and
|
||||
// "mUint32" should not be part of the generated JSON object.
|
||||
int m_uint32;
|
||||
|
||||
@ -30,7 +30,9 @@ WEBRTC_RTCSTATS_IMPL(RTCTestStats,
|
||||
&m_sequence_int64,
|
||||
&m_sequence_uint64,
|
||||
&m_sequence_double,
|
||||
&m_sequence_string)
|
||||
&m_sequence_string,
|
||||
&m_map_string_uint64,
|
||||
&m_map_string_double)
|
||||
|
||||
RTCTestStats::RTCTestStats(const std::string& id, int64_t timestamp_us)
|
||||
: RTCStats(id, timestamp_us),
|
||||
@ -47,7 +49,9 @@ RTCTestStats::RTCTestStats(const std::string& id, int64_t timestamp_us)
|
||||
m_sequence_int64("mSequenceInt64"),
|
||||
m_sequence_uint64("mSequenceUint64"),
|
||||
m_sequence_double("mSequenceDouble"),
|
||||
m_sequence_string("mSequenceString") {}
|
||||
m_sequence_string("mSequenceString"),
|
||||
m_map_string_uint64("mMapStringUint64"),
|
||||
m_map_string_double("mMapStringDouble") {}
|
||||
|
||||
RTCTestStats::RTCTestStats(const RTCTestStats& other)
|
||||
: RTCStats(other.id(), other.timestamp_us()),
|
||||
@ -64,7 +68,9 @@ RTCTestStats::RTCTestStats(const RTCTestStats& other)
|
||||
m_sequence_int64(other.m_sequence_int64),
|
||||
m_sequence_uint64(other.m_sequence_uint64),
|
||||
m_sequence_double(other.m_sequence_double),
|
||||
m_sequence_string(other.m_sequence_string) {}
|
||||
m_sequence_string(other.m_sequence_string),
|
||||
m_map_string_uint64(other.m_map_string_uint64),
|
||||
m_map_string_double(other.m_map_string_double) {}
|
||||
|
||||
RTCTestStats::~RTCTestStats() {}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#define STATS_TEST_RTC_TEST_STATS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -42,6 +43,8 @@ class RTC_EXPORT RTCTestStats : public RTCStats {
|
||||
RTCStatsMember<std::vector<uint64_t>> m_sequence_uint64;
|
||||
RTCStatsMember<std::vector<double>> m_sequence_double;
|
||||
RTCStatsMember<std::vector<std::string>> m_sequence_string;
|
||||
RTCStatsMember<std::map<std::string, uint64_t>> m_map_string_uint64;
|
||||
RTCStatsMember<std::map<std::string, double>> m_map_string_double;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user