blob: c1658985a481279b0963061ff8d442b7ca3c2127 [file] [log] [blame]
wub5a5661f2019-11-05 08:08:09 -08001// Copyright (c) 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
6
7#include <cstddef>
8#include <cstdint>
9#include <memory>
10#include <type_traits>
11
12#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
14
15using testing::ElementsAre;
16
17namespace quic {
18namespace test {
19
20template <typename T, template <typename> class BaseAllocator = std::allocator>
21class CountingAllocator : public BaseAllocator<T> {
22 typedef BaseAllocator<T> BaseType;
23
24 public:
25 using propagate_on_container_copy_assignment = std::true_type;
26 using propagate_on_container_move_assignment = std::true_type;
27 using propagate_on_container_swap = std::true_type;
28
29 T* allocate(std::size_t n) {
30 ++shared_counts_->allocate_count;
31 return BaseType::allocate(n);
32 }
33
34 void deallocate(T* ptr, std::size_t n) {
35 ++shared_counts_->deallocate_count;
36 return BaseType::deallocate(ptr, n);
37 }
38
39 size_t allocate_count() const { return shared_counts_->allocate_count; }
40
41 size_t deallocate_count() const { return shared_counts_->deallocate_count; }
42
43 friend bool operator==(const CountingAllocator& lhs,
44 const CountingAllocator& rhs) {
45 return lhs.shared_counts_ == rhs.shared_counts_;
46 }
47
48 friend bool operator!=(const CountingAllocator& lhs,
49 const CountingAllocator& rhs) {
50 return !(lhs == rhs);
51 }
52
53 private:
54 struct Counts {
55 size_t allocate_count = 0;
56 size_t deallocate_count = 0;
57 };
58
59 std::shared_ptr<Counts> shared_counts_ = std::make_shared<Counts>();
60};
61
62template <typename T,
63 typename propagate_on_copy_assignment,
64 typename propagate_on_move_assignment,
65 typename propagate_on_swap,
66 bool equality_result,
67 template <typename> class BaseAllocator = std::allocator>
68struct ConfigurableAllocator : public BaseAllocator<T> {
69 using propagate_on_container_copy_assignment = propagate_on_copy_assignment;
70 using propagate_on_container_move_assignment = propagate_on_move_assignment;
71 using propagate_on_container_swap = propagate_on_swap;
72
73 friend bool operator==(const ConfigurableAllocator& /*lhs*/,
74 const ConfigurableAllocator& /*rhs*/) {
75 return equality_result;
76 }
77
78 friend bool operator!=(const ConfigurableAllocator& lhs,
79 const ConfigurableAllocator& rhs) {
80 return !(lhs == rhs);
81 }
82};
83
84// [1, 2, 3, 4] ==> [4, 1, 2, 3]
85template <typename Deque>
86void ShiftRight(Deque* dq, bool emplace) {
87 auto back = *(&dq->back());
88 dq->pop_back();
89 if (emplace) {
90 dq->emplace_front(back);
91 } else {
92 dq->push_front(back);
93 }
94}
95
96// [1, 2, 3, 4] ==> [2, 3, 4, 1]
97template <typename Deque>
98void ShiftLeft(Deque* dq, bool emplace) {
99 auto front = *(&dq->front());
100 dq->pop_front();
101 if (emplace) {
102 dq->emplace_back(front);
103 } else {
104 dq->push_back(front);
105 }
106}
107
108TEST(QuicCircularDeque, Empty) {
109 QuicCircularDeque<int> dq;
110 EXPECT_TRUE(dq.empty());
111 EXPECT_EQ(0u, dq.size());
112 dq.clear();
113 dq.push_back(10);
114 EXPECT_FALSE(dq.empty());
115 EXPECT_EQ(1u, dq.size());
116 EXPECT_EQ(10, dq.front());
117 EXPECT_EQ(10, dq.back());
118 dq.pop_front();
119 EXPECT_TRUE(dq.empty());
120 EXPECT_EQ(0u, dq.size());
121
rchb87ddb12019-11-14 12:26:05 -0800122 EXPECT_QUIC_DEBUG_DEATH(dq.front(), "");
123 EXPECT_QUIC_DEBUG_DEATH(dq.back(), "");
124 EXPECT_QUIC_DEBUG_DEATH(dq.at(0), "");
125 EXPECT_QUIC_DEBUG_DEATH(dq[0], "");
wub5a5661f2019-11-05 08:08:09 -0800126}
127
128TEST(QuicCircularDeque, Constructor) {
129 QuicCircularDeque<int> dq;
130 EXPECT_TRUE(dq.empty());
131
132 std::allocator<int> alloc;
133 QuicCircularDeque<int> dq1(alloc);
134 EXPECT_TRUE(dq1.empty());
135
136 QuicCircularDeque<int> dq2(8, 100, alloc);
137 EXPECT_THAT(dq2, ElementsAre(100, 100, 100, 100, 100, 100, 100, 100));
138
139 QuicCircularDeque<int> dq3(5, alloc);
140 EXPECT_THAT(dq3, ElementsAre(0, 0, 0, 0, 0));
141
142 QuicCircularDeque<int> dq4_rand_iter(dq3.begin(), dq3.end(), alloc);
143 EXPECT_THAT(dq4_rand_iter, ElementsAre(0, 0, 0, 0, 0));
144 EXPECT_EQ(dq4_rand_iter, dq3);
145
146 std::list<int> dq4_src = {4, 4, 4, 4};
147 QuicCircularDeque<int> dq4_bidi_iter(dq4_src.begin(), dq4_src.end());
148 EXPECT_THAT(dq4_bidi_iter, ElementsAre(4, 4, 4, 4));
149
150 QuicCircularDeque<int> dq5(dq4_bidi_iter);
151 EXPECT_THAT(dq5, ElementsAre(4, 4, 4, 4));
152 EXPECT_EQ(dq5, dq4_bidi_iter);
153
154 QuicCircularDeque<int> dq6(dq5, alloc);
155 EXPECT_THAT(dq6, ElementsAre(4, 4, 4, 4));
156 EXPECT_EQ(dq6, dq5);
157
158 QuicCircularDeque<int> dq7(std::move(*&dq6));
159 EXPECT_THAT(dq7, ElementsAre(4, 4, 4, 4));
160 EXPECT_TRUE(dq6.empty());
161
162 QuicCircularDeque<int> dq8_equal_allocator(std::move(*&dq7), alloc);
163 EXPECT_THAT(dq8_equal_allocator, ElementsAre(4, 4, 4, 4));
164 EXPECT_TRUE(dq7.empty());
165
166 QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_temp = {5, 6, 7, 8, 9};
167 QuicCircularDeque<int, 3, CountingAllocator<int>> dq8_unequal_allocator(
168 std::move(*&dq8_temp), CountingAllocator<int>());
169 EXPECT_THAT(dq8_unequal_allocator, ElementsAre(5, 6, 7, 8, 9));
170 EXPECT_TRUE(dq8_temp.empty());
171
172 QuicCircularDeque<int> dq9({3, 4, 5, 6, 7}, alloc);
173 EXPECT_THAT(dq9, ElementsAre(3, 4, 5, 6, 7));
174}
175
176TEST(QuicCircularDeque, Assign) {
177 // assign()
178 QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
179 dq.assign(7, 1);
180 EXPECT_THAT(dq, ElementsAre(1, 1, 1, 1, 1, 1, 1));
181 EXPECT_EQ(1u, dq.get_allocator().allocate_count());
182
183 QuicCircularDeque<int, 3, CountingAllocator<int>> dq2;
184 dq2.assign(dq.begin(), dq.end());
185 EXPECT_THAT(dq2, ElementsAre(1, 1, 1, 1, 1, 1, 1));
186 EXPECT_EQ(1u, dq2.get_allocator().allocate_count());
187 EXPECT_TRUE(std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.end()));
188
189 dq2.assign({2, 2, 2, 2, 2, 2});
190 EXPECT_THAT(dq2, ElementsAre(2, 2, 2, 2, 2, 2));
191
192 // Assign from a non random access iterator.
193 std::list<int> dq3_src = {3, 3, 3, 3, 3};
194 QuicCircularDeque<int, 3, CountingAllocator<int>> dq3;
195 dq3.assign(dq3_src.begin(), dq3_src.end());
196 EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
197 EXPECT_LT(1u, dq3.get_allocator().allocate_count());
198
199 // Copy assignment
wub9b164472019-11-06 06:56:35 -0800200 dq3 = *&dq3;
wub5a5661f2019-11-05 08:08:09 -0800201 EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
202
203 QuicCircularDeque<
204 int, 3,
205 ConfigurableAllocator<int,
206 /*propagate_on_copy_assignment=*/std::true_type,
207 /*propagate_on_move_assignment=*/std::true_type,
208 /*propagate_on_swap=*/std::true_type,
209 /*equality_result=*/false>>
210 dq4, dq5;
211 dq4.assign(dq3.begin(), dq3.end());
212 dq5 = dq4;
213 EXPECT_THAT(dq5, ElementsAre(3, 3, 3, 3, 3));
214
215 QuicCircularDeque<
216 int, 3,
217 ConfigurableAllocator<int,
218 /*propagate_on_copy_assignment=*/std::false_type,
219 /*propagate_on_move_assignment=*/std::true_type,
220 /*propagate_on_swap=*/std::true_type,
221 /*equality_result=*/true>>
222 dq6, dq7;
223 dq6.assign(dq3.begin(), dq3.end());
224 dq7 = dq6;
225 EXPECT_THAT(dq7, ElementsAre(3, 3, 3, 3, 3));
226
227 // Move assignment
228 dq3 = std::move(*&dq3);
229 EXPECT_THAT(dq3, ElementsAre(3, 3, 3, 3, 3));
230
231 ASSERT_TRUE(decltype(
232 dq3.get_allocator())::propagate_on_container_move_assignment::value);
233 decltype(dq3) dq8;
234 dq8 = std::move(*&dq3);
235 EXPECT_THAT(dq8, ElementsAre(3, 3, 3, 3, 3));
236 EXPECT_TRUE(dq3.empty());
237
238 QuicCircularDeque<
239 int, 3,
240 ConfigurableAllocator<int,
241 /*propagate_on_copy_assignment=*/std::true_type,
242 /*propagate_on_move_assignment=*/std::false_type,
243 /*propagate_on_swap=*/std::true_type,
244 /*equality_result=*/true>>
245 dq9, dq10;
246 dq9.assign(dq8.begin(), dq8.end());
247 dq10.assign(dq2.begin(), dq2.end());
248 dq9 = std::move(*&dq10);
249 EXPECT_THAT(dq9, ElementsAre(2, 2, 2, 2, 2, 2));
250 EXPECT_TRUE(dq10.empty());
251
252 QuicCircularDeque<
253 int, 3,
254 ConfigurableAllocator<int,
255 /*propagate_on_copy_assignment=*/std::true_type,
256 /*propagate_on_move_assignment=*/std::false_type,
257 /*propagate_on_swap=*/std::true_type,
258 /*equality_result=*/false>>
259 dq11, dq12;
260 dq11.assign(dq8.begin(), dq8.end());
261 dq12.assign(dq2.begin(), dq2.end());
262 dq11 = std::move(*&dq12);
263 EXPECT_THAT(dq11, ElementsAre(2, 2, 2, 2, 2, 2));
264 EXPECT_TRUE(dq12.empty());
265}
266
267TEST(QuicCircularDeque, Access) {
268 // at()
269 // operator[]
270 // front()
271 // back()
272
273 QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
274 dq.push_back(10);
275 EXPECT_EQ(dq.front(), 10);
276 EXPECT_EQ(dq.back(), 10);
277 EXPECT_EQ(dq.at(0), 10);
278 EXPECT_EQ(dq[0], 10);
279 dq.front() = 12;
280 EXPECT_EQ(dq.front(), 12);
281 EXPECT_EQ(dq.back(), 12);
282 EXPECT_EQ(dq.at(0), 12);
283 EXPECT_EQ(dq[0], 12);
284
285 const auto& dqref = dq;
286 EXPECT_EQ(dqref.front(), 12);
287 EXPECT_EQ(dqref.back(), 12);
288 EXPECT_EQ(dqref.at(0), 12);
289 EXPECT_EQ(dqref[0], 12);
290
291 dq.pop_front();
292 EXPECT_TRUE(dqref.empty());
293
294 // Push to capacity.
295 dq.push_back(15);
296 dq.push_front(5);
297 dq.push_back(25);
298 EXPECT_EQ(dq.size(), dq.capacity());
299 EXPECT_THAT(dq, ElementsAre(5, 15, 25));
300 EXPECT_LT(&dq.front(), &dq.back());
301 EXPECT_EQ(dq.front(), 5);
302 EXPECT_EQ(dq.back(), 25);
303 EXPECT_EQ(dq.at(0), 5);
304 EXPECT_EQ(dq.at(1), 15);
305 EXPECT_EQ(dq.at(2), 25);
306 EXPECT_EQ(dq[0], 5);
307 EXPECT_EQ(dq[1], 15);
308 EXPECT_EQ(dq[2], 25);
309
310 // Shift right such that begin=1 and end=0. Data is still not wrapped.
311 dq.pop_front();
312 dq.push_back(35);
313 EXPECT_THAT(dq, ElementsAre(15, 25, 35));
314 EXPECT_LT(&dq.front(), &dq.back());
315 EXPECT_EQ(dq.front(), 15);
316 EXPECT_EQ(dq.back(), 35);
317 EXPECT_EQ(dq.at(0), 15);
318 EXPECT_EQ(dq.at(1), 25);
319 EXPECT_EQ(dq.at(2), 35);
320 EXPECT_EQ(dq[0], 15);
321 EXPECT_EQ(dq[1], 25);
322 EXPECT_EQ(dq[2], 35);
323
324 // Shift right such that data is wrapped.
325 dq.pop_front();
326 dq.push_back(45);
327 EXPECT_THAT(dq, ElementsAre(25, 35, 45));
328 EXPECT_GT(&dq.front(), &dq.back());
329 EXPECT_EQ(dq.front(), 25);
330 EXPECT_EQ(dq.back(), 45);
331 EXPECT_EQ(dq.at(0), 25);
332 EXPECT_EQ(dq.at(1), 35);
333 EXPECT_EQ(dq.at(2), 45);
334 EXPECT_EQ(dq[0], 25);
335 EXPECT_EQ(dq[1], 35);
336 EXPECT_EQ(dq[2], 45);
337
338 // Shift right again, data is still wrapped.
339 dq.pop_front();
340 dq.push_back(55);
341 EXPECT_THAT(dq, ElementsAre(35, 45, 55));
342 EXPECT_GT(&dq.front(), &dq.back());
343 EXPECT_EQ(dq.front(), 35);
344 EXPECT_EQ(dq.back(), 55);
345 EXPECT_EQ(dq.at(0), 35);
346 EXPECT_EQ(dq.at(1), 45);
347 EXPECT_EQ(dq.at(2), 55);
348 EXPECT_EQ(dq[0], 35);
349 EXPECT_EQ(dq[1], 45);
350 EXPECT_EQ(dq[2], 55);
351
352 // Shift right one last time. begin returns to 0. Data is no longer wrapped.
353 dq.pop_front();
354 dq.push_back(65);
355 EXPECT_THAT(dq, ElementsAre(45, 55, 65));
356 EXPECT_LT(&dq.front(), &dq.back());
357 EXPECT_EQ(dq.front(), 45);
358 EXPECT_EQ(dq.back(), 65);
359 EXPECT_EQ(dq.at(0), 45);
360 EXPECT_EQ(dq.at(1), 55);
361 EXPECT_EQ(dq.at(2), 65);
362 EXPECT_EQ(dq[0], 45);
363 EXPECT_EQ(dq[1], 55);
364 EXPECT_EQ(dq[2], 65);
365
366 EXPECT_EQ(1u, dq.get_allocator().allocate_count());
367}
368
369TEST(QuicCircularDeque, Iterate) {
370 QuicCircularDeque<int> dq;
371 EXPECT_EQ(dq.begin(), dq.end());
372 EXPECT_EQ(dq.cbegin(), dq.cend());
373 EXPECT_EQ(dq.rbegin(), dq.rend());
374 EXPECT_EQ(dq.crbegin(), dq.crend());
375
376 dq.emplace_back(2);
377 QuicCircularDeque<int>::const_iterator citer = dq.begin();
378 EXPECT_NE(citer, dq.end());
379 EXPECT_EQ(*citer, 2);
380 ++citer;
381 EXPECT_EQ(citer, dq.end());
382
383 EXPECT_EQ(*dq.begin(), 2);
384 EXPECT_EQ(*dq.cbegin(), 2);
385 EXPECT_EQ(*dq.rbegin(), 2);
386 EXPECT_EQ(*dq.crbegin(), 2);
387
388 dq.emplace_front(1);
389 QuicCircularDeque<int>::const_reverse_iterator criter = dq.rbegin();
390 EXPECT_NE(criter, dq.rend());
391 EXPECT_EQ(*criter, 2);
392 ++criter;
393 EXPECT_NE(criter, dq.rend());
394 EXPECT_EQ(*criter, 1);
395 ++criter;
396 EXPECT_EQ(criter, dq.rend());
397
398 EXPECT_EQ(*dq.begin(), 1);
399 EXPECT_EQ(*dq.cbegin(), 1);
400 EXPECT_EQ(*dq.rbegin(), 2);
401 EXPECT_EQ(*dq.crbegin(), 2);
402
403 dq.push_back(3);
404
405 // Forward iterate.
406 int expected_value = 1;
407 for (QuicCircularDeque<int>::iterator it = dq.begin(); it != dq.end(); ++it) {
408 EXPECT_EQ(expected_value++, *it);
409 }
410
411 expected_value = 1;
412 for (QuicCircularDeque<int>::const_iterator it = dq.cbegin(); it != dq.cend();
413 ++it) {
414 EXPECT_EQ(expected_value++, *it);
415 }
416
417 // Reverse iterate.
418 expected_value = 3;
419 for (QuicCircularDeque<int>::reverse_iterator it = dq.rbegin();
420 it != dq.rend(); ++it) {
421 EXPECT_EQ(expected_value--, *it);
422 }
423
424 expected_value = 3;
425 for (QuicCircularDeque<int>::const_reverse_iterator it = dq.crbegin();
426 it != dq.crend(); ++it) {
427 EXPECT_EQ(expected_value--, *it);
428 }
429}
430
431TEST(QuicCircularDeque, Iterator) {
432 // Default constructed iterators of the same type compare equal.
433 EXPECT_EQ(QuicCircularDeque<int>::iterator(),
434 QuicCircularDeque<int>::iterator());
435 EXPECT_EQ(QuicCircularDeque<int>::const_iterator(),
436 QuicCircularDeque<int>::const_iterator());
437 EXPECT_EQ(QuicCircularDeque<int>::reverse_iterator(),
438 QuicCircularDeque<int>::reverse_iterator());
439 EXPECT_EQ(QuicCircularDeque<int>::const_reverse_iterator(),
440 QuicCircularDeque<int>::const_reverse_iterator());
441
442 QuicCircularDeque<QuicCircularDeque<int>, 3> dqdq = {
443 {1, 2}, {10, 20, 30}, {100, 200, 300, 400}};
444
445 // iter points to {1, 2}
446 decltype(dqdq)::iterator iter = dqdq.begin();
447 EXPECT_EQ(iter->size(), 2u);
448 EXPECT_THAT(*iter, ElementsAre(1, 2));
449
450 // citer points to {10, 20, 30}
451 decltype(dqdq)::const_iterator citer = dqdq.cbegin() + 1;
452 EXPECT_NE(*iter, *citer);
453 EXPECT_EQ(citer->size(), 3u);
454 int x = 10;
455 for (auto it = citer->begin(); it != citer->end(); ++it) {
456 EXPECT_EQ(*it, x);
457 x += 10;
458 }
459
460 EXPECT_LT(iter, citer);
461 EXPECT_LE(iter, iter);
462 EXPECT_GT(citer, iter);
463 EXPECT_GE(citer, citer);
464
465 // iter points to {100, 200, 300, 400}
466 iter += 2;
467 EXPECT_NE(*iter, *citer);
468 EXPECT_EQ(iter->size(), 4u);
469 for (int i = 1; i <= 4; ++i) {
470 EXPECT_EQ(iter->begin()[i - 1], i * 100);
471 }
472
473 EXPECT_LT(citer, iter);
474 EXPECT_LE(iter, iter);
475 EXPECT_GT(iter, citer);
476 EXPECT_GE(citer, citer);
477
478 // iter points to {10, 20, 30}. (same as citer)
479 iter -= 1;
480 EXPECT_EQ(*iter, *citer);
481 EXPECT_EQ(iter->size(), 3u);
482 x = 10;
483 for (auto it = iter->begin(); it != iter->end();) {
484 EXPECT_EQ(*(it++), x);
485 x += 10;
486 }
487 x = 30;
488 for (auto it = iter->begin() + 2; it != iter->begin();) {
489 EXPECT_EQ(*(it--), x);
490 x -= 10;
491 }
492}
493
494TEST(QuicCircularDeque, Resize) {
495 QuicCircularDeque<int, 3, CountingAllocator<int>> dq;
496 dq.resize(8);
497 EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0));
498 EXPECT_EQ(1u, dq.get_allocator().allocate_count());
499
500 dq.resize(10, 5);
501 EXPECT_THAT(dq, ElementsAre(0, 0, 0, 0, 0, 0, 0, 0, 5, 5));
502
503 QuicCircularDeque<int, 3, CountingAllocator<int>> dq2 = dq;
504
505 for (size_t new_size = dq.size(); new_size != 0; --new_size) {
506 dq.resize(new_size);
507 EXPECT_TRUE(
508 std::equal(dq.begin(), dq.end(), dq2.begin(), dq2.begin() + new_size));
509 }
510
511 dq.resize(0);
512 EXPECT_TRUE(dq.empty());
513
514 // Resize when data is wrapped.
515 ASSERT_EQ(dq2.size(), dq2.capacity());
516 while (dq2.size() < dq2.capacity()) {
517 dq2.push_back(5);
518 }
519
520 // Shift left once such that data is wrapped.
521 ASSERT_LT(&dq2.front(), &dq2.back());
522 dq2.pop_back();
523 dq2.push_front(-5);
524 ASSERT_GT(&dq2.front(), &dq2.back());
525
526 EXPECT_EQ(-5, dq2.front());
527 EXPECT_EQ(5, dq2.back());
528 dq2.resize(dq2.size() + 1, 10);
529
530 // Data should be unwrapped after the resize.
531 ASSERT_LT(&dq2.front(), &dq2.back());
532 EXPECT_EQ(-5, dq2.front());
533 EXPECT_EQ(10, dq2.back());
534 EXPECT_EQ(5, *(dq2.rbegin() + 1));
535}
536
537namespace {
538class Foo {
539 public:
540 Foo() : Foo(0xF00) {}
541
542 explicit Foo(int i) : i_(new int(i)) {}
543
544 ~Foo() {
545 if (i_ != nullptr) {
546 delete i_;
547 // Do not set i_ to nullptr such that if the container calls destructor
548 // multiple times, asan can detect it.
549 }
550 }
551
552 Foo(const Foo& other) : i_(new int(*other.i_)) {}
553
554 Foo(Foo&& other) = delete;
555
556 void Set(int i) { *i_ = i; }
557
558 int i() const { return *i_; }
559
560 friend bool operator==(const Foo& lhs, const Foo& rhs) {
561 return lhs.i() == rhs.i();
562 }
563
564 friend std::ostream& operator<<(std::ostream& os, const Foo& foo) {
565 return os << "Foo(" << foo.i() << ")";
566 }
567
568 private:
569 // By pointing i_ to a dynamically allocated integer, a memory leak will be
570 // reported if the container forget to properly destruct this object.
571 int* i_ = nullptr;
572};
573} // namespace
574
575TEST(QuicCircularDeque, RelocateNonTriviallyCopyable) {
576 // When relocating non-trivially-copyable objects:
577 // - Move constructor is preferred, if available.
578 // - Copy constructor is used otherwise.
579
580 {
581 // Move construct in Relocate.
582 typedef std::unique_ptr<Foo> MoveConstructible;
wub9b164472019-11-06 06:56:35 -0800583 ASSERT_FALSE(std::is_trivially_copyable<MoveConstructible>::value);
584 ASSERT_TRUE(std::is_move_constructible<MoveConstructible>::value);
wub5a5661f2019-11-05 08:08:09 -0800585 QuicCircularDeque<MoveConstructible, 3,
586 CountingAllocator<MoveConstructible>>
587 dq1;
588 dq1.resize(3);
589 EXPECT_EQ(dq1.size(), dq1.capacity());
590 EXPECT_EQ(1u, dq1.get_allocator().allocate_count());
591
592 dq1.emplace_back(new Foo(0xF1)); // Cause existing elements to relocate.
593 EXPECT_EQ(4u, dq1.size());
594 EXPECT_EQ(2u, dq1.get_allocator().allocate_count());
595 EXPECT_EQ(dq1[0], nullptr);
596 EXPECT_EQ(dq1[1], nullptr);
597 EXPECT_EQ(dq1[2], nullptr);
598 EXPECT_EQ(dq1[3]->i(), 0xF1);
599 }
600
601 {
602 // Copy construct in Relocate.
603 typedef Foo NonMoveConstructible;
wub9b164472019-11-06 06:56:35 -0800604 ASSERT_FALSE(std::is_trivially_copyable<NonMoveConstructible>::value);
605 ASSERT_FALSE(std::is_move_constructible<NonMoveConstructible>::value);
wub5a5661f2019-11-05 08:08:09 -0800606 QuicCircularDeque<NonMoveConstructible, 3,
607 CountingAllocator<NonMoveConstructible>>
608 dq2;
609 dq2.resize(3);
610 EXPECT_EQ(dq2.size(), dq2.capacity());
611 EXPECT_EQ(1u, dq2.get_allocator().allocate_count());
612
613 dq2.emplace_back(0xF1); // Cause existing elements to relocate.
614 EXPECT_EQ(4u, dq2.size());
615 EXPECT_EQ(2u, dq2.get_allocator().allocate_count());
616 EXPECT_EQ(dq2[0].i(), 0xF00);
617 EXPECT_EQ(dq2[1].i(), 0xF00);
618 EXPECT_EQ(dq2[2].i(), 0xF00);
619 EXPECT_EQ(dq2[3].i(), 0xF1);
620 }
621}
622
623TEST(QuicCircularDeque, PushPop) {
624 // (push|pop|emplace)_(back|front)
625
626 {
627 QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq(4);
628 for (size_t i = 0; i < dq.size(); ++i) {
629 dq[i].Set(i + 1);
630 }
631 QUIC_LOG(INFO) << "dq initialized to " << dq;
632 EXPECT_THAT(dq, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4)));
633
634 ShiftLeft(&dq, false);
635 QUIC_LOG(INFO) << "shift left once : " << dq;
636 EXPECT_THAT(dq, ElementsAre(Foo(2), Foo(3), Foo(4), Foo(1)));
637
638 ShiftLeft(&dq, true);
639 QUIC_LOG(INFO) << "shift left twice: " << dq;
640 EXPECT_THAT(dq, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2)));
641 ASSERT_GT(&dq.front(), &dq.back());
642 // dq destructs with wrapped data.
643 }
644
645 {
646 QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq1(4);
647 for (size_t i = 0; i < dq1.size(); ++i) {
648 dq1[i].Set(i + 1);
649 }
650 QUIC_LOG(INFO) << "dq1 initialized to " << dq1;
651 EXPECT_THAT(dq1, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4)));
652
653 ShiftRight(&dq1, false);
654 QUIC_LOG(INFO) << "shift right once : " << dq1;
655 EXPECT_THAT(dq1, ElementsAre(Foo(4), Foo(1), Foo(2), Foo(3)));
656
657 ShiftRight(&dq1, true);
658 QUIC_LOG(INFO) << "shift right twice: " << dq1;
659 EXPECT_THAT(dq1, ElementsAre(Foo(3), Foo(4), Foo(1), Foo(2)));
660 ASSERT_GT(&dq1.front(), &dq1.back());
661 // dq1 destructs with wrapped data.
662 }
wub020640b2019-11-07 11:20:13 -0800663
664 { // Pop n elements from front.
665 QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq2(5);
666 for (size_t i = 0; i < dq2.size(); ++i) {
667 dq2[i].Set(i + 1);
668 }
669 EXPECT_THAT(dq2, ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)));
670
671 EXPECT_EQ(2u, dq2.pop_front_n(2));
672 EXPECT_THAT(dq2, ElementsAre(Foo(3), Foo(4), Foo(5)));
673
674 EXPECT_EQ(3u, dq2.pop_front_n(100));
675 EXPECT_TRUE(dq2.empty());
676 }
677
678 { // Pop n elements from back.
679 QuicCircularDeque<Foo, 4, CountingAllocator<Foo>> dq3(6);
680 for (size_t i = 0; i < dq3.size(); ++i) {
681 dq3[i].Set(i + 1);
682 }
683 EXPECT_THAT(dq3,
684 ElementsAre(Foo(1), Foo(2), Foo(3), Foo(4), Foo(5), Foo(6)));
685
686 ShiftRight(&dq3, true);
687 ShiftRight(&dq3, true);
688 ShiftRight(&dq3, true);
689 EXPECT_THAT(dq3,
690 ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1), Foo(2), Foo(3)));
691
692 EXPECT_EQ(2u, dq3.pop_back_n(2));
693 EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5), Foo(6), Foo(1)));
694
695 EXPECT_EQ(2u, dq3.pop_back_n(2));
696 EXPECT_THAT(dq3, ElementsAre(Foo(4), Foo(5)));
697 }
wub5a5661f2019-11-05 08:08:09 -0800698}
699
700TEST(QuicCircularDeque, Allocation) {
701 CountingAllocator<int> alloc;
702
703 {
704 QuicCircularDeque<int, 3, CountingAllocator<int>> dq(alloc);
705 EXPECT_EQ(alloc, dq.get_allocator());
706 EXPECT_EQ(0u, dq.size());
707 EXPECT_EQ(0u, dq.capacity());
708 EXPECT_EQ(0u, alloc.allocate_count());
709 EXPECT_EQ(0u, alloc.deallocate_count());
710
711 for (int i = 1; i <= 18; ++i) {
712 SCOPED_TRACE(testing::Message()
713 << "i=" << i << ", capacity_b4_push=" << dq.capacity());
714 dq.push_back(i);
715 EXPECT_EQ(i, static_cast<int>(dq.size()));
716
717 const size_t capacity = 3 + (i - 1) / 3 * 3;
718 EXPECT_EQ(capacity, dq.capacity());
719 EXPECT_EQ(capacity / 3, alloc.allocate_count());
720 EXPECT_EQ(capacity / 3 - 1, alloc.deallocate_count());
721 }
722
723 dq.push_back(19);
724 EXPECT_EQ(22u, dq.capacity()); // 18 + 18 / 4
725 EXPECT_EQ(7u, alloc.allocate_count());
726 EXPECT_EQ(6u, alloc.deallocate_count());
727 }
728
729 EXPECT_EQ(7u, alloc.deallocate_count());
730}
731
732} // namespace test
733} // namespace quic
734
735// Use a non-quic namespace to make sure swap can be used via ADL.
736namespace {
737
738template <typename T>
739using SwappableAllocator = quic::test::ConfigurableAllocator<
740 T,
741 /*propagate_on_copy_assignment=*/std::true_type,
742 /*propagate_on_move_assignment=*/std::true_type,
743 /*propagate_on_swap=*/std::true_type,
744 /*equality_result=*/true>;
745
746template <typename T>
747using UnswappableEqualAllocator = quic::test::ConfigurableAllocator<
748 T,
749 /*propagate_on_copy_assignment=*/std::true_type,
750 /*propagate_on_move_assignment=*/std::true_type,
751 /*propagate_on_swap=*/std::false_type,
752 /*equality_result=*/true>;
753
754template <typename T>
755using UnswappableUnequalAllocator = quic::test::ConfigurableAllocator<
756 T,
757 /*propagate_on_copy_assignment=*/std::true_type,
758 /*propagate_on_move_assignment=*/std::true_type,
759 /*propagate_on_swap=*/std::false_type,
760 /*equality_result=*/false>;
761
762TEST(QuicCircularDeque, Swap) {
763 using std::swap;
764
765 quic::QuicCircularDeque<int64_t, 3, SwappableAllocator<int64_t>> dq1, dq2;
766 dq1.push_back(10);
767 dq1.push_back(11);
768 dq2.push_back(20);
769 swap(dq1, dq2);
770 EXPECT_THAT(dq1, ElementsAre(20));
771 EXPECT_THAT(dq2, ElementsAre(10, 11));
772
773 quic::QuicCircularDeque<char, 3, UnswappableEqualAllocator<char>> dq3, dq4;
774 dq3 = {1, 2, 3, 4, 5};
775 dq4 = {6, 7, 8, 9, 0};
776 swap(dq3, dq4);
777 EXPECT_THAT(dq3, ElementsAre(6, 7, 8, 9, 0));
778 EXPECT_THAT(dq4, ElementsAre(1, 2, 3, 4, 5));
779
780 quic::QuicCircularDeque<int, 3, UnswappableUnequalAllocator<int>> dq5, dq6;
781 dq6.push_front(4);
782
783 // Using UnswappableUnequalAllocator is ok as long as swap is not called.
784 dq5.assign(dq6.begin(), dq6.end());
785 EXPECT_THAT(dq5, ElementsAre(4));
786
wub5a5661f2019-11-05 08:08:09 -0800787 // Undefined behavior to swap between two containers with unequal allocators.
rchb87ddb12019-11-14 12:26:05 -0800788 EXPECT_QUIC_DEBUG_DEATH(swap(dq5, dq6), "Undefined swap behavior");
wub5a5661f2019-11-05 08:08:09 -0800789}
790} // namespace