OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Apple Inc. All rights reserved. | 2 * Copyright (C) 2012 Apple 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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 HashSet<CountCopy> other(set); | 259 HashSet<CountCopy> other(set); |
260 counter = 0; | 260 counter = 0; |
261 set = std::move(other); | 261 set = std::move(other); |
262 EXPECT_EQ(0, counter); | 262 EXPECT_EQ(0, counter); |
263 | 263 |
264 counter = 0; | 264 counter = 0; |
265 HashSet<CountCopy> yetAnother(std::move(set)); | 265 HashSet<CountCopy> yetAnother(std::move(set)); |
266 EXPECT_EQ(0, counter); | 266 EXPECT_EQ(0, counter); |
267 } | 267 } |
268 | 268 |
| 269 class MoveOnly { |
| 270 public: |
| 271 // kEmpty and kDeleted have special meanings when MoveOnly is used as the ke
y of a hash table. |
| 272 enum { |
| 273 kEmpty = 0, |
| 274 kDeleted = -1, |
| 275 kMovedOut = -2 |
| 276 }; |
| 277 |
| 278 explicit MoveOnly(int value = kEmpty, int id = 0) : m_value(value), m_id(id)
{ } |
| 279 MoveOnly(MoveOnly&& other) |
| 280 : m_value(other.m_value) |
| 281 , m_id(other.m_id) |
| 282 { |
| 283 other.m_value = kMovedOut; |
| 284 other.m_id = 0; |
| 285 } |
| 286 MoveOnly& operator=(MoveOnly&& other) |
| 287 { |
| 288 m_value = other.m_value; |
| 289 m_id = other.m_id; |
| 290 other.m_value = kMovedOut; |
| 291 other.m_id = 0; |
| 292 return *this; |
| 293 } |
| 294 |
| 295 int value() const { return m_value; } |
| 296 // id() is used for distinguishing MoveOnlys with the same value(). |
| 297 int id() const { return m_id; } |
| 298 |
| 299 private: |
| 300 MoveOnly(const MoveOnly&) = delete; |
| 301 MoveOnly& operator=(const MoveOnly&) = delete; |
| 302 |
| 303 int m_value; |
| 304 int m_id; |
| 305 }; |
| 306 |
| 307 struct MoveOnlyHashTraits : public GenericHashTraits<MoveOnly> { |
| 308 // This is actually true, but we pretend that it's false to disable the opti
mization. |
| 309 static const bool emptyValueIsZero = false; |
| 310 |
| 311 static const bool hasIsEmptyValueFunction = true; |
| 312 static bool isEmptyValue(const MoveOnly& value) { return value.value() == Mo
veOnly::kEmpty; } |
| 313 static void constructDeletedValue(MoveOnly& slot, bool) { slot = MoveOnly(Mo
veOnly::kDeleted); } |
| 314 static bool isDeletedValue(const MoveOnly& value) { return value.value() ==
MoveOnly::kDeleted; } |
| 315 }; |
| 316 |
| 317 struct MoveOnlyHash { |
| 318 static unsigned hash(const MoveOnly& value) { return DefaultHash<int>::Hash:
:hash(value.value()); } |
| 319 static bool equal(const MoveOnly& left, const MoveOnly& right) |
| 320 { |
| 321 return DefaultHash<int>::Hash::equal(left.value(), right.value()); |
| 322 } |
| 323 static const bool safeToCompareToEmptyOrDeleted = true; |
| 324 }; |
| 325 |
| 326 } // anonymous namespace |
| 327 |
| 328 template <> |
| 329 struct HashTraits<MoveOnly> : public MoveOnlyHashTraits { }; |
| 330 |
| 331 template <> |
| 332 struct DefaultHash<MoveOnly> { |
| 333 using Hash = MoveOnlyHash; |
| 334 }; |
| 335 |
| 336 namespace { |
| 337 |
| 338 TEST(HashSetTest, MoveOnlyValue) |
| 339 { |
| 340 using TheSet = HashSet<MoveOnly>; |
| 341 TheSet set; |
| 342 { |
| 343 TheSet::AddResult addResult = set.add(MoveOnly(1, 1)); |
| 344 EXPECT_TRUE(addResult.isNewEntry); |
| 345 EXPECT_EQ(1, addResult.storedValue->value()); |
| 346 EXPECT_EQ(1, addResult.storedValue->id()); |
| 347 } |
| 348 auto iter = set.find(MoveOnly(1)); |
| 349 ASSERT_TRUE(iter != set.end()); |
| 350 EXPECT_EQ(1, iter->value()); |
| 351 |
| 352 iter = set.find(MoveOnly(2)); |
| 353 EXPECT_TRUE(iter == set.end()); |
| 354 |
| 355 for (int i = 2; i < 32; ++i) { |
| 356 TheSet::AddResult addResult = set.add(MoveOnly(i, i)); |
| 357 EXPECT_TRUE(addResult.isNewEntry); |
| 358 EXPECT_EQ(i, addResult.storedValue->value()); |
| 359 EXPECT_EQ(i, addResult.storedValue->id()); |
| 360 } |
| 361 |
| 362 iter = set.find(MoveOnly(1)); |
| 363 ASSERT_TRUE(iter != set.end()); |
| 364 EXPECT_EQ(1, iter->value()); |
| 365 EXPECT_EQ(1, iter->id()); |
| 366 |
| 367 iter = set.find(MoveOnly(7)); |
| 368 ASSERT_TRUE(iter != set.end()); |
| 369 EXPECT_EQ(7, iter->value()); |
| 370 EXPECT_EQ(7, iter->id()); |
| 371 |
| 372 { |
| 373 TheSet::AddResult addResult = set.add(MoveOnly(7, 777)); // With differe
nt ID for identification. |
| 374 EXPECT_FALSE(addResult.isNewEntry); |
| 375 EXPECT_EQ(7, addResult.storedValue->value()); |
| 376 EXPECT_EQ(7, addResult.storedValue->id()); |
| 377 } |
| 378 |
| 379 set.remove(MoveOnly(11)); |
| 380 iter = set.find(MoveOnly(11)); |
| 381 EXPECT_TRUE(iter == set.end()); |
| 382 |
| 383 MoveOnly thirteen(set.take(MoveOnly(13))); |
| 384 EXPECT_EQ(13, thirteen.value()); |
| 385 EXPECT_EQ(13, thirteen.id()); |
| 386 iter = set.find(MoveOnly(13)); |
| 387 EXPECT_TRUE(iter == set.end()); |
| 388 |
| 389 set.clear(); |
| 390 } |
| 391 |
269 } // anonymous namespace | 392 } // anonymous namespace |
270 | 393 |
271 } // namespace WTF | 394 } // namespace WTF |
OLD | NEW |