| 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 "platform/graphics/ContiguousContainer.h" | 5 #include "platform/graphics/ContiguousContainer.h" |
| 6 | 6 |
| 7 #include "testing/gmock/include/gmock/gmock.h" | 7 #include "testing/gmock/include/gmock/gmock.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
| 9 #include "wtf/TypeTraits.h" | 9 #include "wtf/TypeTraits.h" |
| 10 | 10 |
| 11 namespace blink { | 11 namespace blink { |
| 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 unsigned kNumElements = 150; | 30 static const unsigned kNumElements = 150; |
| 34 | 31 |
| 32 } // namespace |
| 33 |
| 35 TEST(ContiguousContainerTest, SimpleStructs) | 34 TEST(ContiguousContainerTest, SimpleStructs) |
| 36 { | 35 { |
| 37 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 36 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 38 list.allocateAndConstruct<Point2D>(1, 2); | 37 list.allocateAndConstruct<Point2D>(1, 2); |
| 39 list.allocateAndConstruct<Point3D>(3, 4, 5); | 38 list.allocateAndConstruct<Point3D>(3, 4, 5); |
| 40 list.allocateAndConstruct<Point2D>(6, 7); | 39 list.allocateAndConstruct<Point2D>(6, 7); |
| 41 | 40 |
| 42 ASSERT_EQ(3u, list.size()); | 41 ASSERT_EQ(3u, list.size()); |
| 43 EXPECT_EQ(1, list[0].x); | 42 EXPECT_EQ(1, list[0].x); |
| 44 EXPECT_EQ(2, list[0].y); | 43 EXPECT_EQ(2, list[0].y); |
| 45 EXPECT_EQ(3, list[1].x); | 44 EXPECT_EQ(3, list[1].x); |
| 46 EXPECT_EQ(4, list[1].y); | 45 EXPECT_EQ(4, list[1].y); |
| 47 EXPECT_EQ(5, static_cast<Point3D&>(list[1]).z); | 46 EXPECT_EQ(5, static_cast<Point3D&>(list[1]).z); |
| 48 EXPECT_EQ(6, list[2].x); | 47 EXPECT_EQ(6, list[2].x); |
| 49 EXPECT_EQ(7, list[2].y); | 48 EXPECT_EQ(7, list[2].y); |
| 50 } | 49 } |
| 51 | 50 |
| 52 TEST(ContiguousContainerTest, AllocateLots) | 51 TEST(ContiguousContainerTest, AllocateLots) |
| 53 { | 52 { |
| 54 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 53 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 55 for (int i = 0; i < (int)kNumElements; i++) { | 54 for (int i = 0; i < (int)kNumElements; i++) { |
| 56 list.allocateAndConstruct<Point2D>(i, i); | 55 list.allocateAndConstruct<Point2D>(i, i); |
| 57 list.allocateAndConstruct<Point2D>(i, i); | 56 list.allocateAndConstruct<Point2D>(i, i); |
| 58 list.removeLast(); | 57 list.removeLast(); |
| 59 } | 58 } |
| 60 ASSERT_EQ(kNumElements, list.size()); | 59 ASSERT_EQ(kNumElements, list.size()); |
| 61 for (int i = 0; i < (int)kNumElements; i++) { | 60 for (int i = 0; i < (int)kNumElements; i++) { |
| 62 ASSERT_EQ(i, list[i].x); | 61 ASSERT_EQ(i, list[i].x); |
| 63 ASSERT_EQ(i, list[i].y); | 62 ASSERT_EQ(i, list[i].y); |
| 64 } | 63 } |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 EXPECT_EQ(3u, list.size()); | 165 EXPECT_EQ(3u, list.size()); |
| 167 | 166 |
| 168 // The remaining ones are destroyed when the test finishes. | 167 // The remaining ones are destroyed when the test finishes. |
| 169 EXPECT_CALL(list[2], destruct()); | 168 EXPECT_CALL(list[2], destruct()); |
| 170 EXPECT_CALL(list[1], destruct()); | 169 EXPECT_CALL(list[1], destruct()); |
| 171 EXPECT_CALL(list[0], destruct()); | 170 EXPECT_CALL(list[0], destruct()); |
| 172 } | 171 } |
| 173 | 172 |
| 174 TEST(ContiguousContainerTest, InsertionAndIndexedAccess) | 173 TEST(ContiguousContainerTest, InsertionAndIndexedAccess) |
| 175 { | 174 { |
| 176 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 175 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 177 | 176 |
| 178 auto& point1 = list.allocateAndConstruct<Point2D>(); | 177 auto& point1 = list.allocateAndConstruct<Point2D>(); |
| 179 auto& point2 = list.allocateAndConstruct<Point2D>(); | 178 auto& point2 = list.allocateAndConstruct<Point2D>(); |
| 180 auto& point3 = list.allocateAndConstruct<Point2D>(); | 179 auto& point3 = list.allocateAndConstruct<Point2D>(); |
| 181 | 180 |
| 182 EXPECT_EQ(3u, list.size()); | 181 EXPECT_EQ(3u, list.size()); |
| 183 EXPECT_EQ(&point1, &list.first()); | 182 EXPECT_EQ(&point1, &list.first()); |
| 184 EXPECT_EQ(&point3, &list.last()); | 183 EXPECT_EQ(&point3, &list.last()); |
| 185 EXPECT_EQ(&point1, &list[0]); | 184 EXPECT_EQ(&point1, &list[0]); |
| 186 EXPECT_EQ(&point2, &list[1]); | 185 EXPECT_EQ(&point2, &list[1]); |
| 187 EXPECT_EQ(&point3, &list[2]); | 186 EXPECT_EQ(&point3, &list[2]); |
| 188 } | 187 } |
| 189 | 188 |
| 190 TEST(ContiguousContainerTest, InsertionAndClear) | 189 TEST(ContiguousContainerTest, InsertionAndClear) |
| 191 { | 190 { |
| 192 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 191 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 193 EXPECT_TRUE(list.isEmpty()); | 192 EXPECT_TRUE(list.isEmpty()); |
| 194 EXPECT_EQ(0u, list.size()); | 193 EXPECT_EQ(0u, list.size()); |
| 195 | 194 |
| 196 list.allocateAndConstruct<Point2D>(); | 195 list.allocateAndConstruct<Point2D>(); |
| 197 EXPECT_FALSE(list.isEmpty()); | 196 EXPECT_FALSE(list.isEmpty()); |
| 198 EXPECT_EQ(1u, list.size()); | 197 EXPECT_EQ(1u, list.size()); |
| 199 | 198 |
| 200 list.clear(); | 199 list.clear(); |
| 201 EXPECT_TRUE(list.isEmpty()); | 200 EXPECT_TRUE(list.isEmpty()); |
| 202 EXPECT_EQ(0u, list.size()); | 201 EXPECT_EQ(0u, list.size()); |
| 203 | 202 |
| 204 list.allocateAndConstruct<Point2D>(); | 203 list.allocateAndConstruct<Point2D>(); |
| 205 EXPECT_FALSE(list.isEmpty()); | 204 EXPECT_FALSE(list.isEmpty()); |
| 206 EXPECT_EQ(1u, list.size()); | 205 EXPECT_EQ(1u, list.size()); |
| 207 } | 206 } |
| 208 | 207 |
| 209 TEST(ContiguousContainerTest, ElementAddressesAreStable) | 208 TEST(ContiguousContainerTest, ElementAddressesAreStable) |
| 210 { | 209 { |
| 211 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 210 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 212 Vector<Point2D*> pointers; | 211 Vector<Point2D*> pointers; |
| 213 for (int i = 0; i < (int)kNumElements; i++) | 212 for (int i = 0; i < (int)kNumElements; i++) |
| 214 pointers.append(&list.allocateAndConstruct<Point2D>()); | 213 pointers.append(&list.allocateAndConstruct<Point2D>()); |
| 215 EXPECT_EQ(kNumElements, list.size()); | 214 EXPECT_EQ(kNumElements, list.size()); |
| 216 EXPECT_EQ(kNumElements, pointers.size()); | 215 EXPECT_EQ(kNumElements, pointers.size()); |
| 217 | 216 |
| 218 auto listIt = list.begin(); | 217 auto listIt = list.begin(); |
| 219 auto vectorIt = pointers.begin(); | 218 auto vectorIt = pointers.begin(); |
| 220 for (; listIt != list.end(); ++listIt, ++vectorIt) | 219 for (; listIt != list.end(); ++listIt, ++vectorIt) |
| 221 EXPECT_EQ(&*listIt, *vectorIt); | 220 EXPECT_EQ(&*listIt, *vectorIt); |
| 222 } | 221 } |
| 223 | 222 |
| 224 TEST(ContiguousContainerTest, ForwardIteration) | 223 TEST(ContiguousContainerTest, ForwardIteration) |
| 225 { | 224 { |
| 226 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 225 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 227 for (int i = 0; i < (int)kNumElements; i++) | 226 for (int i = 0; i < (int)kNumElements; i++) |
| 228 list.allocateAndConstruct<Point2D>(i, i); | 227 list.allocateAndConstruct<Point2D>(i, i); |
| 229 unsigned count = 0; | 228 unsigned count = 0; |
| 230 for (Point2D& point : list) { | 229 for (Point2D& point : list) { |
| 231 EXPECT_EQ((int)count, point.x); | 230 EXPECT_EQ((int)count, point.x); |
| 232 count++; | 231 count++; |
| 233 } | 232 } |
| 234 EXPECT_EQ(kNumElements, count); | 233 EXPECT_EQ(kNumElements, count); |
| 235 | 234 |
| 236 static_assert(std::is_same<decltype(*list.begin()), Point2D&>::value, | 235 static_assert(std::is_same<decltype(*list.begin()), Point2D&>::value, |
| 237 "Non-const iteration should produce non-const references."); | 236 "Non-const iteration should produce non-const references."); |
| 238 } | 237 } |
| 239 | 238 |
| 240 TEST(ContiguousContainerTest, ConstForwardIteration) | 239 TEST(ContiguousContainerTest, ConstForwardIteration) |
| 241 { | 240 { |
| 242 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 241 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 243 for (int i = 0; i < (int)kNumElements; i++) | 242 for (int i = 0; i < (int)kNumElements; i++) |
| 244 list.allocateAndConstruct<Point2D>(i, i); | 243 list.allocateAndConstruct<Point2D>(i, i); |
| 245 | 244 |
| 246 const auto& constList = list; | 245 const auto& constList = list; |
| 247 unsigned count = 0; | 246 unsigned count = 0; |
| 248 for (const Point2D& point : constList) { | 247 for (const Point2D& point : constList) { |
| 249 EXPECT_EQ((int)count, point.x); | 248 EXPECT_EQ((int)count, point.x); |
| 250 count++; | 249 count++; |
| 251 } | 250 } |
| 252 EXPECT_EQ(kNumElements, count); | 251 EXPECT_EQ(kNumElements, count); |
| 253 | 252 |
| 254 static_assert(std::is_same<decltype(*constList.begin()), const Point2D&>::va
lue, | 253 static_assert(std::is_same<decltype(*constList.begin()), const Point2D&>::va
lue, |
| 255 "Const iteration should produce const references."); | 254 "Const iteration should produce const references."); |
| 256 } | 255 } |
| 257 | 256 |
| 258 TEST(ContiguousContainerTest, ReverseIteration) | 257 TEST(ContiguousContainerTest, ReverseIteration) |
| 259 { | 258 { |
| 260 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 259 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 261 for (int i = 0; i < (int)kNumElements; i++) | 260 for (int i = 0; i < (int)kNumElements; i++) |
| 262 list.allocateAndConstruct<Point2D>(i, i); | 261 list.allocateAndConstruct<Point2D>(i, i); |
| 263 | 262 |
| 264 unsigned count = 0; | 263 unsigned count = 0; |
| 265 for (auto it = list.rbegin(); it != list.rend(); ++it) { | 264 for (auto it = list.rbegin(); it != list.rend(); ++it) { |
| 266 EXPECT_EQ((int)(kNumElements - 1 - count), it->x); | 265 EXPECT_EQ((int)(kNumElements - 1 - count), it->x); |
| 267 count++; | 266 count++; |
| 268 } | 267 } |
| 269 EXPECT_EQ(kNumElements, count); | 268 EXPECT_EQ(kNumElements, count); |
| 270 | 269 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 check_equal(); // One full, one empty. | 333 check_equal(); // One full, one empty. |
| 335 push(); | 334 push(); |
| 336 pop(); | 335 pop(); |
| 337 pop(); | 336 pop(); |
| 338 ASSERT_TRUE(list.isEmpty()); | 337 ASSERT_TRUE(list.isEmpty()); |
| 339 check_equal(); // Empty. | 338 check_equal(); // Empty. |
| 340 } | 339 } |
| 341 | 340 |
| 342 TEST(ContiguousContainerTest, AppendByMovingSameList) | 341 TEST(ContiguousContainerTest, AppendByMovingSameList) |
| 343 { | 342 { |
| 344 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 343 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 345 list.allocateAndConstruct<Point3D>(1, 2, 3); | 344 list.allocateAndConstruct<Point3D>(1, 2, 3); |
| 346 | 345 |
| 347 // Moves the Point3D to the end, and default-constructs a Point2D in its | 346 // Moves the Point3D to the end, and default-constructs a Point2D in its |
| 348 // place. | 347 // place. |
| 349 list.appendByMoving(list.first(), sizeof(Point3D)); | 348 list.appendByMoving(list.first(), sizeof(Point3D), log2Alignment<Point3D>())
; |
| 350 EXPECT_EQ(1, list.last().x); | 349 EXPECT_EQ(1, list.last().x); |
| 351 EXPECT_EQ(2, list.last().y); | 350 EXPECT_EQ(2, list.last().y); |
| 352 EXPECT_EQ(3, static_cast<const Point3D&>(list.last()).z); | 351 EXPECT_EQ(3, static_cast<const Point3D&>(list.last()).z); |
| 353 EXPECT_EQ(2u, list.size()); | 352 EXPECT_EQ(2u, list.size()); |
| 354 | 353 |
| 355 // Moves that Point2D to the end, and default-constructs another in its | 354 // Moves that Point2D to the end, and default-constructs another in its |
| 356 // place. | 355 // place. |
| 357 list.first().x = 4; | 356 list.first().x = 4; |
| 358 list.appendByMoving(list.first(), sizeof(Point2D)); | 357 list.appendByMoving(list.first(), sizeof(Point2D), log2Alignment<Point2D>())
; |
| 359 EXPECT_EQ(4, list.last().x); | 358 EXPECT_EQ(4, list.last().x); |
| 360 EXPECT_EQ(3u, list.size()); | 359 EXPECT_EQ(3u, list.size()); |
| 361 } | 360 } |
| 362 | 361 |
| 363 TEST(ContiguousContainerTest, AppendByMovingDoesNotDestruct) | 362 TEST(ContiguousContainerTest, AppendByMovingDoesNotDestruct) |
| 364 { | 363 { |
| 365 // GMock mock objects (e.g. MockDestructible) aren't guaranteed to be safe | 364 // GMock mock objects (e.g. MockDestructible) aren't guaranteed to be safe |
| 366 // to memcpy (which is required for appendByMoving). | 365 // to memcpy (which is required for appendByMoving). |
| 367 class DestructionNotifier { | 366 class DestructionNotifier { |
| 368 public: | 367 public: |
| 369 DestructionNotifier(bool* flag = nullptr) : m_flag(flag) { } | 368 DestructionNotifier(bool* flag = nullptr) : m_flag(flag) { } |
| 370 ~DestructionNotifier() { if (m_flag) *m_flag = true; } | 369 ~DestructionNotifier() { if (m_flag) *m_flag = true; } |
| 371 private: | 370 private: |
| 372 bool* m_flag; | 371 bool* m_flag; |
| 373 }; | 372 }; |
| 374 | 373 |
| 375 bool destroyed = false; | 374 bool destroyed = false; |
| 376 ContiguousContainer<DestructionNotifier> list1(sizeof(DestructionNotifier)); | 375 ContiguousContainer<DestructionNotifier> list1(sizeof(DestructionNotifier)); |
| 377 list1.allocateAndConstruct<DestructionNotifier>(&destroyed); | 376 list1.allocateAndConstruct<DestructionNotifier>(&destroyed); |
| 378 { | 377 { |
| 379 // Make sure destructor isn't called during appendByMoving. | 378 // Make sure destructor isn't called during appendByMoving. |
| 380 ContiguousContainer<DestructionNotifier> list2(sizeof(DestructionNotifie
r)); | 379 ContiguousContainer<DestructionNotifier> list2(sizeof(DestructionNotifie
r)); |
| 381 list2.appendByMoving(list1.last(), sizeof(DestructionNotifier)); | 380 list2.appendByMoving(list1.last(), sizeof(DestructionNotifier), log2Alig
nment<DestructionNotifier>()); |
| 382 EXPECT_FALSE(destroyed); | 381 EXPECT_FALSE(destroyed); |
| 383 } | 382 } |
| 384 // But it should be destroyed when list2 is. | 383 // But it should be destroyed when list2 is. |
| 385 EXPECT_TRUE(destroyed); | 384 EXPECT_TRUE(destroyed); |
| 386 } | 385 } |
| 387 | 386 |
| 388 TEST(ContiguousContainerTest, AppendByMovingReturnsMovedPointer) | 387 TEST(ContiguousContainerTest, AppendByMovingReturnsMovedPointer) |
| 389 { | 388 { |
| 390 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); | 389 ContiguousContainer<Point2D> list1(kMaxPointSize); |
| 391 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); | 390 ContiguousContainer<Point2D> list2(kMaxPointSize); |
| 392 | 391 |
| 393 Point2D& point = list1.allocateAndConstruct<Point2D>(); | 392 Point2D& point = list1.allocateAndConstruct<Point2D>(); |
| 394 Point2D& movedPoint1 = list2.appendByMoving(point, sizeof(Point2D)); | 393 Point2D& movedPoint1 = list2.appendByMoving(point, sizeof(Point2D), log2Alig
nment<Point2D>()); |
| 395 EXPECT_EQ(&movedPoint1, &list2.last()); | 394 EXPECT_EQ(&movedPoint1, &list2.last()); |
| 396 | 395 |
| 397 Point2D& movedPoint2 = list1.appendByMoving(movedPoint1, sizeof(Point2D)); | 396 Point2D& movedPoint2 = list1.appendByMoving(movedPoint1, sizeof(Point2D), lo
g2Alignment<Point2D>()); |
| 398 EXPECT_EQ(&movedPoint2, &list1.last()); | 397 EXPECT_EQ(&movedPoint2, &list1.last()); |
| 399 EXPECT_NE(&movedPoint1, &movedPoint2); | 398 EXPECT_NE(&movedPoint1, &movedPoint2); |
| 400 } | 399 } |
| 401 | 400 |
| 402 TEST(ContiguousContainerTest, AppendByMovingReplacesSourceWithNewElement) | 401 TEST(ContiguousContainerTest, AppendByMovingReplacesSourceWithNewElement) |
| 403 { | 402 { |
| 404 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); | 403 ContiguousContainer<Point2D> list1(kMaxPointSize); |
| 405 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); | 404 ContiguousContainer<Point2D> list2(kMaxPointSize); |
| 406 | 405 |
| 407 list1.allocateAndConstruct<Point2D>(1, 2); | 406 list1.allocateAndConstruct<Point2D>(1, 2); |
| 408 EXPECT_EQ(1, list1.first().x); | 407 EXPECT_EQ(1, list1.first().x); |
| 409 EXPECT_EQ(2, list1.first().y); | 408 EXPECT_EQ(2, list1.first().y); |
| 410 | 409 |
| 411 list2.appendByMoving(list1.first(), sizeof(Point2D)); | 410 list2.appendByMoving(list1.first(), sizeof(Point2D), log2Alignment<Point2D>(
)); |
| 412 EXPECT_EQ(0, list1.first().x); | 411 EXPECT_EQ(0, list1.first().x); |
| 413 EXPECT_EQ(0, list1.first().y); | 412 EXPECT_EQ(0, list1.first().y); |
| 414 EXPECT_EQ(1, list2.first().x); | 413 EXPECT_EQ(1, list2.first().x); |
| 415 EXPECT_EQ(2, list2.first().y); | 414 EXPECT_EQ(2, list2.first().y); |
| 416 | 415 |
| 417 EXPECT_EQ(1u, list1.size()); | 416 EXPECT_EQ(1u, list1.size()); |
| 418 EXPECT_EQ(1u, list2.size()); | 417 EXPECT_EQ(1u, list2.size()); |
| 419 } | 418 } |
| 420 | 419 |
| 421 TEST(ContiguousContainerTest, AppendByMovingElementsOfDifferentSizes) | 420 TEST(ContiguousContainerTest, AppendByMovingElementsOfDifferentSizes) |
| 422 { | 421 { |
| 423 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 422 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 424 list.allocateAndConstruct<Point3D>(1, 2, 3); | 423 list.allocateAndConstruct<Point3D>(1, 2, 3); |
| 425 list.allocateAndConstruct<Point2D>(4, 5); | 424 list.allocateAndConstruct<Point2D>(4, 5); |
| 426 | 425 |
| 427 EXPECT_EQ(1, list[0].x); | 426 EXPECT_EQ(1, list[0].x); |
| 428 EXPECT_EQ(2, list[0].y); | 427 EXPECT_EQ(2, list[0].y); |
| 429 EXPECT_EQ(3, static_cast<const Point3D&>(list[0]).z); | 428 EXPECT_EQ(3, static_cast<const Point3D&>(list[0]).z); |
| 430 EXPECT_EQ(4, list[1].x); | 429 EXPECT_EQ(4, list[1].x); |
| 431 EXPECT_EQ(5, list[1].y); | 430 EXPECT_EQ(5, list[1].y); |
| 432 | 431 |
| 433 // Test that moving the first element actually moves the entire object, not | 432 // Test that moving the first element actually moves the entire object, not |
| 434 // just the base element. | 433 // just the base element. |
| 435 list.appendByMoving(list[0], sizeof(Point3D)); | 434 list.appendByMoving(list[0], sizeof(Point3D), log2Alignment<Point3D>()); |
| 436 EXPECT_EQ(1, list[2].x); | 435 EXPECT_EQ(1, list[2].x); |
| 437 EXPECT_EQ(2, list[2].y); | 436 EXPECT_EQ(2, list[2].y); |
| 438 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); | 437 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); |
| 439 EXPECT_EQ(4, list[1].x); | 438 EXPECT_EQ(4, list[1].x); |
| 440 EXPECT_EQ(5, list[1].y); | 439 EXPECT_EQ(5, list[1].y); |
| 441 | 440 |
| 442 list.appendByMoving(list[1], sizeof(Point2D)); | 441 list.appendByMoving(list[1], sizeof(Point2D), log2Alignment<Point2D>()); |
| 443 EXPECT_EQ(1, list[2].x); | 442 EXPECT_EQ(1, list[2].x); |
| 444 EXPECT_EQ(2, list[2].y); | 443 EXPECT_EQ(2, list[2].y); |
| 445 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); | 444 EXPECT_EQ(3, static_cast<const Point3D&>(list[2]).z); |
| 446 EXPECT_EQ(4, list[3].x); | 445 EXPECT_EQ(4, list[3].x); |
| 447 EXPECT_EQ(5, list[3].y); | 446 EXPECT_EQ(5, list[3].y); |
| 448 } | 447 } |
| 449 | 448 |
| 450 TEST(ContiguousContainerTest, Swap) | 449 TEST(ContiguousContainerTest, Swap) |
| 451 { | 450 { |
| 452 ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize); | 451 ContiguousContainer<Point2D> list1(kMaxPointSize); |
| 453 list1.allocateAndConstruct<Point2D>(1, 2); | 452 list1.allocateAndConstruct<Point2D>(1, 2); |
| 454 ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize); | 453 ContiguousContainer<Point2D> list2(kMaxPointSize); |
| 455 list2.allocateAndConstruct<Point2D>(3, 4); | 454 list2.allocateAndConstruct<Point2D>(3, 4); |
| 456 list2.allocateAndConstruct<Point2D>(5, 6); | 455 list2.allocateAndConstruct<Point2D>(5, 6); |
| 457 | 456 |
| 458 EXPECT_EQ(1u, list1.size()); | 457 EXPECT_EQ(1u, list1.size()); |
| 459 EXPECT_EQ(1, list1[0].x); | 458 EXPECT_EQ(1, list1[0].x); |
| 460 EXPECT_EQ(2, list1[0].y); | 459 EXPECT_EQ(2, list1[0].y); |
| 461 EXPECT_EQ(2u, list2.size()); | 460 EXPECT_EQ(2u, list2.size()); |
| 462 EXPECT_EQ(3, list2[0].x); | 461 EXPECT_EQ(3, list2[0].x); |
| 463 EXPECT_EQ(4, list2[0].y); | 462 EXPECT_EQ(4, list2[0].y); |
| 464 EXPECT_EQ(5, list2[1].x); | 463 EXPECT_EQ(5, list2[1].x); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 484 | 483 |
| 485 // At time of writing, removing elements from the end can cause up to 7x the | 484 // At time of writing, removing elements from the end can cause up to 7x the |
| 486 // memory required to be consumed, in the worst case, since we can have up t
o | 485 // memory required to be consumed, in the worst case, since we can have up t
o |
| 487 // two trailing inner lists that are empty (for 2*size + 4*size in unused | 486 // two trailing inner lists that are empty (for 2*size + 4*size in unused |
| 488 // memory, due to the exponential growth strategy). | 487 // memory, due to the exponential growth strategy). |
| 489 // Unfortunately, this captures behaviour of the underlying allocator as | 488 // Unfortunately, this captures behaviour of the underlying allocator as |
| 490 // well as this container, so we're pretty loose here. This constant may | 489 // well as this container, so we're pretty loose here. This constant may |
| 491 // need to be adjusted. | 490 // need to be adjusted. |
| 492 const size_t maxWasteFactor = 8; | 491 const size_t maxWasteFactor = 8; |
| 493 | 492 |
| 494 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize, initialCap
acity); | 493 ContiguousContainer<Point2D> list(kMaxPointSize, initialCapacity); |
| 495 | 494 |
| 496 // The capacity should grow with the list. | 495 // The capacity should grow with the list. |
| 497 for (int i = 0; i < iterations; i++) { | 496 for (int i = 0; i < iterations; i++) { |
| 498 size_t capacity = list.capacityInBytes(); | 497 size_t capacity = list.capacityInBytes(); |
| 499 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); | 498 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); |
| 500 ASSERT_LE(capacity, | 499 ASSERT_LE(capacity, |
| 501 std::max(list.size() * sizeof(Point2D), upperBoundOnMinCapacity) * m
axWasteFactor); | 500 std::max(list.size() * sizeof(Point2D), upperBoundOnMinCapacity) * m
axWasteFactor); |
| 502 list.allocateAndConstruct<Point2D>(); | 501 list.allocateAndConstruct<Point2D>(); |
| 503 } | 502 } |
| 504 | 503 |
| 505 // The capacity should shrink with the list. | 504 // The capacity should shrink with the list. |
| 506 for (int i = 0; i < iterations; i++) { | 505 for (int i = 0; i < iterations; i++) { |
| 507 size_t capacity = list.capacityInBytes(); | 506 size_t capacity = list.capacityInBytes(); |
| 508 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); | 507 ASSERT_GE(capacity, list.size() * sizeof(Point2D)); |
| 509 ASSERT_LE(capacity, | 508 ASSERT_LE(capacity, |
| 510 std::max(list.size() * sizeof(Point2D), upperBoundOnMinCapacity) * m
axWasteFactor); | 509 std::max(list.size() * sizeof(Point2D), upperBoundOnMinCapacity) * m
axWasteFactor); |
| 511 list.removeLast(); | 510 list.removeLast(); |
| 512 } | 511 } |
| 513 } | 512 } |
| 514 | 513 |
| 515 TEST(ContiguousContainerTest, CapacityInBytesAfterClear) | 514 TEST(ContiguousContainerTest, CapacityInBytesAfterClear) |
| 516 { | 515 { |
| 517 // Clearing should restore the capacity of the container to the same as a | 516 // Clearing should restore the capacity of the container to the same as a |
| 518 // newly allocated one (without reserved capacity requested). | 517 // newly allocated one (without reserved capacity requested). |
| 519 ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize); | 518 ContiguousContainer<Point2D> list(kMaxPointSize); |
| 520 size_t emptyCapacity = list.capacityInBytes(); | 519 size_t emptyCapacity = list.capacityInBytes(); |
| 521 list.allocateAndConstruct<Point2D>(); | 520 list.allocateAndConstruct<Point2D>(); |
| 522 list.allocateAndConstruct<Point2D>(); | 521 list.allocateAndConstruct<Point2D>(); |
| 523 list.clear(); | 522 list.clear(); |
| 524 EXPECT_EQ(emptyCapacity, list.capacityInBytes()); | 523 EXPECT_EQ(emptyCapacity, list.capacityInBytes()); |
| 525 } | 524 } |
| 526 | 525 |
| 527 } // namespace | 526 TEST(ContiguousContainerTest, Alignment) |
| 527 { |
| 528 ContiguousContainer<char> container(64, 64); |
| 529 void* item1 = container.allocate(21, 4); // alignment 16 |
| 530 ASSERT_TRUE(item1); |
| 531 EXPECT_EQ(0u, reinterpret_cast<size_t>(item1) & 0x0F); |
| 532 EXPECT_GE(21u, container.usedCapacityInBytes()); |
| 533 // The initial gap may not be consistent among runs. |
| 534 // |--------21-------|-------------------43-----------------------| |
| 535 // | item1 | unused | |
| 536 |
| 537 void* item2 = container.allocate(9, 3); // alignment 8 |
| 538 ASSERT_TRUE(item2); |
| 539 EXPECT_EQ(0u, reinterpret_cast<size_t>(item2) & 7); |
| 540 // |---------24--------|---9---|----------------31----------------| |
| 541 // | item1 | | item2 | unused | |
| 542 EXPECT_EQ(24u + 9u, container.usedCapacityInBytes()); |
| 543 |
| 544 void* item3 = container.allocate(3, 2); // alignment 4 |
| 545 ASSERT_TRUE(item3); |
| 546 EXPECT_EQ(0u, reinterpret_cast<size_t>(item3) & 3); |
| 547 // |---------24--------|----12----|--3--|----------25-------------| |
| 548 // | item1 | | item2 | |item3| unused | |
| 549 EXPECT_EQ(24u + 12u + 3u, container.usedCapacityInBytes()); |
| 550 |
| 551 void* item4 = container.allocate(11, 0); |
| 552 ASSERT_TRUE(item4); |
| 553 // |---------24--------|----12----|--3--|---11---|-------14-------| |
| 554 // | item1 | | item2 | |item3| item4 | unused | |
| 555 EXPECT_EQ(24u + 12u + 3u + 11u, container.usedCapacityInBytes()); |
| 556 |
| 557 // All of the above allocations should be in the initial buffer. |
| 558 EXPECT_EQ(64u, container.capacityInBytes()); |
| 559 |
| 560 // The initial buffer can't hold another object aligned at 16 bytes. |
| 561 void* item5 = container.allocate(8, 4); |
| 562 ASSERT_TRUE(item5); |
| 563 EXPECT_EQ(0u, reinterpret_cast<size_t>(item5) & 0x0F); |
| 564 EXPECT_GT(container.capacityInBytes(), 64u); |
| 565 |
| 566 container.removeLast(); // item5 |
| 567 // The container should retain the last empty buffer to avoid reallocation o
f |
| 568 // buffer for new item allocations. |
| 569 EXPECT_GT(container.capacityInBytes(), 64u); |
| 570 |
| 571 container.removeLast(); // item4 |
| 572 EXPECT_EQ(24u + 12u + 3u, container.usedCapacityInBytes()); |
| 573 container.removeLast(); // item3 |
| 574 EXPECT_EQ(24u + 12u, container.usedCapacityInBytes()); |
| 575 container.removeLast(); // item2 |
| 576 EXPECT_EQ(24u, container.usedCapacityInBytes()); |
| 577 container.removeLast(); // item1 |
| 578 EXPECT_EQ(0u, container.usedCapacityInBytes()); |
| 579 } |
| 580 |
| 528 } // namespace blink | 581 } // namespace blink |
| OLD | NEW |