OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 | 295 |
296 TEST(HashMapTest, ValueTypeDestructed) | 296 TEST(HashMapTest, ValueTypeDestructed) |
297 { | 297 { |
298 InstanceCounter::counter = 0; | 298 InstanceCounter::counter = 0; |
299 HashMap<int, InstanceCounter> map; | 299 HashMap<int, InstanceCounter> map; |
300 map.set(1, InstanceCounter()); | 300 map.set(1, InstanceCounter()); |
301 map.clear(); | 301 map.clear(); |
302 EXPECT_EQ(0, InstanceCounter::counter); | 302 EXPECT_EQ(0, InstanceCounter::counter); |
303 } | 303 } |
304 | 304 |
| 305 class MoveOnly { |
| 306 public: |
| 307 // kEmpty and kDeleted have special meanings when MoveOnly is used as the ke
y of a hash table. |
| 308 enum { |
| 309 kEmpty = 0, |
| 310 kDeleted = -1, |
| 311 kMovedOut = -2 |
| 312 }; |
| 313 |
| 314 explicit MoveOnly(int value = kEmpty) : m_value(value) { } |
| 315 MoveOnly(MoveOnly&& other) |
| 316 : m_value(other.m_value) |
| 317 { |
| 318 other.m_value = kMovedOut; |
| 319 } |
| 320 MoveOnly& operator=(MoveOnly&& other) |
| 321 { |
| 322 m_value = other.m_value; |
| 323 other.m_value = kMovedOut; |
| 324 return *this; |
| 325 } |
| 326 |
| 327 int value() const { return m_value; } |
| 328 |
| 329 private: |
| 330 MoveOnly(const MoveOnly&) = delete; |
| 331 MoveOnly& operator=(const MoveOnly&) = delete; |
| 332 |
| 333 int m_value; |
| 334 }; |
| 335 |
| 336 struct MoveOnlyHashTraits : public GenericHashTraits<MoveOnly> { |
| 337 // This is actually true, but we pretend that it's false to disable the opti
mization. |
| 338 static const bool emptyValueIsZero = false; |
| 339 |
| 340 static const bool hasIsEmptyValueFunction = true; |
| 341 static bool isEmptyValue(const MoveOnly& value) { return value.value() == Mo
veOnly::kEmpty; } |
| 342 static void constructDeletedValue(MoveOnly& slot, bool) { slot = MoveOnly(Mo
veOnly::kDeleted); } |
| 343 static bool isDeletedValue(const MoveOnly& value) { return value.value() ==
MoveOnly::kDeleted; } |
| 344 }; |
| 345 |
| 346 struct MoveOnlyHash { |
| 347 static unsigned hash(const MoveOnly& value) { return DefaultHash<int>::Hash:
:hash(value.value()); } |
| 348 static bool equal(const MoveOnly& left, const MoveOnly& right) |
| 349 { |
| 350 return DefaultHash<int>::Hash::equal(left.value(), right.value()); |
| 351 } |
| 352 static const bool safeToCompareToEmptyOrDeleted = true; |
| 353 }; |
| 354 |
| 355 } // anonymous namespace |
| 356 |
| 357 template <> |
| 358 struct HashTraits<MoveOnly> : public MoveOnlyHashTraits { }; |
| 359 |
| 360 template <> |
| 361 struct DefaultHash<MoveOnly> { |
| 362 using Hash = MoveOnlyHash; |
| 363 }; |
| 364 |
| 365 namespace { |
| 366 |
| 367 TEST(HashMapTest, MoveOnlyValueType) |
| 368 { |
| 369 using TheMap = HashMap<int, MoveOnly>; |
| 370 TheMap map; |
| 371 { |
| 372 TheMap::AddResult addResult = map.add(1, MoveOnly(10)); |
| 373 EXPECT_TRUE(addResult.isNewEntry); |
| 374 EXPECT_EQ(1, addResult.storedValue->key); |
| 375 EXPECT_EQ(10, addResult.storedValue->value.value()); |
| 376 } |
| 377 auto iter = map.find(1); |
| 378 ASSERT_TRUE(iter != map.end()); |
| 379 EXPECT_EQ(1, iter->key); |
| 380 EXPECT_EQ(10, iter->value.value()); |
| 381 |
| 382 iter = map.find(2); |
| 383 EXPECT_TRUE(iter == map.end()); |
| 384 |
| 385 // Try to add more to trigger rehashing. |
| 386 for (int i = 2; i < 32; ++i) { |
| 387 TheMap::AddResult addResult = map.add(i, MoveOnly(i * 10)); |
| 388 EXPECT_TRUE(addResult.isNewEntry); |
| 389 EXPECT_EQ(i, addResult.storedValue->key); |
| 390 EXPECT_EQ(i * 10, addResult.storedValue->value.value()); |
| 391 } |
| 392 |
| 393 iter = map.find(1); |
| 394 ASSERT_TRUE(iter != map.end()); |
| 395 EXPECT_EQ(1, iter->key); |
| 396 EXPECT_EQ(10, iter->value.value()); |
| 397 |
| 398 iter = map.find(7); |
| 399 ASSERT_TRUE(iter != map.end()); |
| 400 EXPECT_EQ(7, iter->key); |
| 401 EXPECT_EQ(70, iter->value.value()); |
| 402 |
| 403 { |
| 404 TheMap::AddResult addResult = map.set(9, MoveOnly(999)); |
| 405 EXPECT_FALSE(addResult.isNewEntry); |
| 406 EXPECT_EQ(9, addResult.storedValue->key); |
| 407 EXPECT_EQ(999, addResult.storedValue->value.value()); |
| 408 } |
| 409 |
| 410 map.remove(11); |
| 411 iter = map.find(11); |
| 412 EXPECT_TRUE(iter == map.end()); |
| 413 |
| 414 MoveOnly oneThirty(map.take(13)); |
| 415 EXPECT_EQ(130, oneThirty.value()); |
| 416 iter = map.find(13); |
| 417 EXPECT_TRUE(iter == map.end()); |
| 418 |
| 419 map.clear(); |
| 420 } |
| 421 |
| 422 TEST(HashMapTest, MoveOnlyKeyType) |
| 423 { |
| 424 // The content of this test is similar to the test above, except that the ty
pes of key and value are swapped. |
| 425 using TheMap = HashMap<MoveOnly, int>; |
| 426 TheMap map; |
| 427 { |
| 428 TheMap::AddResult addResult = map.add(MoveOnly(1), 10); |
| 429 EXPECT_TRUE(addResult.isNewEntry); |
| 430 EXPECT_EQ(1, addResult.storedValue->key.value()); |
| 431 EXPECT_EQ(10, addResult.storedValue->value); |
| 432 } |
| 433 auto iter = map.find(MoveOnly(1)); |
| 434 ASSERT_TRUE(iter != map.end()); |
| 435 EXPECT_EQ(1, iter->key.value()); |
| 436 EXPECT_EQ(10, iter->value); |
| 437 |
| 438 iter = map.find(MoveOnly(2)); |
| 439 EXPECT_TRUE(iter == map.end()); |
| 440 |
| 441 for (int i = 2; i < 32; ++i) { |
| 442 TheMap::AddResult addResult = map.add(MoveOnly(i), i * 10); |
| 443 EXPECT_TRUE(addResult.isNewEntry); |
| 444 EXPECT_EQ(i, addResult.storedValue->key.value()); |
| 445 EXPECT_EQ(i * 10, addResult.storedValue->value); |
| 446 } |
| 447 |
| 448 iter = map.find(MoveOnly(1)); |
| 449 ASSERT_TRUE(iter != map.end()); |
| 450 EXPECT_EQ(1, iter->key.value()); |
| 451 EXPECT_EQ(10, iter->value); |
| 452 |
| 453 iter = map.find(MoveOnly(7)); |
| 454 ASSERT_TRUE(iter != map.end()); |
| 455 EXPECT_EQ(7, iter->key.value()); |
| 456 EXPECT_EQ(70, iter->value); |
| 457 |
| 458 { |
| 459 TheMap::AddResult addResult = map.set(MoveOnly(9), 999); |
| 460 EXPECT_FALSE(addResult.isNewEntry); |
| 461 EXPECT_EQ(9, addResult.storedValue->key.value()); |
| 462 EXPECT_EQ(999, addResult.storedValue->value); |
| 463 } |
| 464 |
| 465 map.remove(MoveOnly(11)); |
| 466 iter = map.find(MoveOnly(11)); |
| 467 EXPECT_TRUE(iter == map.end()); |
| 468 |
| 469 int oneThirty = map.take(MoveOnly(13)); |
| 470 EXPECT_EQ(130, oneThirty); |
| 471 iter = map.find(MoveOnly(13)); |
| 472 EXPECT_TRUE(iter == map.end()); |
| 473 |
| 474 map.clear(); |
| 475 } |
| 476 |
305 } // anonymous namespace | 477 } // anonymous namespace |
306 | 478 |
307 } // namespace WTF | 479 } // namespace WTF |
OLD | NEW |