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

Side by Side Diff: cc/base/contiguous_container_unittest.cc

Issue 2119033003: Fix alignment issue of ContiguousContainer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include "cc/base/contiguous_container.h" 7 #include "cc/base/contiguous_container.h"
8 #include "testing/gmock/include/gmock/gmock.h" 8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h" 9 #include "testing/gtest/include/gtest/gtest.h"
10 10
11 namespace cc { 11 namespace cc {
12 namespace { 12 namespace {
13 13
14 struct Point2D { 14 struct Point2D {
15 Point2D() : Point2D(0, 0) {} 15 Point2D() : Point2D(0, 0) {}
16 Point2D(int x, int y) : x(x), y(y) {} 16 Point2D(int x, int y) : x(x), y(y) {}
17 int x, y; 17 int x, y;
18 }; 18 };
19 19
20 struct Point3D : public Point2D { 20 struct Point3D : public Point2D {
21 Point3D() : Point3D(0, 0, 0) {} 21 Point3D() : Point3D(0, 0, 0) {}
22 Point3D(int x, int y, int z) : Point2D(x, y), z(z) {} 22 Point3D(int x, int y, int z) : Point2D(x, y), z(z) {}
23 int z; 23 int z;
24 }; 24 };
25 25
26 // Maximum size of a subclass of Point2D. 26 // Maximum size of a subclass of Point2D.
27 static const size_t kMaxPointSize = sizeof(Point3D); 27 static const size_t kMaxPointSize = sizeof(Point3D);
28 28
29 // Alignment for Point2D and its subclasses.
30 static const size_t kPointAlignment = sizeof(int);
31
32 // How many elements to use for tests with "plenty" of elements. 29 // How many elements to use for tests with "plenty" of elements.
33 static const size_t kNumElements = 150; 30 static const size_t kNumElements = 150;
34 31
32 } // namespace
33
35 TEST(ContiguousContainerTest, SimpleStructs) { 34 TEST(ContiguousContainerTest, SimpleStructs) {
36 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 35 ContiguousContainer<Point2D> list(kMaxPointSize);
37 list.AllocateAndConstruct<Point2D>(1, 2); 36 list.AllocateAndConstruct<Point2D>(1, 2);
38 list.AllocateAndConstruct<Point3D>(3, 4, 5); 37 list.AllocateAndConstruct<Point3D>(3, 4, 5);
39 list.AllocateAndConstruct<Point2D>(6, 7); 38 list.AllocateAndConstruct<Point2D>(6, 7);
40 39
41 ASSERT_EQ(3u, list.size()); 40 ASSERT_EQ(3u, list.size());
42 EXPECT_EQ(1, list[0].x); 41 EXPECT_EQ(1, list[0].x);
43 EXPECT_EQ(2, list[0].y); 42 EXPECT_EQ(2, list[0].y);
44 EXPECT_EQ(3, list[1].x); 43 EXPECT_EQ(3, list[1].x);
45 EXPECT_EQ(4, list[1].y); 44 EXPECT_EQ(4, list[1].y);
46 EXPECT_EQ(5, static_cast<Point3D&>(list[1]).z); 45 EXPECT_EQ(5, static_cast<Point3D&>(list[1]).z);
47 EXPECT_EQ(6, list[2].x); 46 EXPECT_EQ(6, list[2].x);
48 EXPECT_EQ(7, list[2].y); 47 EXPECT_EQ(7, list[2].y);
49 } 48 }
50 49
51 TEST(ContiguousContainerTest, AllocateLots) { 50 TEST(ContiguousContainerTest, AllocateLots) {
52 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 51 ContiguousContainer<Point2D> list(kMaxPointSize);
53 for (int i = 0; i < (int)kNumElements; i++) { 52 for (int i = 0; i < (int)kNumElements; i++) {
54 list.AllocateAndConstruct<Point2D>(i, i); 53 list.AllocateAndConstruct<Point2D>(i, i);
55 list.AllocateAndConstruct<Point2D>(i, i); 54 list.AllocateAndConstruct<Point2D>(i, i);
56 list.RemoveLast(); 55 list.RemoveLast();
57 } 56 }
58 ASSERT_EQ(kNumElements, list.size()); 57 ASSERT_EQ(kNumElements, list.size());
59 for (int i = 0; i < (int)kNumElements; i++) { 58 for (int i = 0; i < (int)kNumElements; i++) {
60 ASSERT_EQ(i, list[i].x); 59 ASSERT_EQ(i, list[i].x);
61 ASSERT_EQ(i, list[i].y); 60 ASSERT_EQ(i, list[i].y);
62 } 61 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 separator.Call(); 159 separator.Call();
161 EXPECT_EQ(3u, list.size()); 160 EXPECT_EQ(3u, list.size());
162 161
163 // The remaining ones are destroyed when the test finishes. 162 // The remaining ones are destroyed when the test finishes.
164 EXPECT_CALL(list[2], Destruct()); 163 EXPECT_CALL(list[2], Destruct());
165 EXPECT_CALL(list[1], Destruct()); 164 EXPECT_CALL(list[1], Destruct());
166 EXPECT_CALL(list[0], Destruct()); 165 EXPECT_CALL(list[0], Destruct());
167 } 166 }
168 167
169 TEST(ContiguousContainerTest, InsertionAndIndexedAccess) { 168 TEST(ContiguousContainerTest, InsertionAndIndexedAccess) {
170 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 169 ContiguousContainer<Point2D> list(kMaxPointSize);
171 170
172 auto& point1 = list.AllocateAndConstruct<Point2D>(); 171 auto& point1 = list.AllocateAndConstruct<Point2D>();
173 auto& point2 = list.AllocateAndConstruct<Point2D>(); 172 auto& point2 = list.AllocateAndConstruct<Point2D>();
174 auto& point3 = list.AllocateAndConstruct<Point2D>(); 173 auto& point3 = list.AllocateAndConstruct<Point2D>();
175 174
176 EXPECT_EQ(3u, list.size()); 175 EXPECT_EQ(3u, list.size());
177 EXPECT_EQ(&point1, &list.first()); 176 EXPECT_EQ(&point1, &list.first());
178 EXPECT_EQ(&point3, &list.last()); 177 EXPECT_EQ(&point3, &list.last());
179 EXPECT_EQ(&point1, &list[0]); 178 EXPECT_EQ(&point1, &list[0]);
180 EXPECT_EQ(&point2, &list[1]); 179 EXPECT_EQ(&point2, &list[1]);
181 EXPECT_EQ(&point3, &list[2]); 180 EXPECT_EQ(&point3, &list[2]);
182 } 181 }
183 182
184 TEST(ContiguousContainerTest, InsertionAndClear) { 183 TEST(ContiguousContainerTest, InsertionAndClear) {
185 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 184 ContiguousContainer<Point2D> list(kMaxPointSize);
186 EXPECT_TRUE(list.empty()); 185 EXPECT_TRUE(list.empty());
187 EXPECT_EQ(0u, list.size()); 186 EXPECT_EQ(0u, list.size());
188 187
189 list.AllocateAndConstruct<Point2D>(); 188 list.AllocateAndConstruct<Point2D>();
190 EXPECT_FALSE(list.empty()); 189 EXPECT_FALSE(list.empty());
191 EXPECT_EQ(1u, list.size()); 190 EXPECT_EQ(1u, list.size());
192 191
193 list.Clear(); 192 list.Clear();
194 EXPECT_TRUE(list.empty()); 193 EXPECT_TRUE(list.empty());
195 EXPECT_EQ(0u, list.size()); 194 EXPECT_EQ(0u, list.size());
196 195
197 list.AllocateAndConstruct<Point2D>(); 196 list.AllocateAndConstruct<Point2D>();
198 EXPECT_FALSE(list.empty()); 197 EXPECT_FALSE(list.empty());
199 EXPECT_EQ(1u, list.size()); 198 EXPECT_EQ(1u, list.size());
200 } 199 }
201 200
202 TEST(ContiguousContainerTest, ElementAddressesAreStable) { 201 TEST(ContiguousContainerTest, ElementAddressesAreStable) {
203 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 202 ContiguousContainer<Point2D> list(kMaxPointSize);
204 std::vector<Point2D*> pointers; 203 std::vector<Point2D*> pointers;
205 for (int i = 0; i < (int)kNumElements; i++) 204 for (int i = 0; i < (int)kNumElements; i++)
206 pointers.push_back(&list.AllocateAndConstruct<Point2D>()); 205 pointers.push_back(&list.AllocateAndConstruct<Point2D>());
207 EXPECT_EQ(kNumElements, list.size()); 206 EXPECT_EQ(kNumElements, list.size());
208 EXPECT_EQ(kNumElements, pointers.size()); 207 EXPECT_EQ(kNumElements, pointers.size());
209 208
210 auto listIt = list.begin(); 209 auto listIt = list.begin();
211 auto vectorIt = pointers.begin(); 210 auto vectorIt = pointers.begin();
212 for (; listIt != list.end(); ++listIt, ++vectorIt) 211 for (; listIt != list.end(); ++listIt, ++vectorIt)
213 EXPECT_EQ(&*listIt, *vectorIt); 212 EXPECT_EQ(&*listIt, *vectorIt);
214 } 213 }
215 214
216 TEST(ContiguousContainerTest, ForwardIteration) { 215 TEST(ContiguousContainerTest, ForwardIteration) {
217 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 216 ContiguousContainer<Point2D> list(kMaxPointSize);
218 for (int i = 0; i < (int)kNumElements; i++) 217 for (int i = 0; i < (int)kNumElements; i++)
219 list.AllocateAndConstruct<Point2D>(i, i); 218 list.AllocateAndConstruct<Point2D>(i, i);
220 unsigned count = 0; 219 unsigned count = 0;
221 for (Point2D& point : list) { 220 for (Point2D& point : list) {
222 EXPECT_EQ((int)count, point.x); 221 EXPECT_EQ((int)count, point.x);
223 count++; 222 count++;
224 } 223 }
225 EXPECT_EQ(kNumElements, count); 224 EXPECT_EQ(kNumElements, count);
226 225
227 static_assert(std::is_same<decltype(*list.begin()), Point2D&>::value, 226 static_assert(std::is_same<decltype(*list.begin()), Point2D&>::value,
228 "Non-const iteration should produce non-const references."); 227 "Non-const iteration should produce non-const references.");
229 } 228 }
230 229
231 TEST(ContiguousContainerTest, ConstForwardIteration) { 230 TEST(ContiguousContainerTest, ConstForwardIteration) {
232 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 231 ContiguousContainer<Point2D> list(kMaxPointSize);
233 for (int i = 0; i < (int)kNumElements; i++) 232 for (int i = 0; i < (int)kNumElements; i++)
234 list.AllocateAndConstruct<Point2D>(i, i); 233 list.AllocateAndConstruct<Point2D>(i, i);
235 234
236 const auto& const_list = list; 235 const auto& const_list = list;
237 unsigned count = 0; 236 unsigned count = 0;
238 for (const Point2D& point : const_list) { 237 for (const Point2D& point : const_list) {
239 EXPECT_EQ((int)count, point.x); 238 EXPECT_EQ((int)count, point.x);
240 count++; 239 count++;
241 } 240 }
242 EXPECT_EQ(kNumElements, count); 241 EXPECT_EQ(kNumElements, count);
243 242
244 static_assert( 243 static_assert(
245 std::is_same<decltype(*const_list.begin()), const Point2D&>::value, 244 std::is_same<decltype(*const_list.begin()), const Point2D&>::value,
246 "Const iteration should produce const references."); 245 "Const iteration should produce const references.");
247 } 246 }
248 247
249 TEST(ContiguousContainerTest, ReverseIteration) { 248 TEST(ContiguousContainerTest, ReverseIteration) {
250 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 249 ContiguousContainer<Point2D> list(kMaxPointSize);
251 for (int i = 0; i < (int)kNumElements; i++) 250 for (int i = 0; i < (int)kNumElements; i++)
252 list.AllocateAndConstruct<Point2D>(i, i); 251 list.AllocateAndConstruct<Point2D>(i, i);
253 252
254 unsigned count = 0; 253 unsigned count = 0;
255 for (auto it = list.rbegin(); it != list.rend(); ++it) { 254 for (auto it = list.rbegin(); it != list.rend(); ++it) {
256 EXPECT_EQ((int)(kNumElements - 1 - count), it->x); 255 EXPECT_EQ((int)(kNumElements - 1 - count), it->x);
257 count++; 256 count++;
258 } 257 }
259 EXPECT_EQ(kNumElements, count); 258 EXPECT_EQ(kNumElements, count);
260 259
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 pop(); 320 pop();
322 check_equal(); // One full, one empty. 321 check_equal(); // One full, one empty.
323 push(); 322 push();
324 pop(); 323 pop();
325 pop(); 324 pop();
326 ASSERT_TRUE(list.empty()); 325 ASSERT_TRUE(list.empty());
327 check_equal(); // Empty. 326 check_equal(); // Empty.
328 } 327 }
329 328
330 TEST(ContiguousContainerTest, AppendByMovingSameList) { 329 TEST(ContiguousContainerTest, AppendByMovingSameList) {
331 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 330 ContiguousContainer<Point2D> list(kMaxPointSize);
332 list.AllocateAndConstruct<Point3D>(1, 2, 3); 331 list.AllocateAndConstruct<Point3D>(1, 2, 3);
333 332
334 // Moves the Point3D to the end, and default-constructs a Point2D in its 333 // Moves the Point3D to the end, and default-constructs a Point2D in its
335 // place. 334 // place.
336 list.AppendByMoving(&list.first(), sizeof(Point3D)); 335 list.AppendByMoving(&list.first(), sizeof(Point3D), Log2Alignment<Point3D>());
337 EXPECT_EQ(1, list.last().x); 336 EXPECT_EQ(1, list.last().x);
338 EXPECT_EQ(2, list.last().y); 337 EXPECT_EQ(2, list.last().y);
339 EXPECT_EQ(3, static_cast<const Point3D&>(list.last()).z); 338 EXPECT_EQ(3, static_cast<const Point3D&>(list.last()).z);
340 EXPECT_EQ(2u, list.size()); 339 EXPECT_EQ(2u, list.size());
341 340
342 // Moves that Point2D to the end, and default-constructs another in its 341 // Moves that Point2D to the end, and default-constructs another in its
343 // place. 342 // place.
344 list.first().x = 4; 343 list.first().x = 4;
345 list.AppendByMoving(&list.first(), sizeof(Point2D)); 344 list.AppendByMoving(&list.first(), sizeof(Point2D), Log2Alignment<Point2D>());
346 EXPECT_EQ(4, list.last().x); 345 EXPECT_EQ(4, list.last().x);
347 EXPECT_EQ(3u, list.size()); 346 EXPECT_EQ(3u, list.size());
348 } 347 }
349 348
350 TEST(ContiguousContainerTest, AppendByMovingDoesNotDestruct) { 349 TEST(ContiguousContainerTest, AppendByMovingDoesNotDestruct) {
351 // GMock mock objects (e.g. MockDestructible) aren't guaranteed to be safe 350 // GMock mock objects (e.g. MockDestructible) aren't guaranteed to be safe
352 // to memcpy (which is required for AppendByMoving). 351 // to memcpy (which is required for AppendByMoving).
353 class DestructionNotifier { 352 class DestructionNotifier {
354 public: 353 public:
355 explicit DestructionNotifier(bool* flag = nullptr) : flag_(flag) {} 354 explicit DestructionNotifier(bool* flag = nullptr) : flag_(flag) {}
356 ~DestructionNotifier() { 355 ~DestructionNotifier() {
357 if (flag_) 356 if (flag_)
358 *flag_ = true; 357 *flag_ = true;
359 } 358 }
360 359
361 private: 360 private:
362 bool* flag_; 361 bool* flag_;
363 }; 362 };
364 363
365 bool destroyed = false; 364 bool destroyed = false;
366 ContiguousContainer<DestructionNotifier> list1(sizeof(DestructionNotifier)); 365 ContiguousContainer<DestructionNotifier> list1(sizeof(DestructionNotifier));
367 list1.AllocateAndConstruct<DestructionNotifier>(&destroyed); 366 list1.AllocateAndConstruct<DestructionNotifier>(&destroyed);
368 { 367 {
369 // Make sure destructor isn't called during AppendByMoving. 368 // Make sure destructor isn't called during AppendByMoving.
370 ContiguousContainer<DestructionNotifier> list2(sizeof(DestructionNotifier)); 369 ContiguousContainer<DestructionNotifier> list2(sizeof(DestructionNotifier));
371 list2.AppendByMoving(&list1.last(), sizeof(DestructionNotifier)); 370 list2.AppendByMoving(&list1.last(), sizeof(DestructionNotifier),
371 Log2Alignment<DestructionNotifier>());
372 EXPECT_FALSE(destroyed); 372 EXPECT_FALSE(destroyed);
373 } 373 }
374 // But it should be destroyed when list2 is. 374 // But it should be destroyed when list2 is.
375 EXPECT_TRUE(destroyed); 375 EXPECT_TRUE(destroyed);
376 } 376 }
377 377
378 TEST(ContiguousContainerTest, AppendByMovingReturnsMovedPointer) { 378 TEST(ContiguousContainerTest, AppendByMovingReturnsMovedPointer) {
379 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); 379 ContiguousContainer<Point2D> list1(kMaxPointSize);
380 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); 380 ContiguousContainer<Point2D> list2(kMaxPointSize);
381 381
382 Point2D& point = list1.AllocateAndConstruct<Point2D>(); 382 Point2D& point = list1.AllocateAndConstruct<Point2D>();
383 Point2D& moved_point1 = list2.AppendByMoving(&point, sizeof(Point2D)); 383 Point2D& moved_point1 =
384 list2.AppendByMoving(&point, sizeof(Point2D), Log2Alignment<Point2D>());
384 EXPECT_EQ(&moved_point1, &list2.last()); 385 EXPECT_EQ(&moved_point1, &list2.last());
385 386
386 Point2D& moved_point2 = list1.AppendByMoving(&moved_point1, sizeof(Point2D)); 387 Point2D& moved_point2 = list1.AppendByMoving(&moved_point1, sizeof(Point2D),
388 Log2Alignment<Point2D>());
387 EXPECT_EQ(&moved_point2, &list1.last()); 389 EXPECT_EQ(&moved_point2, &list1.last());
388 EXPECT_NE(&moved_point1, &moved_point2); 390 EXPECT_NE(&moved_point1, &moved_point2);
389 } 391 }
390 392
391 TEST(ContiguousContainerTest, AppendByMovingReplacesSourceWithNewElement) { 393 TEST(ContiguousContainerTest, AppendByMovingReplacesSourceWithNewElement) {
392 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); 394 ContiguousContainer<Point2D> list1(kMaxPointSize);
393 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); 395 ContiguousContainer<Point2D> list2(kMaxPointSize);
394 396
395 list1.AllocateAndConstruct<Point2D>(1, 2); 397 list1.AllocateAndConstruct<Point2D>(1, 2);
396 EXPECT_EQ(1, list1.first().x); 398 EXPECT_EQ(1, list1.first().x);
397 EXPECT_EQ(2, list1.first().y); 399 EXPECT_EQ(2, list1.first().y);
398 400
399 list2.AppendByMoving(&list1.first(), sizeof(Point2D)); 401 list2.AppendByMoving(&list1.first(), sizeof(Point2D),
402 Log2Alignment<Point2D>());
400 EXPECT_EQ(0, list1.first().x); 403 EXPECT_EQ(0, list1.first().x);
401 EXPECT_EQ(0, list1.first().y); 404 EXPECT_EQ(0, list1.first().y);
402 EXPECT_EQ(1, list2.first().x); 405 EXPECT_EQ(1, list2.first().x);
403 EXPECT_EQ(2, list2.first().y); 406 EXPECT_EQ(2, list2.first().y);
404 407
405 EXPECT_EQ(1u, list1.size()); 408 EXPECT_EQ(1u, list1.size());
406 EXPECT_EQ(1u, list2.size()); 409 EXPECT_EQ(1u, list2.size());
407 } 410 }
408 411
409 TEST(ContiguousContainerTest, AppendByMovingElementsOfDifferentSizes) { 412 TEST(ContiguousContainerTest, AppendByMovingElementsOfDifferentSizes) {
410 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 413 ContiguousContainer<Point2D> list(kMaxPointSize);
411 list.AllocateAndConstruct<Point3D>(1, 2, 3); 414 list.AllocateAndConstruct<Point3D>(1, 2, 3);
412 list.AllocateAndConstruct<Point2D>(4, 5); 415 list.AllocateAndConstruct<Point2D>(4, 5);
413 416
414 EXPECT_EQ(1, list[0].x); 417 EXPECT_EQ(1, list[0].x);
415 EXPECT_EQ(2, list[0].y); 418 EXPECT_EQ(2, list[0].y);
416 EXPECT_EQ(3, static_cast<const Point3D&>(list[0]).z); 419 EXPECT_EQ(3, static_cast<const Point3D&>(list[0]).z);
417 EXPECT_EQ(4, list[1].x); 420 EXPECT_EQ(4, list[1].x);
418 EXPECT_EQ(5, list[1].y); 421 EXPECT_EQ(5, list[1].y);
419 422
420 // Test that moving the first element actually moves the entire object, not 423 // Test that moving the first element actually moves the entire object, not
421 // just the base element. 424 // just the base element.
422 list.AppendByMoving(&list[0], sizeof(Point3D)); 425 list.AppendByMoving(&list[0], sizeof(Point3D), Log2Alignment<Point3D>());
423 EXPECT_EQ(1, list[2].x); 426 EXPECT_EQ(1, list[2].x);
424 EXPECT_EQ(2, list[2].y); 427 EXPECT_EQ(2, list[2].y);
425 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); 428 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z);
426 EXPECT_EQ(4, list[1].x); 429 EXPECT_EQ(4, list[1].x);
427 EXPECT_EQ(5, list[1].y); 430 EXPECT_EQ(5, list[1].y);
428 431
429 list.AppendByMoving(&list[1], sizeof(Point2D)); 432 list.AppendByMoving(&list[1], sizeof(Point2D), Log2Alignment<Point2D>());
430 EXPECT_EQ(1, list[2].x); 433 EXPECT_EQ(1, list[2].x);
431 EXPECT_EQ(2, list[2].y); 434 EXPECT_EQ(2, list[2].y);
432 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); 435 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z);
433 EXPECT_EQ(4, list[3].x); 436 EXPECT_EQ(4, list[3].x);
434 EXPECT_EQ(5, list[3].y); 437 EXPECT_EQ(5, list[3].y);
435 } 438 }
436 439
437 TEST(ContiguousContainerTest, Swap) { 440 TEST(ContiguousContainerTest, Swap) {
438 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); 441 ContiguousContainer<Point2D> list1(kMaxPointSize);
439 list1.AllocateAndConstruct<Point2D>(1, 2); 442 list1.AllocateAndConstruct<Point2D>(1, 2);
440 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); 443 ContiguousContainer<Point2D> list2(kMaxPointSize);
441 list2.AllocateAndConstruct<Point2D>(3, 4); 444 list2.AllocateAndConstruct<Point2D>(3, 4);
442 list2.AllocateAndConstruct<Point2D>(5, 6); 445 list2.AllocateAndConstruct<Point2D>(5, 6);
443 446
444 EXPECT_EQ(1u, list1.size()); 447 EXPECT_EQ(1u, list1.size());
445 EXPECT_EQ(1, list1[0].x); 448 EXPECT_EQ(1, list1[0].x);
446 EXPECT_EQ(2, list1[0].y); 449 EXPECT_EQ(2, list1[0].y);
447 EXPECT_EQ(2u, list2.size()); 450 EXPECT_EQ(2u, list2.size());
448 EXPECT_EQ(3, list2[0].x); 451 EXPECT_EQ(3, list2[0].x);
449 EXPECT_EQ(4, list2[0].y); 452 EXPECT_EQ(4, list2[0].y);
450 EXPECT_EQ(5, list2[1].x); 453 EXPECT_EQ(5, list2[1].x);
(...skipping 18 matching lines...) Expand all
469 472
470 // At time of writing, removing elements from the end can cause up to 7x the 473 // At time of writing, removing elements from the end can cause up to 7x the
471 // memory required to be consumed, in the worst case, since we can have up to 474 // memory required to be consumed, in the worst case, since we can have up to
472 // two trailing inner lists that are empty (for 2*size + 4*size in unused 475 // two trailing inner lists that are empty (for 2*size + 4*size in unused
473 // memory, due to the exponential growth strategy). 476 // memory, due to the exponential growth strategy).
474 // Unfortunately, this captures behaviour of the underlying allocator as 477 // Unfortunately, this captures behaviour of the underlying allocator as
475 // well as this container, so we're pretty loose here. This constant may 478 // well as this container, so we're pretty loose here. This constant may
476 // need to be adjusted. 479 // need to be adjusted.
477 const size_t max_waste_factor = 8; 480 const size_t max_waste_factor = 8;
478 481
479 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize, 482 ContiguousContainer<Point2D> list(kMaxPointSize, initial_capacity);
480 initial_capacity);
481 483
482 // The capacity should grow with the list. 484 // The capacity should grow with the list.
483 for (int i = 0; i < iterations; i++) { 485 for (int i = 0; i < iterations; i++) {
484 size_t capacity = list.GetCapacityInBytes(); 486 size_t capacity = list.GetCapacityInBytes();
485 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); 487 ASSERT_GE(capacity, list.size() * sizeof(Point2D));
486 ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D), 488 ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D),
487 upper_bound_on_min_capacity) * 489 upper_bound_on_min_capacity) *
488 max_waste_factor); 490 max_waste_factor);
489 list.AllocateAndConstruct<Point2D>(); 491 list.AllocateAndConstruct<Point2D>();
490 } 492 }
491 493
492 // The capacity should shrink with the list. 494 // The capacity should shrink with the list.
493 for (int i = 0; i < iterations; i++) { 495 for (int i = 0; i < iterations; i++) {
494 size_t capacity = list.GetCapacityInBytes(); 496 size_t capacity = list.GetCapacityInBytes();
495 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); 497 ASSERT_GE(capacity, list.size() * sizeof(Point2D));
496 ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D), 498 ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D),
497 upper_bound_on_min_capacity) * 499 upper_bound_on_min_capacity) *
498 max_waste_factor); 500 max_waste_factor);
499 list.RemoveLast(); 501 list.RemoveLast();
500 } 502 }
501 } 503 }
502 504
503 TEST(ContiguousContainerTest, CapacityInBytesAfterClear) { 505 TEST(ContiguousContainerTest, CapacityInBytesAfterClear) {
504 // Clearing should restore the capacity of the container to the same as a 506 // Clearing should restore the capacity of the container to the same as a
505 // newly allocated one (without reserved capacity requested). 507 // newly allocated one (without reserved capacity requested).
506 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); 508 ContiguousContainer<Point2D> list(kMaxPointSize);
507 size_t empty_capacity = list.GetCapacityInBytes(); 509 size_t empty_capacity = list.GetCapacityInBytes();
508 list.AllocateAndConstruct<Point2D>(); 510 list.AllocateAndConstruct<Point2D>();
509 list.AllocateAndConstruct<Point2D>(); 511 list.AllocateAndConstruct<Point2D>();
510 list.Clear(); 512 list.Clear();
511 EXPECT_EQ(empty_capacity, list.GetCapacityInBytes()); 513 EXPECT_EQ(empty_capacity, list.GetCapacityInBytes());
512 } 514 }
513 515
514 } // namespace 516 TEST(ContiguousContainerTest, Alignment) {
517 ContiguousContainer<char> container(64, 64);
518 void* item1 = container.Allocate(21, 4); // alignment 16
519 ASSERT_TRUE(item1);
520 EXPECT_EQ(0u, reinterpret_cast<size_t>(item1) & 0x0F);
521 EXPECT_GE(21u, container.UsedCapacityInBytes());
522 // The initial gap may not be consistent among runs.
523 // |--------21-------|-------------------43-----------------------|
524 // | item1 | unused |
525
526 void* item2 = container.Allocate(9, 3); // alignment 8
527 ASSERT_TRUE(item2);
528 EXPECT_EQ(0u, reinterpret_cast<size_t>(item2) & 7);
529 // |---------24--------|---9---|----------------31----------------|
530 // | item1 | | item2 | unused |
531 EXPECT_EQ(24u + 9u, container.UsedCapacityInBytes());
532
533 void* item3 = container.Allocate(3, 2); // alignment 4
534 ASSERT_TRUE(item3);
535 EXPECT_EQ(0u, reinterpret_cast<size_t>(item3) & 3);
536 // |---------24--------|----12----|--3--|----------25-------------|
537 // | item1 | | item2 | |item3| unused |
538 EXPECT_EQ(24u + 12u + 3u, container.UsedCapacityInBytes());
539
540 void* item4 = container.Allocate(11, 0);
541 ASSERT_TRUE(item4);
542 // |---------24--------|----12----|--3--|---11---|-------14-------|
543 // | item1 | | item2 | |item3| item4 | unused |
544 EXPECT_EQ(24u + 12u + 3u + 11u, container.UsedCapacityInBytes());
545
546 // All of the above allocations should be in the initial buffer.
547 EXPECT_EQ(64u, container.GetCapacityInBytes());
548
549 // The initial buffer can't hold another object aligned at 16 bytes.
550 void* item5 = container.Allocate(8, 4);
551 ASSERT_TRUE(item5);
552 EXPECT_EQ(0u, reinterpret_cast<size_t>(item5) & 0x0F);
553 EXPECT_GT(container.GetCapacityInBytes(), 64u);
554
555 container.RemoveLast(); // item5
556 // The container should retain the last empty buffer to avoid reallocation of
557 // buffer for new item allocations.
558 EXPECT_GT(container.GetCapacityInBytes(), 64u);
559
560 container.RemoveLast(); // item4
561 EXPECT_EQ(24u + 12u + 3u, container.UsedCapacityInBytes());
562 container.RemoveLast(); // item3
563 EXPECT_EQ(24u + 12u, container.UsedCapacityInBytes());
564 container.RemoveLast(); // item2
565 EXPECT_EQ(24u, container.UsedCapacityInBytes());
566 container.RemoveLast(); // item1
567 EXPECT_EQ(0u, container.UsedCapacityInBytes());
568 }
569
515 } // namespace cc 570 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698