| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |