OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #ifndef WEBRTC_API_RTCSTATS_H_ | |
12 #define WEBRTC_API_RTCSTATS_H_ | |
13 | |
14 #include <map> | |
15 #include <memory> | |
16 #include <string> | |
17 #include <utility> | |
18 #include <vector> | |
19 | |
20 #include "webrtc/base/checks.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 class RTCStatsMemberInterface; | |
25 | |
26 // Abstract base class for RTCStats-derived dictionaries, see | |
27 // https://w3c.github.io/webrtc-stats/. | |
28 // | |
29 // All derived classes must have the following static variable defined: | |
30 // static const char* const kType; | |
31 // The address of |kType| is used as a unique class identifier and the value as | |
32 // a string representation of the class type, see | |
33 // https://w3c.github.io/webrtc-stats/#rtcstatstype-str*. | |
34 // Use the |WEBRTC_RTCSTATS_IMPL| macro when implementing subclasses, see macro | |
35 // for details. | |
36 // | |
37 // Derived classes list their dictionary members, RTCStatsMember<T>, as public | |
38 // fields, allowing the following: | |
39 // | |
40 // RTCFooStats foo("fooId", GetCurrentTime()); | |
41 // foo.bar = 42; | |
42 // foo.baz = std::vector<std::string>(); | |
43 // foo.baz->push_back("hello world"); | |
44 // uint32_t x = *foo.bar; | |
45 // | |
46 // Pointers to all the members are available with |Members|, allowing iteration: | |
47 // | |
48 // for (const RTCStatsMemberInterface* member : foo.Members()) { | |
49 // printf("%s = %s\n", member->name(), member->ValueToString().c_str()); | |
50 // } | |
51 class RTCStats { | |
52 public: | |
53 RTCStats(const std::string& id, double timestamp) | |
54 : id_(id), timestamp_(timestamp) {} | |
55 RTCStats(std::string&& id, double timestamp) | |
56 : id_(std::move(id)), timestamp_(timestamp) {} | |
57 virtual ~RTCStats() {} | |
58 | |
59 virtual std::unique_ptr<RTCStats> copy() const = 0; | |
60 | |
61 const std::string& id() const { return id_; } | |
62 // Time relative to the UNIX epoch (Jan 1, 1970, UTC), in seconds. | |
63 double timestamp() const { return timestamp_; } | |
64 // Returns the address of the static |kType| variable of the implementing | |
65 // class. Comparing it to |&T::kType| tests if a stats object is of type |T|. | |
66 virtual const char* const* type() const = 0; | |
nisse-webrtc
2016/08/23 08:27:28
Do you really need to return a pointer to a pointe
hbos
2016/08/23 16:21:17
Done. (You're right, const char[] works but not co
| |
67 // Returns the value of the static |kType| variable of the implementing class. | |
68 virtual const char* type_name() const = 0; | |
69 // Returns a vector of pointers to all the RTCStatsMemberInterface members of | |
70 // this class. This allows for iteration of members. | |
71 std::vector<const RTCStatsMemberInterface*> Members() const; | |
72 | |
73 // Creates a human readable string representation of the report, listing all | |
74 // of its members (names and values). | |
75 std::string ToString() const; | |
76 | |
77 // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the | |
78 // object is of type |T|. | |
79 template<typename T> | |
80 T& cast_to() { | |
81 RTC_DCHECK_EQ(type(), &T::kType); | |
nisse-webrtc
2016/08/23 08:27:28
I would expect that you don't do cast and then mod
hbos
2016/08/23 16:21:18
With a const return value on the other |cast_to| m
| |
82 return static_cast<T&>(*this); | |
83 } | |
84 template<typename T> | |
85 T& cast_to() const { | |
86 RTC_DCHECK_EQ(type(), &T::kType); | |
87 return static_cast<T&>(*this); | |
nisse-webrtc
2016/08/23 08:27:28
And this one really ought to have a const return v
hbos
2016/08/23 16:21:17
Done.
| |
88 } | |
89 | |
90 protected: | |
91 // Gets a vector of all members of this |RTCStats| object, including members | |
92 // derived from parent classes. |additional_capacity| is how many more members | |
93 // shall be reserved in the vector (so that subclasses can allocate a vector | |
94 // with room for both parent and child members without it having to resize). | |
95 virtual std::vector<const RTCStatsMemberInterface*> | |
96 MembersOfThisObjectAndAncestors( | |
97 size_t additional_capacity) const; | |
98 | |
99 std::string const id_; | |
100 double timestamp_; | |
101 }; | |
102 | |
103 // All |RTCStats| classes should use this macro in a public section of the class | |
104 // definition. | |
105 // | |
106 // This macro declares the static |kType| and overrides methods as required by | |
107 // subclasses of |RTCStats|: |copy|, |type|, |type_name| and | |
108 // |MembersOfThisObjectAndAncestors|. The |...| argument is a list of addresses | |
109 // to each member defined in the implementing class (list cannot be empty, must | |
110 // have at least one new member). | |
111 // | |
112 // (Since class names need to be known to implement these methods this cannot be | |
113 // part of the base |RTCStats|. While these methods could be implemented using | |
114 // templates, that would only work for immediate subclasses. Subclasses of | |
115 // subclasses also have to override these methods, resulting in boilerplate | |
116 // code. Using a macro avoids this and works for any |RTCStats| class, including | |
117 // grandchildren.) | |
118 // | |
119 // Sample usage: | |
120 // | |
121 // rtcfoostats.h: | |
122 // class RTCFooStats : public RTCStats { | |
123 // public: | |
124 // RTCFooStats(const std::string& id, double timestamp) | |
125 // : RTCStats(id, timestamp), | |
126 // foo("foo"), | |
127 // bar("bar") { | |
128 // } | |
129 // | |
130 // WEBRTC_RTCSTATS_IMPL(RTCStats, RTCFooStats, | |
131 // &foo, | |
132 // &bar); | |
133 // | |
134 // RTCStatsMember<int32_t> foo; | |
135 // RTCStatsMember<int32_t> bar; | |
136 // }; | |
137 // | |
138 // rtcfoostats.cc: | |
139 // const char* const RTCFooStats::kType = "foo-stats"; | |
140 // | |
141 #define WEBRTC_RTCSTATS_IMPL(parent_class, this_class, ...) \ | |
nisse-webrtc
2016/08/23 08:27:28
You have checked that variadic macros, with ..., a
hbos
2016/08/23 16:21:18
Yes, it is used by other code (e.g. webrtc/base/lo
| |
142 public: \ | |
143 static const char* const kType; \ | |
nisse-webrtc
2016/08/23 08:27:28
As above, I'd suggest making this
static const
hbos
2016/08/23 16:21:18
Unfortunately, the variable can only be declared i
| |
144 std::unique_ptr<webrtc::RTCStats> copy() const override { \ | |
145 return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \ | |
146 } \ | |
147 const char* const* type() const override { return &this_class::kType; } \ | |
148 const char* type_name() const override { return this_class::kType; } \ | |
149 protected: \ | |
150 std::vector<const webrtc::RTCStatsMemberInterface*> \ | |
151 MembersOfThisObjectAndAncestors( \ | |
152 size_t additional_capacity) const override { \ | |
153 const webrtc::RTCStatsMemberInterface* members[] = { \ | |
nisse-webrtc
2016/08/23 08:27:28
In general when doing large macros, you have to ta
hbos
2016/08/23 16:21:18
Done. Nice catch. I couldn't find anything in the
| |
154 __VA_ARGS__ \ | |
155 }; \ | |
156 size_t members_count = sizeof(members) / sizeof(members[0]); \ | |
157 std::vector<const webrtc::RTCStatsMemberInterface*> members_vec = \ | |
158 parent_class::MembersOfThisObjectAndAncestors( \ | |
159 additional_capacity + members_count); \ | |
nisse-webrtc
2016/08/23 08:27:28
How do you test this allocation logic? Is there so
hbos
2016/08/23 16:21:18
I added a DCHECK that ensures the capacity is enou
| |
160 members_vec.insert(members_vec.end(), \ | |
161 &members[0], &members[members_count]); \ | |
nisse-webrtc
2016/08/23 08:27:28
There's an extra copy, first into the members arra
hbos
2016/08/23 16:21:18
Variadic functions come to mind, but I don't think
| |
162 return members_vec; \ | |
163 } \ | |
164 public: | |
165 | |
166 // Interface for |RTCStats| members, which have a name and a value of a type | |
167 // defined in a subclass. Only the types listed in |Type| are supported, these | |
168 // are implemented by |RTCStatsMember<T>|. The value of a member may be | |
169 // undefined, the value can only be read if |is_defined|. | |
170 class RTCStatsMemberInterface { | |
171 public: | |
172 // Member value types. | |
173 enum Type { | |
nisse-webrtc
2016/08/23 08:27:28
Hmm, this was a bit confusing at first. Here types
hbos
2016/08/23 16:21:18
That is correct.
The RTCStats type is for RTCStat
| |
174 kInt32, // int32_t | |
175 kUint32, // uint32_t | |
176 kInt64, // int64_t | |
177 kUint64, // uint64_t | |
178 kDouble, // double | |
179 kStaticString, // const char* | |
180 kString, // std::string | |
181 | |
182 kSequenceInt32, // std::vector<int32_t> | |
183 kSequenceUint32, // std::vector<uint32_t> | |
184 kSequenceInt64, // std::vector<int64_t> | |
185 kSequenceUint64, // std::vector<uint64_t> | |
186 kSequenceDouble, // std::vector<double> | |
187 kSequenceStaticString, // std::vector<const char*> | |
188 kSequenceString, // std::vector<std::string> | |
189 }; | |
190 | |
191 virtual ~RTCStatsMemberInterface() {} | |
192 | |
193 const char* name() const { return name_; } | |
194 virtual Type type() const = 0; | |
195 virtual bool is_sequence() const = 0; | |
196 virtual bool is_string() const = 0; // true for sequences of strings too. | |
nisse-webrtc
2016/08/23 08:27:28
That's kind of surprising. Why?
Only use I've see
hbos
2016/08/23 16:21:17
Hmm, yeah, strange decision, I'll make it false in
| |
197 bool is_defined() const { return is_defined_; } | |
198 virtual std::string ValueToString() const = 0; | |
199 | |
200 template<typename T> | |
201 T& cast_to() const { | |
nisse-webrtc
2016/08/23 08:27:28
I think the return type should be const T&.
hbos
2016/08/23 16:21:18
Done.
| |
202 RTC_DCHECK_EQ(type(), T::kType); | |
203 return static_cast<T&>(*this); | |
204 } | |
205 | |
206 protected: | |
207 RTCStatsMemberInterface(const char* name, bool is_defined) | |
208 : name_(name), is_defined_(is_defined) {} | |
209 | |
210 const char* const name_; | |
211 bool is_defined_; | |
212 }; | |
213 | |
214 // Template implementation of |RTCStatsMemberInterface|. Every possible |T| is | |
215 // specialized in rtcstats.cc, using a different |T| results in a linker error | |
216 // (undefined reference to |kType|). The supported types are the ones described | |
217 // by |RTCStatsMemberInterface::Type|. | |
218 template<typename T> | |
219 class RTCStatsMember : public RTCStatsMemberInterface { | |
220 public: | |
221 static const Type kType; | |
222 | |
223 explicit RTCStatsMember(const char* name) | |
224 : RTCStatsMemberInterface(name, false), | |
225 value_() {} | |
226 RTCStatsMember(const char* name, const T& value) | |
227 : RTCStatsMemberInterface(name, true), | |
228 value_(value) {} | |
229 RTCStatsMember(const char* name, T&& value) | |
230 : RTCStatsMemberInterface(name, true), | |
231 value_(std::move(value)) {} | |
232 explicit RTCStatsMember(const RTCStatsMember<T>& other) | |
233 : RTCStatsMemberInterface(other.name_, other.is_defined_), | |
234 value_(other.value_) {} | |
235 explicit RTCStatsMember(RTCStatsMember<T>&& other) | |
236 : RTCStatsMemberInterface(other.name_, other.is_defined_), | |
237 value_(std::move(other.value_)) {} | |
238 | |
239 Type type() const override { return kType; } | |
240 bool is_sequence() const override; | |
241 bool is_string() const override; | |
242 std::string ValueToString() const override; | |
243 | |
244 // Assignment operators. | |
245 T& operator=(const T& value) { | |
246 value_ = value; | |
247 is_defined_ = true; | |
248 return value_; | |
249 } | |
250 T& operator=(const T&& value) { | |
251 value_ = std::move(value); | |
252 is_defined_ = true; | |
253 return value_; | |
254 } | |
255 T& operator=(const RTCStatsMember<T>& other) { | |
256 RTC_DCHECK(other.is_defined_); | |
257 value_ = other.is_defined_; | |
258 is_defined_ = true; | |
259 return value_; | |
260 } | |
261 | |
262 // Value getters. | |
263 T& operator*() { | |
264 RTC_DCHECK(is_defined_); | |
265 return value_; | |
266 } | |
267 const T& operator*() const { | |
268 RTC_DCHECK(is_defined_); | |
269 return value_; | |
270 } | |
271 | |
272 // Value getters, arrow operator. | |
273 T* operator->() { | |
274 RTC_DCHECK(is_defined_); | |
275 return &value_; | |
276 } | |
277 const T* operator->() const { | |
278 RTC_DCHECK(is_defined_); | |
279 return &value_; | |
280 } | |
281 | |
282 private: | |
283 T value_; | |
284 }; | |
285 | |
286 } // namespace webrtc | |
287 | |
288 #endif // WEBRTC_API_RTCSTATS_H_ | |
OLD | NEW |