Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: webrtc/base/numerics/cyclic_buffer_unittest.cc

Issue 2691073002: New implementation of generic cyclic buffer.
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/numerics/cyclic_buffer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 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 #include <deque>
12 #include <list>
13 #include <string>
14
15 #include "webrtc/base/numerics/cyclic_buffer.h"
16 #include "webrtc/base/timeutils.h"
17 #include "webrtc/base/random.h"
18 #include "webrtc/test/gtest.h"
19
20 namespace {
21
22 struct Usage {
23 size_t default_constructor = 0;
24 size_t cast_constructor = 0;
25 size_t copy_constructor = 0;
26 size_t move_constructor = 0;
27 size_t move_cast_constructor = 0;
28 size_t destructors = 0;
29 size_t copy_assignment = 0;
30 size_t cast_assignment = 0;
31 size_t move_assignment = 0;
32 size_t move_cast_assignment = 0;
33 size_t casts = 0;
34 };
35
36 // void ResetMagicTypeUsage(Usage& usage) {
37 // usage.default_constructor = 0;
38 // usage.cast_constructor = 0;
39 // usage.copy_constructor = 0;
40 // usage.move_constructor = 0;
41 // usage.move_cast_constructor = 0;
42 // usage.destructors = 0;
43 // usage.copy_assignment = 0;
44 // usage.cast_assignment = 0;
45 // usage.move_assignment = 0;
46 // usage.move_cast_assignment = 0;
47 // usage.casts = 0;
48 // }
49
50 // void PrintMagicTypeUsage(const Usage& usage) {
51 // printf("%zu default constructor calls\n", usage.default_constructor);
52 // printf("%zu cast constructor calls\n", usage.cast_constructor);
53 // printf("%zu copy constructor calls\n", usage.copy_constructor);
54 // printf("%zu move cast constructor calls\n", usage.move_cast_constructor);
55 // printf("%zu move constructor calls\n", usage.move_constructor);
56 // printf("%zu destructor calls\n", usage.destructors);
57 // printf("%zu copy assignments calls\n", usage.copy_assignment);
58 // printf("%zu cast assignments calls\n", usage.cast_assignment);
59 // printf("%zu move assignments calls\n", usage.move_assignment);
60 // printf("%zu move cast assignments calls\n", usage.move_cast_assignment);
61 // printf("%zu casts\n", usage.casts);
62 // }
63
64 // Wrapper type to detect memory management problems, like using memcpy to copy
65 // data without running the constructor, using the data before it has been
66 // assigned, or using the data after it has been deleted.
67 template <typename T>
68 class MagicType {
69 public:
70 MagicType() : magic_(this), constructed_(true), assigned_(false) {
71 usage.default_constructor++;
72 }
73
74 MagicType(const T& value) // we actually want implicit casts here
75 : value_(value), magic_(this), constructed_(true), assigned_(true) {
76 usage.cast_constructor++;
77 }
78
79 MagicType(T&& value) // we actually want implicit casts here
80 : value_(std::move(value)),
81 magic_(this),
82 constructed_(true),
83 assigned_(true) {
84 usage.move_cast_constructor++;
85 }
86
87 MagicType(const MagicType<T>& m)
88 : value_(m.value_),
89 magic_(this),
90 constructed_(m.constructed_),
91 assigned_(m.assigned_) {
92 RTC_DCHECK(m.magic_ == &m);
93 RTC_DCHECK(m.constructed_);
94 usage.copy_constructor++;
95 }
96
97 MagicType(MagicType<T>&& m)
98 : value_(std::move(m.value_)),
99 magic_(this),
100 constructed_(m.constructed_),
101 assigned_(m.assigned_) {
102 RTC_DCHECK(m.magic_ == &m);
103 RTC_DCHECK(m.constructed_);
104 usage.move_constructor++;
105 }
106
107 ~MagicType() {
108 RTC_DCHECK(magic_ == this);
109 RTC_DCHECK(constructed_);
110 magic_ = nullptr;
111 constructed_ = false;
112 assigned_ = false;
113 usage.destructors++;
114 }
115
116 MagicType<T>& operator=(const T& value) {
117 RTC_DCHECK(magic_ == this);
118 RTC_DCHECK(constructed_);
119 value_ = value;
120 assigned_ = true;
121 usage.cast_assignment++;
122 return *this;
123 }
124
125 MagicType<T>& operator=(T&& value) {
126 RTC_DCHECK(magic_ == this);
127 RTC_DCHECK(constructed_);
128 value_ = value;
129 assigned_ = true;
130 usage.move_cast_assignment++;
131 return *this;
132 }
133
134 MagicType<T>& operator=(const MagicType<T>& m) {
135 RTC_DCHECK(m.magic_ == &m);
136 RTC_DCHECK(m.constructed_);
137 RTC_DCHECK(magic_ == this);
138 RTC_DCHECK(constructed_);
139 value_ = m.value_;
140 assigned_ = m.assigned_;
141 usage.copy_assignment++;
142 return *this;
143 }
144
145 MagicType<T>& operator=(MagicType<T>&& m) {
146 RTC_DCHECK(m.magic_ == &m);
147 RTC_DCHECK(m.constructed_);
148 RTC_DCHECK(magic_ == this);
149 RTC_DCHECK(constructed_);
150 value_ = m.value_;
151 assigned_ = m.assigned_;
152 usage.move_assignment++;
153 return *this;
154 }
155
156 operator T() const {
157 RTC_DCHECK(magic_ == this);
158 RTC_DCHECK(constructed_);
159 RTC_DCHECK(assigned_);
160 usage.casts++;
161 return value_;
162 }
163
164 static Usage usage;
165
166 private:
167 T value_;
168 MagicType<T>* magic_;
169 bool constructed_;
170 bool assigned_;
171 };
172
173 template <typename T>
174 Usage MagicType<T>::usage;
175 } // namespace
176
177 namespace webrtc {
178
179 TEST(CyclicBufferTest, EmptyBuffer) {
180 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(5);
181 EXPECT_EQ(buffer.size(), 0u);
182 }
183
184 TEST(CyclicBufferTest, PushBack) {
185 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(5);
186 buffer.push_back(45);
187 EXPECT_EQ(buffer.size(), 1u);
188 EXPECT_EQ(buffer.back(), 45);
189 EXPECT_EQ(buffer.front(), 45);
190 buffer.push_back(98);
191 EXPECT_EQ(buffer.size(), 2u);
192 EXPECT_EQ(buffer.back(), 98);
193 EXPECT_EQ(buffer.front(), 45);
194 buffer.push_back(35);
195 EXPECT_EQ(buffer.size(), 3u);
196 EXPECT_EQ(buffer.back(), 35);
197 EXPECT_EQ(buffer.front(), 45);
198 }
199
200 TEST(CyclicBufferTest, PopFront) {
201 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(5);
202 buffer.push_back(45);
203 buffer.push_back(98);
204 buffer.push_back(35);
205 EXPECT_EQ(buffer.size(), 3u);
206 EXPECT_EQ(buffer.back(), 35);
207 EXPECT_EQ(buffer.front(), 45);
208 buffer.pop_front();
209 EXPECT_EQ(buffer.size(), 2u);
210 EXPECT_EQ(buffer.back(), 35);
211 EXPECT_EQ(buffer.front(), 98);
212 buffer.pop_front();
213 EXPECT_EQ(buffer.size(), 1u);
214 EXPECT_EQ(buffer.back(), 35);
215 EXPECT_EQ(buffer.front(), 35);
216 buffer.pop_front();
217 EXPECT_EQ(buffer.size(), 0u);
218 }
219
220 TEST(CyclicBufferTest, PushFront) {
221 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(5);
222 buffer.push_front(45);
223 EXPECT_EQ(buffer.size(), 1u);
224 EXPECT_EQ(buffer.back(), 45);
225 EXPECT_EQ(buffer.front(), 45);
226 buffer.push_front(98);
227 EXPECT_EQ(buffer.size(), 2u);
228 EXPECT_EQ(buffer.back(), 45);
229 EXPECT_EQ(buffer.front(), 98);
230 buffer.push_front(35);
231 EXPECT_EQ(buffer.size(), 3u);
232 EXPECT_EQ(buffer.back(), 45);
233 EXPECT_EQ(buffer.front(), 35);
234 }
235
236 TEST(CyclicBufferTest, PopBack) {
237 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(5);
238 buffer.push_front(45);
239 buffer.push_front(98);
240 buffer.push_front(35);
241 EXPECT_EQ(buffer.size(), 3u);
242 EXPECT_EQ(buffer.back(), 45);
243 EXPECT_EQ(buffer.front(), 35);
244 buffer.pop_back();
245 EXPECT_EQ(buffer.size(), 2u);
246 EXPECT_EQ(buffer.back(), 98);
247 EXPECT_EQ(buffer.front(), 35);
248 buffer.pop_back();
249 EXPECT_EQ(buffer.size(), 1u);
250 EXPECT_EQ(buffer.back(), 35);
251 EXPECT_EQ(buffer.front(), 35);
252 buffer.pop_back();
253 EXPECT_EQ(buffer.size(), 0u);
254 }
255
256 TEST(CyclicBufferTest, BufferWithCapacityOne) {
257 CyclicBuffer<int, GrowthPolicy::ASSERT> buffer(1);
258 // Insert and remove one element from a buffer with capacity 1.
259 buffer.push_back(45);
260 EXPECT_EQ(buffer.size(), 1u);
261 EXPECT_EQ(buffer.back(), 45);
262 EXPECT_EQ(buffer.front(), 45);
263 buffer.pop_front();
264 EXPECT_EQ(buffer.size(), 0u);
265 // Verify that we are still in a valid state by attempting a another
266 // operation.
267 buffer.push_back(21);
268 EXPECT_EQ(buffer.size(), 1u);
269 EXPECT_EQ(buffer.back(), 21);
270 EXPECT_EQ(buffer.front(), 21);
271 buffer.pop_front();
272 EXPECT_EQ(buffer.size(), 0u);
273 }
274
275 TEST(CyclicBufferTest, BufferMagicType) {
276 CyclicBuffer<MagicType<int>, GrowthPolicy::ASSERT> buffer(3);
277 buffer.push_back(45);
278 EXPECT_EQ(buffer.size(), 1u);
279 EXPECT_EQ(buffer.back(), 45);
280 EXPECT_EQ(buffer.front(), 45);
281 buffer.push_back(98);
282 EXPECT_EQ(buffer.size(), 2u);
283 EXPECT_EQ(buffer.back(), 98);
284 EXPECT_EQ(buffer.front(), 45);
285 buffer.push_back(35);
286 EXPECT_EQ(buffer.size(), 3u);
287 EXPECT_EQ(buffer.back(), 35);
288 EXPECT_EQ(buffer.front(), 45);
289 buffer.pop_front();
290 EXPECT_EQ(buffer.size(), 2u);
291 EXPECT_EQ(buffer.back(), 35);
292 EXPECT_EQ(buffer.front(), 98);
293 buffer.pop_front();
294 EXPECT_EQ(buffer.size(), 1u);
295 EXPECT_EQ(buffer.back(), 35);
296 EXPECT_EQ(buffer.front(), 35);
297 buffer.pop_front();
298 EXPECT_EQ(buffer.size(), 0u);
299 }
300
301 template <typename Buffer>
302 int64_t TestIntBufferPerformance(Buffer* buffer,
303 size_t elements,
304 size_t capacity) {
305 int64_t start = rtc::TimeMicros();
306 for (size_t i = 0; i < elements; i++) {
307 if (buffer->size() == capacity)
308 buffer->pop_front();
309 buffer->push_back(i);
310 }
311 int64_t stop = rtc::TimeMicros();
312 return stop - start;
313 }
314
315 template <typename Buffer>
316 int64_t TestStringBufferPerformance(Buffer* buffer,
317 size_t elements,
318 size_t capacity) {
319 int64_t start = rtc::TimeMicros();
320 for (size_t i = 0; i < elements; i++) {
321 if (buffer->size() == capacity)
322 buffer->pop_front();
323 buffer->push_back(std::to_string(i));
324 }
325 int64_t stop = rtc::TimeMicros();
326 return stop - start;
327 }
328
329 TEST(CyclicBufferTest, DISABLED_PerformanceInt) {
330 CyclicBuffer<int, GrowthPolicy::ASSERT> cyclic(1023u);
331 std::deque<int> double_ended;
332 // printf("Time used by std::list = %ld\n", TestListPerformance(1000000u,
333 // 1023u));
334
335 int64_t deque_time = 0;
336 int64_t cyclicbuffer_time = 0;
337 for (int i = 0; i < 100; i++) {
338 deque_time += TestIntBufferPerformance(&double_ended, 1000000u, 1023u);
339 cyclicbuffer_time += TestIntBufferPerformance(&cyclic, 1000000u, 1023u);
340 }
341 printf("Time used by std::deque = %ld\n", deque_time / 100);
342 printf("Time used by CyclicBuffer = %ld\n", cyclicbuffer_time / 100);
343 }
344
345 TEST(CyclicBufferTest, DISABLED_PerformanceDouble) {
346 CyclicBuffer<double, GrowthPolicy::ASSERT> cyclic(1023u);
347 std::deque<double> double_ended;
348
349 int64_t deque_time = 0;
350 int64_t cyclicbuffer_time = 0;
351 for (int i = 0; i < 100; i++) {
352 deque_time += TestIntBufferPerformance(&double_ended, 1000000u, 1023u);
353 cyclicbuffer_time += TestIntBufferPerformance(&cyclic, 1000000u, 1023u);
354 }
355 printf("Time used by std::deque = %ld\n", deque_time / 100);
356 printf("Time used by CyclicBuffer = %ld\n", cyclicbuffer_time / 100);
357 }
358
359 TEST(CyclicBufferTest, DISABLED_PerformanceString) {
360 CyclicBuffer<std::string, GrowthPolicy::ASSERT> cyclic(1023u);
361 std::deque<std::string> double_ended;
362
363 int64_t deque_time = 0;
364 int64_t cyclicbuffer_time = 0;
365 for (int i = 0; i < 100; i++) {
366 deque_time += TestStringBufferPerformance(&double_ended, 1000000u, 1023u);
367 cyclicbuffer_time += TestStringBufferPerformance(&cyclic, 1000000u, 1023u);
368 }
369 printf("Time used by std::deque = %ld\n", deque_time / 100);
370 printf("Time used by CyclicBuffer = %ld\n", cyclicbuffer_time / 100);
371 }
372
373 TEST(CyclicBufferTest, DISABLED_PerformanceMagicTypeString) {
374 CyclicBuffer<MagicType<std::string>, GrowthPolicy::ASSERT> cyclic(1023u);
375 std::deque<MagicType<std::string>> double_ended;
376
377 int64_t deque_time = 0;
378 int64_t cyclicbuffer_time = 0;
379 for (int i = 0; i < 100; i++) {
380 // ResetMagicTypeUsage(MagicType<std::string>::usage);
381 deque_time += TestStringBufferPerformance(&double_ended, 1000000u, 1023u);
382 // printf("std::deque performance\n");
383 // PrintMagicTypeUsage(MagicType<std::string>::usage);
384
385 // ResetMagicTypeUsage(MagicType<std::string>::usage);
386 cyclicbuffer_time += TestStringBufferPerformance(&cyclic, 1000000u, 1023u);
387 // printf("CyclicBuffer performance\n");
388 // PrintMagicTypeUsage(MagicType<std::string>::usage);
389 // printf("\n");
390 }
391 printf("Time used by std::deque = %ld\n", deque_time / 100);
392 printf("Time used by CyclicBuffer = %ld\n", cyclicbuffer_time / 100);
393 }
394
395 void BehavesAsDeque(size_t operations, size_t capacity, uint64_t seed) {
396 Random random(seed);
397 std::deque<uint32_t> q;
398 CyclicBuffer<uint32_t, GrowthPolicy::ASSERT> cq(capacity);
399
400 for (size_t i = 0; i < operations; i++) {
401 bool insert = random.Rand<bool>();
402 bool front = random.Rand<bool>();
403 if ((insert && q.size() < capacity) || q.empty()) {
404 uint32_t value = random.Rand<uint32_t>();
405 if (front) {
406 q.push_front(value);
407 cq.push_front(value);
408 } else {
409 q.push_back(value);
410 cq.push_back(value);
411 }
412 } else {
413 if (front) {
414 q.pop_front();
415 cq.pop_front();
416 } else {
417 q.pop_back();
418 cq.pop_back();
419 }
420 }
421
422 EXPECT_EQ(q.size(), cq.size());
423 if (!q.empty()) {
424 EXPECT_EQ(q.front(), cq.front());
425 EXPECT_EQ(q.back(), cq.back());
426 }
427 }
428 }
429
430 TEST(CyclicBufferTest, BehavesAsDeque) {
431 BehavesAsDeque(1000000, 1023, 123454321);
432 }
433
434 TEST(CyclicBufferTest, BehavesAsDequeSmallBuffer) {
435 BehavesAsDeque(1000000, 4, 123454321);
436 }
437
438 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/base/numerics/cyclic_buffer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698