Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / xpcom / tests / gtest / TestHashtables.cpp
blobfe1e6a3611bfdbdd3f3ac87e82fd9497c454e204
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTHashtable.h"
8 #include "nsBaseHashtable.h"
9 #include "nsTHashMap.h"
10 #include "nsInterfaceHashtable.h"
11 #include "nsClassHashtable.h"
12 #include "nsRefCountedHashtable.h"
14 #include "nsCOMPtr.h"
15 #include "nsIMemoryReporter.h"
16 #include "nsISupports.h"
17 #include "nsCOMArray.h"
18 #include "mozilla/Attributes.h"
19 #include "mozilla/Unused.h"
21 #include "gtest/gtest.h"
23 #include <numeric>
25 using mozilla::MakeRefPtr;
26 using mozilla::MakeUnique;
27 using mozilla::UniquePtr;
29 namespace TestHashtables {
31 class TestUniChar // for nsClassHashtable
33 public:
34 explicit TestUniChar(uint32_t aWord) { mWord = aWord; }
36 ~TestUniChar() = default;
38 uint32_t GetChar() const { return mWord; }
40 private:
41 uint32_t mWord;
44 class TestUniCharDerived : public TestUniChar {
45 using TestUniChar::TestUniChar;
48 class TestUniCharRefCounted // for nsRefPtrHashtable
50 public:
51 explicit TestUniCharRefCounted(uint32_t aWord,
52 uint32_t aExpectedAddRefCnt = 0)
53 : mExpectedAddRefCnt(aExpectedAddRefCnt),
54 mAddRefCnt(0),
55 mRefCnt(0),
56 mWord(aWord) {}
58 uint32_t AddRef() {
59 mRefCnt++;
60 mAddRefCnt++;
61 return mRefCnt;
64 uint32_t Release() {
65 EXPECT_TRUE(mRefCnt > 0);
66 mRefCnt--;
67 if (mRefCnt == 0) {
68 delete this;
69 return 0;
71 return mRefCnt;
74 uint32_t GetChar() const { return mWord; }
76 private:
77 ~TestUniCharRefCounted() {
78 if (mExpectedAddRefCnt > 0) {
79 EXPECT_EQ(mAddRefCnt, mExpectedAddRefCnt);
83 uint32_t mExpectedAddRefCnt;
84 uint32_t mAddRefCnt;
85 uint32_t mRefCnt;
86 uint32_t mWord;
89 struct EntityNode {
90 const char* mStr; // never owns buffer
91 uint32_t mUnicode;
93 bool operator<(const EntityNode& aOther) const {
94 return mUnicode < aOther.mUnicode ||
95 (mUnicode == aOther.mUnicode && strcmp(mStr, aOther.mStr) < 0);
99 static const EntityNode gEntities[] = {
100 {"nbsp", 160}, {"iexcl", 161}, {"cent", 162}, {"pound", 163},
101 {"curren", 164}, {"yen", 165}, {"brvbar", 166}, {"sect", 167},
102 {"uml", 168}, {"copy", 169}, {"ordf", 170}, {"laquo", 171},
103 {"not", 172}, {"shy", 173}, {"reg", 174}, {"macr", 175}};
105 #define ENTITY_COUNT (unsigned(sizeof(gEntities) / sizeof(EntityNode)))
107 class EntityToUnicodeEntry : public PLDHashEntryHdr {
108 public:
109 typedef const char* KeyType;
110 typedef const char* KeyTypePointer;
112 explicit EntityToUnicodeEntry(const char* aKey) { mNode = nullptr; }
113 EntityToUnicodeEntry(const EntityToUnicodeEntry& aEntry) {
114 mNode = aEntry.mNode;
116 ~EntityToUnicodeEntry() = default;
118 bool KeyEquals(const char* aEntity) const {
119 return !strcmp(mNode->mStr, aEntity);
121 static const char* KeyToPointer(const char* aEntity) { return aEntity; }
122 static PLDHashNumber HashKey(const char* aEntity) {
123 return mozilla::HashString(aEntity);
125 enum { ALLOW_MEMMOVE = true };
127 const EntityNode* mNode;
130 static uint32_t nsTIterPrint(nsTHashtable<EntityToUnicodeEntry>& hash) {
131 uint32_t n = 0;
132 for (auto iter = hash.Iter(); !iter.Done(); iter.Next()) {
133 n++;
135 return n;
138 static uint32_t nsTIterPrintRemove(nsTHashtable<EntityToUnicodeEntry>& hash) {
139 uint32_t n = 0;
140 for (auto iter = hash.Iter(); !iter.Done(); iter.Next()) {
141 iter.Remove();
142 n++;
144 return n;
147 static void testTHashtable(nsTHashtable<EntityToUnicodeEntry>& hash,
148 uint32_t numEntries) {
149 uint32_t i;
150 for (i = 0; i < numEntries; ++i) {
151 EntityToUnicodeEntry* entry = hash.PutEntry(gEntities[i].mStr);
153 EXPECT_TRUE(entry);
155 EXPECT_FALSE(entry->mNode);
156 entry->mNode = &gEntities[i];
159 for (i = 0; i < numEntries; ++i) {
160 EntityToUnicodeEntry* entry = hash.GetEntry(gEntities[i].mStr);
162 EXPECT_TRUE(entry);
165 EntityToUnicodeEntry* entry = hash.GetEntry("xxxy");
167 EXPECT_FALSE(entry);
169 uint32_t count = nsTIterPrint(hash);
170 EXPECT_EQ(count, numEntries);
172 for (const auto& entry :
173 const_cast<const nsTHashtable<EntityToUnicodeEntry>&>(hash)) {
174 static_assert(std::is_same_v<decltype(entry), const EntityToUnicodeEntry&>);
176 for (auto& entry : hash) {
177 static_assert(std::is_same_v<decltype(entry), EntityToUnicodeEntry&>);
180 EXPECT_EQ(numEntries == ENTITY_COUNT ? 6 : 0,
181 std::count_if(hash.cbegin(), hash.cend(), [](const auto& entry) {
182 return entry.mNode->mUnicode >= 170;
183 }));
187 // all this nsIFoo stuff was copied wholesale from TestCOMPtr.cpp
190 #define NS_IFOO_IID \
192 0x6f7652e0, 0xee43, 0x11d1, { \
193 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 \
197 class IFoo final : public nsISupports {
198 public:
199 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
201 IFoo();
203 NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
204 NS_IMETHOD_(MozExternalRefCountType) Release() override;
205 NS_IMETHOD QueryInterface(const nsIID&, void**) override;
207 NS_IMETHOD SetString(const nsACString& /*in*/ aString);
208 NS_IMETHOD GetString(nsACString& /*out*/ aString);
210 static void print_totals();
212 private:
213 ~IFoo();
215 unsigned int refcount_;
217 static unsigned int total_constructions_;
218 static unsigned int total_destructions_;
219 nsCString mString;
222 NS_DEFINE_STATIC_IID_ACCESSOR(IFoo, NS_IFOO_IID)
224 unsigned int IFoo::total_constructions_;
225 unsigned int IFoo::total_destructions_;
227 void IFoo::print_totals() {}
229 IFoo::IFoo() : refcount_(0) { ++total_constructions_; }
231 IFoo::~IFoo() { ++total_destructions_; }
233 MozExternalRefCountType IFoo::AddRef() {
234 ++refcount_;
235 return refcount_;
238 MozExternalRefCountType IFoo::Release() {
239 int newcount = --refcount_;
240 if (newcount == 0) {
241 delete this;
244 return newcount;
247 nsresult IFoo::QueryInterface(const nsIID& aIID, void** aResult) {
248 nsISupports* rawPtr = 0;
249 nsresult status = NS_OK;
251 if (aIID.Equals(NS_GET_IID(IFoo)))
252 rawPtr = this;
253 else {
254 nsID iid_of_ISupports = NS_ISUPPORTS_IID;
255 if (aIID.Equals(iid_of_ISupports))
256 rawPtr = static_cast<nsISupports*>(this);
257 else
258 status = NS_ERROR_NO_INTERFACE;
261 NS_IF_ADDREF(rawPtr);
262 *aResult = rawPtr;
264 return status;
267 nsresult IFoo::SetString(const nsACString& aString) {
268 mString = aString;
269 return NS_OK;
272 nsresult IFoo::GetString(nsACString& aString) {
273 aString = mString;
274 return NS_OK;
277 static nsresult CreateIFoo(IFoo** result)
278 // a typical factory function (that calls AddRef)
280 auto* foop = new IFoo();
282 foop->AddRef();
283 *result = foop;
285 return NS_OK;
288 class DefaultConstructible {
289 public:
290 // Allow default construction.
291 DefaultConstructible() = default;
293 // Construct/assign from a ref counted char.
294 explicit DefaultConstructible(RefPtr<TestUniCharRefCounted> aChar)
295 : mChar(std::move(aChar)) {}
297 const RefPtr<TestUniCharRefCounted>& CharRef() const { return mChar; }
299 // DefaultConstructible can be copied and moved.
300 DefaultConstructible(const DefaultConstructible&) = default;
301 DefaultConstructible& operator=(const DefaultConstructible&) = default;
302 DefaultConstructible(DefaultConstructible&&) = default;
303 DefaultConstructible& operator=(DefaultConstructible&&) = default;
305 private:
306 RefPtr<TestUniCharRefCounted> mChar;
309 class MovingNonDefaultConstructible;
311 class NonDefaultConstructible {
312 public:
313 // Construct/assign from a ref counted char.
314 explicit NonDefaultConstructible(RefPtr<TestUniCharRefCounted> aChar)
315 : mChar(std::move(aChar)) {}
317 // Disallow default construction.
318 NonDefaultConstructible() = delete;
320 MOZ_IMPLICIT NonDefaultConstructible(MovingNonDefaultConstructible&& aOther);
322 const RefPtr<TestUniCharRefCounted>& CharRef() const { return mChar; }
324 // NonDefaultConstructible can be copied, but not trivially (efficiently)
325 // moved.
326 NonDefaultConstructible(const NonDefaultConstructible&) = default;
327 NonDefaultConstructible& operator=(const NonDefaultConstructible&) = default;
329 private:
330 RefPtr<TestUniCharRefCounted> mChar;
333 class MovingNonDefaultConstructible {
334 public:
335 // Construct/assign from a ref counted char.
336 explicit MovingNonDefaultConstructible(RefPtr<TestUniCharRefCounted> aChar)
337 : mChar(std::move(aChar)) {}
339 MovingNonDefaultConstructible() = delete;
341 MOZ_IMPLICIT MovingNonDefaultConstructible(
342 const NonDefaultConstructible& aSrc)
343 : mChar(aSrc.CharRef()) {}
345 RefPtr<TestUniCharRefCounted> unwrapChar() && { return std::move(mChar); }
347 // MovingNonDefaultConstructible can be moved, but not copied.
348 MovingNonDefaultConstructible(const MovingNonDefaultConstructible&) = delete;
349 MovingNonDefaultConstructible& operator=(
350 const MovingNonDefaultConstructible&) = delete;
351 MovingNonDefaultConstructible(MovingNonDefaultConstructible&&) = default;
352 MovingNonDefaultConstructible& operator=(MovingNonDefaultConstructible&&) =
353 default;
355 private:
356 RefPtr<TestUniCharRefCounted> mChar;
359 NonDefaultConstructible::NonDefaultConstructible(
360 MovingNonDefaultConstructible&& aOther)
361 : mChar(std::move(aOther).unwrapChar()) {}
363 struct DefaultConstructible_DefaultConstructible {
364 using DataType = DefaultConstructible;
365 using UserDataType = DefaultConstructible;
367 static constexpr uint32_t kExpectedAddRefCnt_Contains = 1;
368 static constexpr uint32_t kExpectedAddRefCnt_GetGeneration = 1;
369 static constexpr uint32_t kExpectedAddRefCnt_SizeOfExcludingThis = 1;
370 static constexpr uint32_t kExpectedAddRefCnt_SizeOfIncludingThis = 1;
371 static constexpr uint32_t kExpectedAddRefCnt_Count = 1;
372 static constexpr uint32_t kExpectedAddRefCnt_IsEmpty = 1;
373 static constexpr uint32_t kExpectedAddRefCnt_Get_OutputParam = 3;
374 static constexpr uint32_t kExpectedAddRefCnt_Get = 3;
375 static constexpr uint32_t kExpectedAddRefCnt_MaybeGet = 3;
376 static constexpr uint32_t kExpectedAddRefCnt_LookupOrInsert = 1;
377 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate = 1;
378 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Fallible = 1;
379 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue = 1;
380 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue_Fallible =
382 static constexpr uint32_t kExpectedAddRefCnt_Remove_OutputParam = 1;
383 static constexpr uint32_t kExpectedAddRefCnt_Remove = 1;
384 static constexpr uint32_t kExpectedAddRefCnt_Extract = 1;
385 static constexpr uint32_t kExpectedAddRefCnt_RemoveIf = 1;
386 static constexpr uint32_t kExpectedAddRefCnt_Lookup = 1;
387 static constexpr uint32_t kExpectedAddRefCnt_Lookup_Remove = 1;
388 static constexpr uint32_t kExpectedAddRefCnt_LookupForAdd = 1;
389 static constexpr uint32_t kExpectedAddRefCnt_LookupForAdd_OrInsert = 1;
390 static constexpr uint32_t kExpectedAddRefCnt_LookupForAdd_OrRemove = 1;
391 static constexpr uint32_t kExpectedAddRefCnt_Iter = 1;
392 static constexpr uint32_t kExpectedAddRefCnt_ConstIter = 1;
393 static constexpr uint32_t kExpectedAddRefCnt_begin_end = 1;
394 static constexpr uint32_t kExpectedAddRefCnt_cbegin_cend = 1;
395 static constexpr uint32_t kExpectedAddRefCnt_Clear = 1;
396 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfExcludingThis = 1;
397 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfIncludingThis = 1;
398 static constexpr uint32_t kExpectedAddRefCnt_SwapElements = 1;
399 static constexpr uint32_t kExpectedAddRefCnt_MarkImmutable = 1;
402 struct NonDefaultConstructible_NonDefaultConstructible {
403 using DataType = NonDefaultConstructible;
404 using UserDataType = NonDefaultConstructible;
406 static constexpr uint32_t kExpectedAddRefCnt_Contains = 2;
407 static constexpr uint32_t kExpectedAddRefCnt_GetGeneration = 2;
408 static constexpr uint32_t kExpectedAddRefCnt_SizeOfExcludingThis = 3;
409 static constexpr uint32_t kExpectedAddRefCnt_SizeOfIncludingThis = 3;
410 static constexpr uint32_t kExpectedAddRefCnt_Count = 2;
411 static constexpr uint32_t kExpectedAddRefCnt_IsEmpty = 2;
412 static constexpr uint32_t kExpectedAddRefCnt_Get_OutputParam = 5;
413 static constexpr uint32_t kExpectedAddRefCnt_MaybeGet = 5;
414 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate = 2;
415 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Fallible = 2;
416 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue = 2;
417 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue_Fallible =
419 static constexpr uint32_t kExpectedAddRefCnt_Remove = 2;
420 static constexpr uint32_t kExpectedAddRefCnt_Extract = 3;
421 static constexpr uint32_t kExpectedAddRefCnt_RemoveIf = 2;
422 static constexpr uint32_t kExpectedAddRefCnt_Lookup = 2;
423 static constexpr uint32_t kExpectedAddRefCnt_Lookup_Remove = 2;
424 static constexpr uint32_t kExpectedAddRefCnt_Iter = 2;
425 static constexpr uint32_t kExpectedAddRefCnt_ConstIter = 2;
426 static constexpr uint32_t kExpectedAddRefCnt_begin_end = 2;
427 static constexpr uint32_t kExpectedAddRefCnt_cbegin_cend = 2;
428 static constexpr uint32_t kExpectedAddRefCnt_Clear = 2;
429 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfExcludingThis = 2;
430 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfIncludingThis = 2;
431 static constexpr uint32_t kExpectedAddRefCnt_SwapElements = 2;
432 static constexpr uint32_t kExpectedAddRefCnt_MarkImmutable = 2;
435 struct NonDefaultConstructible_MovingNonDefaultConstructible {
436 using DataType = NonDefaultConstructible;
437 using UserDataType = MovingNonDefaultConstructible;
439 static constexpr uint32_t kExpectedAddRefCnt_Contains = 1;
440 static constexpr uint32_t kExpectedAddRefCnt_GetGeneration = 1;
441 static constexpr uint32_t kExpectedAddRefCnt_SizeOfExcludingThis = 1;
442 static constexpr uint32_t kExpectedAddRefCnt_SizeOfIncludingThis = 1;
443 static constexpr uint32_t kExpectedAddRefCnt_Count = 1;
444 static constexpr uint32_t kExpectedAddRefCnt_IsEmpty = 1;
445 static constexpr uint32_t kExpectedAddRefCnt_Get_OutputParam = 2;
446 static constexpr uint32_t kExpectedAddRefCnt_MaybeGet = 2;
447 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate = 1;
448 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Fallible = 1;
449 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue = 1;
450 static constexpr uint32_t kExpectedAddRefCnt_InsertOrUpdate_Rvalue_Fallible =
452 static constexpr uint32_t kExpectedAddRefCnt_Remove = 1;
453 static constexpr uint32_t kExpectedAddRefCnt_Extract = 2;
454 static constexpr uint32_t kExpectedAddRefCnt_RemoveIf = 1;
455 static constexpr uint32_t kExpectedAddRefCnt_Lookup = 1;
456 static constexpr uint32_t kExpectedAddRefCnt_Lookup_Remove = 1;
457 static constexpr uint32_t kExpectedAddRefCnt_Iter = 1;
458 static constexpr uint32_t kExpectedAddRefCnt_ConstIter = 1;
459 static constexpr uint32_t kExpectedAddRefCnt_begin_end = 1;
460 static constexpr uint32_t kExpectedAddRefCnt_cbegin_cend = 1;
461 static constexpr uint32_t kExpectedAddRefCnt_Clear = 1;
462 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfExcludingThis = 1;
463 static constexpr uint32_t kExpectedAddRefCnt_ShallowSizeOfIncludingThis = 1;
464 static constexpr uint32_t kExpectedAddRefCnt_SwapElements = 1;
465 static constexpr uint32_t kExpectedAddRefCnt_MarkImmutable = 1;
468 template <bool flag = false>
469 void UnsupportedType() {
470 static_assert(flag, "Unsupported type!");
473 class TypeNames {
474 public:
475 template <typename T>
476 static std::string GetName(int) {
477 if constexpr (std::is_same<T,
478 DefaultConstructible_DefaultConstructible>()) {
479 return "DefaultConstructible_DefaultConstructible";
480 } else if constexpr (
481 std::is_same<T, NonDefaultConstructible_NonDefaultConstructible>()) {
482 return "NonDefaultConstructible_NonDefaultConstructible";
483 } else if constexpr (
484 std::is_same<T,
485 NonDefaultConstructible_MovingNonDefaultConstructible>()) {
486 return "NonDefaultConstructible_MovingNonDefaultConstructible";
487 } else {
488 UnsupportedType();
493 template <typename TypeParam>
494 auto MakeEmptyBaseHashtable() {
495 nsBaseHashtable<nsUint64HashKey, typename TypeParam::DataType,
496 typename TypeParam::UserDataType>
497 table;
499 return table;
502 template <typename TypeParam>
503 auto MakeBaseHashtable(const uint32_t aExpectedAddRefCnt) {
504 auto table = MakeEmptyBaseHashtable<TypeParam>();
506 auto myChar = MakeRefPtr<TestUniCharRefCounted>(42, aExpectedAddRefCnt);
508 table.InsertOrUpdate(1, typename TypeParam::UserDataType(std::move(myChar)));
510 return table;
513 template <typename TypeParam>
514 typename TypeParam::DataType GetDataFrom(
515 typename TypeParam::UserDataType& aUserData) {
516 if constexpr (std::is_same_v<TypeParam,
517 DefaultConstructible_DefaultConstructible> ||
518 std::is_same_v<
519 TypeParam,
520 NonDefaultConstructible_NonDefaultConstructible>) {
521 return aUserData;
522 } else if constexpr (
523 std::is_same_v<TypeParam,
524 NonDefaultConstructible_MovingNonDefaultConstructible>) {
525 return std::move(aUserData);
526 } else {
527 UnsupportedType();
531 template <typename TypeParam>
532 typename TypeParam::DataType GetDataFrom(
533 mozilla::Maybe<typename TypeParam::UserDataType>& aMaybeUserData) {
534 return GetDataFrom<TypeParam>(*aMaybeUserData);
537 } // namespace TestHashtables
539 using namespace TestHashtables;
541 TEST(Hashtable, THashtable)
543 // check an nsTHashtable
544 nsTHashtable<EntityToUnicodeEntry> EntityToUnicode(ENTITY_COUNT);
546 testTHashtable(EntityToUnicode, 5);
548 uint32_t count = nsTIterPrintRemove(EntityToUnicode);
549 ASSERT_EQ(count, uint32_t(5));
551 count = nsTIterPrint(EntityToUnicode);
552 ASSERT_EQ(count, uint32_t(0));
554 testTHashtable(EntityToUnicode, ENTITY_COUNT);
556 EntityToUnicode.Clear();
558 count = nsTIterPrint(EntityToUnicode);
559 ASSERT_EQ(count, uint32_t(0));
562 TEST(Hashtable, PtrHashtable)
564 nsTHashtable<nsPtrHashKey<int>> hash;
566 for (const auto& entry :
567 const_cast<const nsTHashtable<nsPtrHashKey<int>>&>(hash)) {
568 static_assert(std::is_same_v<decltype(entry), const nsPtrHashKey<int>&>);
570 for (auto& entry : hash) {
571 static_assert(std::is_same_v<decltype(entry), nsPtrHashKey<int>&>);
575 TEST(Hashtable, Move)
577 const void* kPtr = reinterpret_cast<void*>(static_cast<uintptr_t>(0xbadc0de));
579 nsTHashtable<nsPtrHashKey<const void>> table;
580 table.PutEntry(kPtr);
582 nsTHashtable<nsPtrHashKey<const void>> moved = std::move(table);
583 ASSERT_EQ(table.Count(), 0u);
584 ASSERT_EQ(moved.Count(), 1u);
586 EXPECT_TRUE(moved.Contains(kPtr));
587 EXPECT_FALSE(table.Contains(kPtr));
590 TEST(Hashtable, Keys)
592 static constexpr uint64_t count = 10;
594 nsTHashtable<nsUint64HashKey> table;
595 for (uint64_t i = 0; i < count; i++) {
596 table.PutEntry(i);
599 nsTArray<uint64_t> keys;
600 for (const uint64_t& key : table.Keys()) {
601 keys.AppendElement(key);
603 keys.Sort();
605 EXPECT_EQ((nsTArray<uint64_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), keys);
608 template <typename TypeParam>
609 class BaseHashtableTest : public ::testing::Test {};
611 TYPED_TEST_SUITE_P(BaseHashtableTest);
613 TYPED_TEST_P(BaseHashtableTest, Contains) {
614 auto table =
615 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Contains);
617 auto res = table.Contains(1);
618 EXPECT_TRUE(res);
621 TYPED_TEST_P(BaseHashtableTest, GetGeneration) {
622 auto table =
623 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_GetGeneration);
625 auto res = table.GetGeneration();
626 EXPECT_GT(res, 0u);
629 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
631 TYPED_TEST_P(BaseHashtableTest, SizeOfExcludingThis) {
632 // This doesn't compile at the moment, since nsBaseHashtableET lacks
633 // SizeOfExcludingThis implementation. Bug 1689214.
634 #if 0
635 auto table = MakeBaseHashtable<TypeParam>(
636 TypeParam::kExpectedAddRefCnt_SizeOfExcludingThis);
638 auto res = table.SizeOfExcludingThis(MallocSizeOf);
639 EXPECT_GT(res, 0u);
640 #endif
643 TYPED_TEST_P(BaseHashtableTest, SizeOfIncludingThis) {
644 // This doesn't compile at the moment, since nsBaseHashtableET lacks
645 // SizeOfIncludingThis implementation. Bug 1689214.
646 #if 0
647 auto table = MakeBaseHashtable<TypeParam>(
648 TypeParam::kExpectedAddRefCnt_SizeOfIncludingThis);
650 auto res = table.SizeOfIncludingThis(MallocSizeOf);
651 EXPECT_GT(res, 0u);
652 #endif
655 TYPED_TEST_P(BaseHashtableTest, Count) {
656 auto table =
657 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Count);
659 auto res = table.Count();
660 EXPECT_EQ(res, 1u);
663 TYPED_TEST_P(BaseHashtableTest, IsEmpty) {
664 auto table =
665 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_IsEmpty);
667 auto res = table.IsEmpty();
668 EXPECT_EQ(res, false);
671 TYPED_TEST_P(BaseHashtableTest, Get_OutputParam) {
672 auto table = MakeBaseHashtable<TypeParam>(
673 TypeParam::kExpectedAddRefCnt_Get_OutputParam);
675 typename TypeParam::UserDataType userData(nullptr);
676 auto res = table.Get(1, &userData);
677 EXPECT_TRUE(res);
679 auto data = GetDataFrom<TypeParam>(userData);
680 EXPECT_EQ(data.CharRef()->GetChar(), 42u);
683 TYPED_TEST_P(BaseHashtableTest, Get) {
684 // The Get overload can't support non-default-constructible UserDataType.
685 if constexpr (std::is_default_constructible_v<
686 typename TypeParam::UserDataType>) {
687 auto table =
688 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Get);
690 auto userData = table.Get(1);
692 auto data = GetDataFrom<TypeParam>(userData);
693 EXPECT_EQ(data.CharRef()->GetChar(), 42u);
697 TYPED_TEST_P(BaseHashtableTest, MaybeGet) {
698 auto table =
699 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_MaybeGet);
701 auto maybeUserData = table.MaybeGet(1);
702 EXPECT_TRUE(maybeUserData);
704 auto data = GetDataFrom<TypeParam>(maybeUserData);
705 EXPECT_EQ(data.CharRef()->GetChar(), 42u);
708 TYPED_TEST_P(BaseHashtableTest, LookupOrInsert_Default) {
709 if constexpr (std::is_default_constructible_v<typename TypeParam::DataType>) {
710 auto table = MakeEmptyBaseHashtable<TypeParam>();
712 typename TypeParam::DataType& data = table.LookupOrInsert(1);
713 EXPECT_EQ(data.CharRef(), nullptr);
715 data = typename TypeParam::DataType(MakeRefPtr<TestUniCharRefCounted>(
716 42, TypeParam::kExpectedAddRefCnt_LookupOrInsert));
720 TYPED_TEST_P(BaseHashtableTest, LookupOrInsert_NonDefault) {
721 auto table = MakeEmptyBaseHashtable<TypeParam>();
723 typename TypeParam::DataType& data = table.LookupOrInsert(
724 1, typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42)});
725 EXPECT_NE(data.CharRef(), nullptr);
728 TYPED_TEST_P(BaseHashtableTest, LookupOrInsert_NonDefault_AlreadyPresent) {
729 auto table = MakeEmptyBaseHashtable<TypeParam>();
731 typename TypeParam::DataType& data1 = table.LookupOrInsert(
732 1, typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42)});
733 TestUniCharRefCounted* const address = data1.CharRef();
734 typename TypeParam::DataType& data2 = table.LookupOrInsert(
736 typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42, 1)});
737 EXPECT_EQ(&data1, &data2);
738 EXPECT_EQ(address, data2.CharRef());
741 TYPED_TEST_P(BaseHashtableTest, LookupOrInsertWith) {
742 auto table = MakeEmptyBaseHashtable<TypeParam>();
744 typename TypeParam::DataType& data = table.LookupOrInsertWith(1, [] {
745 return typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42)};
747 EXPECT_NE(data.CharRef(), nullptr);
750 TYPED_TEST_P(BaseHashtableTest, LookupOrInsertWith_AlreadyPresent) {
751 auto table = MakeEmptyBaseHashtable<TypeParam>();
753 table.LookupOrInsertWith(1, [] {
754 return typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42)};
756 table.LookupOrInsertWith(1, [] {
757 ADD_FAILURE();
758 return typename TypeParam::DataType{MakeRefPtr<TestUniCharRefCounted>(42)};
762 TYPED_TEST_P(BaseHashtableTest, InsertOrUpdate) {
763 auto table = MakeEmptyBaseHashtable<TypeParam>();
765 auto myChar = MakeRefPtr<TestUniCharRefCounted>(
766 42, TypeParam::kExpectedAddRefCnt_InsertOrUpdate);
768 table.InsertOrUpdate(1, typename TypeParam::UserDataType(std::move(myChar)));
771 TYPED_TEST_P(BaseHashtableTest, InsertOrUpdate_Fallible) {
772 auto table = MakeEmptyBaseHashtable<TypeParam>();
774 auto myChar = MakeRefPtr<TestUniCharRefCounted>(
775 42, TypeParam::kExpectedAddRefCnt_InsertOrUpdate_Fallible);
777 auto res = table.InsertOrUpdate(
778 1, typename TypeParam::UserDataType(std::move(myChar)),
779 mozilla::fallible);
780 EXPECT_TRUE(res);
783 TYPED_TEST_P(BaseHashtableTest, InsertOrUpdate_Rvalue) {
784 auto table = MakeEmptyBaseHashtable<TypeParam>();
786 auto myChar = MakeRefPtr<TestUniCharRefCounted>(
787 42, TypeParam::kExpectedAddRefCnt_InsertOrUpdate_Rvalue);
789 table.InsertOrUpdate(
790 1, std::move(typename TypeParam::UserDataType(std::move(myChar))));
793 TYPED_TEST_P(BaseHashtableTest, InsertOrUpdate_Rvalue_Fallible) {
794 auto table = MakeEmptyBaseHashtable<TypeParam>();
796 auto myChar = MakeRefPtr<TestUniCharRefCounted>(
797 42, TypeParam::kExpectedAddRefCnt_InsertOrUpdate_Rvalue_Fallible);
799 auto res = table.InsertOrUpdate(
800 1, std::move(typename TypeParam::UserDataType(std::move(myChar))),
801 mozilla::fallible);
802 EXPECT_TRUE(res);
805 TYPED_TEST_P(BaseHashtableTest, Remove_OutputParam) {
806 // The Remove overload can't support non-default-constructible DataType.
807 if constexpr (std::is_default_constructible_v<typename TypeParam::DataType>) {
808 auto table = MakeBaseHashtable<TypeParam>(
809 TypeParam::kExpectedAddRefCnt_Remove_OutputParam);
811 typename TypeParam::DataType data;
812 auto res = table.Remove(1, &data);
813 EXPECT_TRUE(res);
814 EXPECT_EQ(data.CharRef()->GetChar(), 42u);
818 TYPED_TEST_P(BaseHashtableTest, Remove) {
819 auto table =
820 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Remove);
822 auto res = table.Remove(1);
823 EXPECT_TRUE(res);
826 TYPED_TEST_P(BaseHashtableTest, Extract) {
827 auto table =
828 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Extract);
830 auto maybeData = table.Extract(1);
831 EXPECT_TRUE(maybeData);
832 EXPECT_EQ(maybeData->CharRef()->GetChar(), 42u);
835 TYPED_TEST_P(BaseHashtableTest, RemoveIf) {
836 auto table =
837 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_RemoveIf);
839 table.RemoveIf([](const auto&) { return true; });
842 TYPED_TEST_P(BaseHashtableTest, Lookup) {
843 auto table =
844 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Lookup);
846 auto res = table.Lookup(1);
847 EXPECT_TRUE(res);
848 EXPECT_EQ(res.Data().CharRef()->GetChar(), 42u);
851 TYPED_TEST_P(BaseHashtableTest, Lookup_Remove) {
852 auto table =
853 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Lookup_Remove);
855 auto res = table.Lookup(1);
856 EXPECT_TRUE(res);
857 EXPECT_EQ(res.Data().CharRef()->GetChar(), 42u);
859 res.Remove();
862 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NoOp) {
863 auto table = MakeEmptyBaseHashtable<TypeParam>();
865 table.WithEntryHandle(1, [](auto&&) {});
867 EXPECT_FALSE(table.Contains(1));
870 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NotFound_OrInsert) {
871 auto table = MakeEmptyBaseHashtable<TypeParam>();
873 table.WithEntryHandle(1, [](auto&& entry) {
874 entry.OrInsert(typename TypeParam::UserDataType(
875 MakeRefPtr<TestUniCharRefCounted>(42)));
878 EXPECT_TRUE(table.Contains(1));
881 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NotFound_OrInsertFrom) {
882 auto table = MakeEmptyBaseHashtable<TypeParam>();
884 table.WithEntryHandle(1, [](auto&& entry) {
885 entry.OrInsertWith([] {
886 return typename TypeParam::UserDataType(
887 MakeRefPtr<TestUniCharRefCounted>(42));
891 EXPECT_TRUE(table.Contains(1));
894 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NotFound_OrInsertFrom_Exists) {
895 auto table = MakeEmptyBaseHashtable<TypeParam>();
897 table.WithEntryHandle(1, [](auto&& entry) {
898 entry.OrInsertWith([] {
899 return typename TypeParam::UserDataType(
900 MakeRefPtr<TestUniCharRefCounted>(42));
903 table.WithEntryHandle(1, [](auto&& entry) {
904 entry.OrInsertWith([]() -> typename TypeParam::UserDataType {
905 ADD_FAILURE();
906 return typename TypeParam::UserDataType(
907 MakeRefPtr<TestUniCharRefCounted>(42));
911 EXPECT_TRUE(table.Contains(1));
914 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NotFound_OrRemove) {
915 auto table = MakeEmptyBaseHashtable<TypeParam>();
917 table.WithEntryHandle(1, [](auto&& entry) { entry.OrRemove(); });
919 EXPECT_FALSE(table.Contains(1));
922 TYPED_TEST_P(BaseHashtableTest, WithEntryHandle_NotFound_OrRemove_Exists) {
923 auto table = MakeEmptyBaseHashtable<TypeParam>();
925 table.WithEntryHandle(1, [](auto&& entry) {
926 entry.OrInsertWith([] {
927 return typename TypeParam::UserDataType(
928 MakeRefPtr<TestUniCharRefCounted>(42));
931 table.WithEntryHandle(1, [](auto&& entry) { entry.OrRemove(); });
933 EXPECT_FALSE(table.Contains(1));
936 TYPED_TEST_P(BaseHashtableTest, Iter) {
937 auto table = MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Iter);
939 for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
940 EXPECT_EQ(iter.Data().CharRef()->GetChar(), 42u);
944 TYPED_TEST_P(BaseHashtableTest, ConstIter) {
945 auto table =
946 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_ConstIter);
948 for (auto iter = table.ConstIter(); !iter.Done(); iter.Next()) {
949 EXPECT_EQ(iter.Data().CharRef()->GetChar(), 42u);
953 TYPED_TEST_P(BaseHashtableTest, begin_end) {
954 auto table =
955 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_begin_end);
957 auto res = std::count_if(table.begin(), table.end(), [](const auto& entry) {
958 return entry.GetData().CharRef()->GetChar() == 42;
960 EXPECT_EQ(res, 1);
963 TYPED_TEST_P(BaseHashtableTest, cbegin_cend) {
964 auto table =
965 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_cbegin_cend);
967 auto res = std::count_if(table.cbegin(), table.cend(), [](const auto& entry) {
968 return entry.GetData().CharRef()->GetChar() == 42;
970 EXPECT_EQ(res, 1);
973 TYPED_TEST_P(BaseHashtableTest, Clear) {
974 auto table =
975 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_Clear);
977 table.Clear();
980 TYPED_TEST_P(BaseHashtableTest, ShallowSizeOfExcludingThis) {
981 auto table = MakeBaseHashtable<TypeParam>(
982 TypeParam::kExpectedAddRefCnt_ShallowSizeOfExcludingThis);
984 auto res = table.ShallowSizeOfExcludingThis(MallocSizeOf);
985 EXPECT_GT(res, 0u);
988 TYPED_TEST_P(BaseHashtableTest, ShallowSizeOfIncludingThis) {
989 // Make this work with ASAN builds, bug 1689549.
990 #if !defined(MOZ_ASAN)
991 auto table = MakeBaseHashtable<TypeParam>(
992 TypeParam::kExpectedAddRefCnt_ShallowSizeOfIncludingThis);
994 auto res = table.ShallowSizeOfIncludingThis(MallocSizeOf);
995 EXPECT_GT(res, 0u);
996 #endif
999 TYPED_TEST_P(BaseHashtableTest, SwapElements) {
1000 auto table =
1001 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_SwapElements);
1003 auto table2 = MakeEmptyBaseHashtable<TypeParam>();
1005 table.SwapElements(table2);
1008 TYPED_TEST_P(BaseHashtableTest, MarkImmutable) {
1009 auto table =
1010 MakeBaseHashtable<TypeParam>(TypeParam::kExpectedAddRefCnt_MarkImmutable);
1012 table.MarkImmutable();
1015 REGISTER_TYPED_TEST_SUITE_P(
1016 BaseHashtableTest, Contains, GetGeneration, SizeOfExcludingThis,
1017 SizeOfIncludingThis, Count, IsEmpty, Get_OutputParam, Get, MaybeGet,
1018 LookupOrInsert_Default, LookupOrInsert_NonDefault,
1019 LookupOrInsert_NonDefault_AlreadyPresent, LookupOrInsertWith,
1020 LookupOrInsertWith_AlreadyPresent, InsertOrUpdate, InsertOrUpdate_Fallible,
1021 InsertOrUpdate_Rvalue, InsertOrUpdate_Rvalue_Fallible, Remove_OutputParam,
1022 Remove, Extract, RemoveIf, Lookup, Lookup_Remove, WithEntryHandle_NoOp,
1023 WithEntryHandle_NotFound_OrInsert, WithEntryHandle_NotFound_OrInsertFrom,
1024 WithEntryHandle_NotFound_OrInsertFrom_Exists,
1025 WithEntryHandle_NotFound_OrRemove, WithEntryHandle_NotFound_OrRemove_Exists,
1026 Iter, ConstIter, begin_end, cbegin_cend, Clear, ShallowSizeOfExcludingThis,
1027 ShallowSizeOfIncludingThis, SwapElements, MarkImmutable);
1029 using BaseHashtableTestTypes =
1030 ::testing::Types<DefaultConstructible_DefaultConstructible,
1031 NonDefaultConstructible_NonDefaultConstructible,
1032 NonDefaultConstructible_MovingNonDefaultConstructible>;
1034 INSTANTIATE_TYPED_TEST_SUITE_P(Hashtables, BaseHashtableTest,
1035 BaseHashtableTestTypes, TypeNames);
1037 TEST(Hashtables, DataHashtable)
1039 // check a data-hashtable
1040 nsTHashMap<nsUint32HashKey, const char*> UniToEntity(ENTITY_COUNT);
1042 for (auto& entity : gEntities) {
1043 UniToEntity.InsertOrUpdate(entity.mUnicode, entity.mStr);
1046 const char* str;
1048 for (auto& entity : gEntities) {
1049 ASSERT_TRUE(UniToEntity.Get(entity.mUnicode, &str));
1052 ASSERT_FALSE(UniToEntity.Get(99446, &str));
1054 uint32_t count = 0;
1055 for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
1056 count++;
1058 ASSERT_EQ(count, ENTITY_COUNT);
1060 UniToEntity.Clear();
1062 count = 0;
1063 for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
1064 printf(" enumerated %u = \"%s\"\n", iter.Key(), iter.Data());
1065 count++;
1067 ASSERT_EQ(count, uint32_t(0));
1070 TEST(Hashtables, DataHashtable_STLIterators)
1072 using mozilla::Unused;
1074 nsTHashMap<nsUint32HashKey, const char*> UniToEntity(ENTITY_COUNT);
1076 for (auto& entity : gEntities) {
1077 UniToEntity.InsertOrUpdate(entity.mUnicode, entity.mStr);
1080 // operators, including conversion from iterator to const_iterator
1081 nsTHashMap<nsUint32HashKey, const char*>::const_iterator ci =
1082 UniToEntity.begin();
1083 ++ci;
1084 ASSERT_EQ(1, std::distance(UniToEntity.cbegin(), ci++));
1085 ASSERT_EQ(2, std::distance(UniToEntity.cbegin(), ci));
1086 ASSERT_TRUE(ci == ci);
1087 auto otherCi = ci;
1088 ++otherCi;
1089 ++ci;
1090 ASSERT_TRUE(&*ci == &*otherCi);
1092 // STL algorithms (just to check that the iterator sufficiently conforms
1093 // with the actual syntactical requirements of those algorithms).
1094 std::for_each(UniToEntity.cbegin(), UniToEntity.cend(),
1095 [](const auto& entry) {});
1096 Unused << std::find_if(
1097 UniToEntity.cbegin(), UniToEntity.cend(),
1098 [](const auto& entry) { return entry.GetKey() == 42; });
1099 Unused << std::accumulate(
1100 UniToEntity.cbegin(), UniToEntity.cend(), 0u,
1101 [](size_t sum, const auto& entry) { return sum + entry.GetKey(); });
1102 Unused << std::any_of(UniToEntity.cbegin(), UniToEntity.cend(),
1103 [](const auto& entry) { return entry.GetKey() == 42; });
1104 Unused << std::max_element(UniToEntity.cbegin(), UniToEntity.cend(),
1105 [](const auto& lhs, const auto& rhs) {
1106 return lhs.GetKey() > rhs.GetKey();
1109 // const range-based for
1111 std::set<EntityNode> entities(gEntities, gEntities + ENTITY_COUNT);
1112 for (const auto& entity :
1113 const_cast<const nsTHashMap<nsUint32HashKey, const char*>&>(
1114 UniToEntity)) {
1115 ASSERT_EQ(1u,
1116 entities.erase(EntityNode{entity.GetData(), entity.GetKey()}));
1118 ASSERT_TRUE(entities.empty());
1121 // non-const range-based for
1123 std::set<EntityNode> entities(gEntities, gEntities + ENTITY_COUNT);
1124 for (auto& entity : UniToEntity) {
1125 ASSERT_EQ(1u,
1126 entities.erase(EntityNode{entity.GetData(), entity.GetKey()}));
1128 entity.SetData(nullptr);
1129 ASSERT_EQ(nullptr, entity.GetData());
1131 ASSERT_TRUE(entities.empty());
1135 TEST(Hashtables, DataHashtable_RemoveIf)
1137 // check a data-hashtable
1138 nsTHashMap<nsUint32HashKey, const char*> UniToEntity(ENTITY_COUNT);
1140 for (auto& entity : gEntities) {
1141 UniToEntity.InsertOrUpdate(entity.mUnicode, entity.mStr);
1144 UniToEntity.RemoveIf([](const auto& iter) { return iter.Key() >= 170; });
1146 ASSERT_EQ(10u, UniToEntity.Count());
1149 TEST(Hashtables, ClassHashtable)
1151 // check a class-hashtable
1152 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1154 for (auto& entity : gEntities) {
1155 // Insert a sub-class of TestUniChar to test if this is accepted by
1156 // InsertOrUpdate.
1157 EntToUniClass.InsertOrUpdate(
1158 nsDependentCString(entity.mStr),
1159 mozilla::MakeUnique<TestUniCharDerived>(entity.mUnicode));
1162 TestUniChar* myChar;
1164 for (auto& entity : gEntities) {
1165 ASSERT_TRUE(EntToUniClass.Get(nsDependentCString(entity.mStr), &myChar));
1168 ASSERT_FALSE(EntToUniClass.Get("xxxx"_ns, &myChar));
1170 uint32_t count = 0;
1171 for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
1172 count++;
1174 ASSERT_EQ(count, ENTITY_COUNT);
1176 EntToUniClass.Clear();
1178 count = 0;
1179 for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
1180 count++;
1182 ASSERT_EQ(count, uint32_t(0));
1185 TEST(Hashtables, ClassHashtable_RangeBasedFor)
1187 // check a class-hashtable
1188 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1190 for (auto& entity : gEntities) {
1191 EntToUniClass.InsertOrUpdate(nsDependentCString(entity.mStr),
1192 MakeUnique<TestUniChar>(entity.mUnicode));
1195 // const range-based for
1197 std::set<EntityNode> entities(gEntities, gEntities + ENTITY_COUNT);
1198 for (const auto& entity :
1199 const_cast<const nsClassHashtable<nsCStringHashKey, TestUniChar>&>(
1200 EntToUniClass)) {
1201 const char* str;
1202 entity.GetKey().GetData(&str);
1203 ASSERT_EQ(1u,
1204 entities.erase(EntityNode{str, entity.GetData()->GetChar()}));
1206 ASSERT_TRUE(entities.empty());
1209 // non-const range-based for
1211 std::set<EntityNode> entities(gEntities, gEntities + ENTITY_COUNT);
1212 for (auto& entity : EntToUniClass) {
1213 const char* str;
1214 entity.GetKey().GetData(&str);
1215 ASSERT_EQ(1u,
1216 entities.erase(EntityNode{str, entity.GetData()->GetChar()}));
1218 entity.SetData(UniquePtr<TestUniChar>{});
1219 ASSERT_EQ(nullptr, entity.GetData());
1221 ASSERT_TRUE(entities.empty());
1225 TEST(Hashtables, DataHashtableWithInterfaceKey)
1227 // check a data-hashtable with an interface key
1228 nsTHashMap<nsISupportsHashKey, uint32_t> EntToUniClass2(ENTITY_COUNT);
1230 nsCOMArray<IFoo> fooArray;
1232 for (uint32_t i = 0; i < ENTITY_COUNT; ++i) {
1233 nsCOMPtr<IFoo> foo;
1234 CreateIFoo(getter_AddRefs(foo));
1235 foo->SetString(nsDependentCString(gEntities[i].mStr));
1237 fooArray.InsertObjectAt(foo, i);
1239 EntToUniClass2.InsertOrUpdate(foo, gEntities[i].mUnicode);
1242 uint32_t myChar2;
1244 for (uint32_t i = 0; i < ENTITY_COUNT; ++i) {
1245 ASSERT_TRUE(EntToUniClass2.Get(fooArray[i], &myChar2));
1248 ASSERT_FALSE(EntToUniClass2.Get((nsISupports*)0x55443316, &myChar2));
1250 uint32_t count = 0;
1251 for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
1252 nsAutoCString s;
1253 nsCOMPtr<IFoo> foo = do_QueryInterface(iter.Key());
1254 foo->GetString(s);
1255 count++;
1257 ASSERT_EQ(count, ENTITY_COUNT);
1259 EntToUniClass2.Clear();
1261 count = 0;
1262 for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
1263 nsAutoCString s;
1264 nsCOMPtr<IFoo> foo = do_QueryInterface(iter.Key());
1265 foo->GetString(s);
1266 count++;
1268 ASSERT_EQ(count, uint32_t(0));
1271 TEST(Hashtables, InterfaceHashtable)
1273 // check an interface-hashtable with an uint32_t key
1274 nsInterfaceHashtable<nsUint32HashKey, IFoo> UniToEntClass2(ENTITY_COUNT);
1276 for (auto& entity : gEntities) {
1277 nsCOMPtr<IFoo> foo;
1278 CreateIFoo(getter_AddRefs(foo));
1279 foo->SetString(nsDependentCString(entity.mStr));
1281 UniToEntClass2.InsertOrUpdate(entity.mUnicode, foo);
1284 for (auto& entity : gEntities) {
1285 nsCOMPtr<IFoo> myEnt;
1286 ASSERT_TRUE(UniToEntClass2.Get(entity.mUnicode, getter_AddRefs(myEnt)));
1288 nsAutoCString myEntStr;
1289 myEnt->GetString(myEntStr);
1292 nsCOMPtr<IFoo> myEnt;
1293 ASSERT_FALSE(UniToEntClass2.Get(9462, getter_AddRefs(myEnt)));
1295 uint32_t count = 0;
1296 for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
1297 nsAutoCString s;
1298 iter.UserData()->GetString(s);
1299 count++;
1301 ASSERT_EQ(count, ENTITY_COUNT);
1303 UniToEntClass2.Clear();
1305 count = 0;
1306 for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
1307 nsAutoCString s;
1308 iter.Data()->GetString(s);
1309 count++;
1311 ASSERT_EQ(count, uint32_t(0));
1314 TEST(Hashtables, DataHashtable_WithEntryHandle)
1316 // check WithEntryHandle/OrInsertWith
1317 nsTHashMap<nsUint32HashKey, const char*> UniToEntity(ENTITY_COUNT);
1319 for (auto& entity : gEntities) {
1320 UniToEntity.WithEntryHandle(entity.mUnicode, [&entity](auto&& entry) {
1321 EXPECT_FALSE(entry);
1322 const char* const val =
1323 entry.OrInsertWith([&entity]() { return entity.mStr; });
1324 EXPECT_TRUE(entry);
1325 EXPECT_TRUE(val == entity.mStr);
1326 EXPECT_TRUE(entry.Data() == entity.mStr);
1330 for (auto& entity : gEntities) {
1331 UniToEntity.WithEntryHandle(entity.mUnicode,
1332 [](auto&& entry) { EXPECT_TRUE(entry); });
1335 // 0 should not be found
1336 size_t count = UniToEntity.Count();
1337 UniToEntity.Lookup(0U).Remove();
1338 ASSERT_TRUE(count == UniToEntity.Count());
1340 // Lookup should find all entries
1341 count = 0;
1342 for (auto& entity : gEntities) {
1343 if (UniToEntity.Lookup(entity.mUnicode)) {
1344 count++;
1347 ASSERT_TRUE(count == UniToEntity.Count());
1349 for (auto& entity : gEntities) {
1350 UniToEntity.WithEntryHandle(entity.mUnicode,
1351 [](auto&& entry) { EXPECT_TRUE(entry); });
1354 // Lookup().Remove() should remove all entries.
1355 for (auto& entity : gEntities) {
1356 if (auto entry = UniToEntity.Lookup(entity.mUnicode)) {
1357 entry.Remove();
1360 ASSERT_TRUE(0 == UniToEntity.Count());
1362 // Remove newly added entries via OrRemove.
1363 for (auto& entity : gEntities) {
1364 UniToEntity.WithEntryHandle(entity.mUnicode, [](auto&& entry) {
1365 EXPECT_FALSE(entry);
1366 entry.OrRemove();
1369 ASSERT_TRUE(0 == UniToEntity.Count());
1371 // Remove existing entries via OrRemove.
1372 for (auto& entity : gEntities) {
1373 UniToEntity.WithEntryHandle(entity.mUnicode, [&entity](auto&& entry) {
1374 EXPECT_FALSE(entry);
1375 const char* const val = entry.OrInsert(entity.mStr);
1376 EXPECT_TRUE(entry);
1377 EXPECT_TRUE(val == entity.mStr);
1378 EXPECT_TRUE(entry.Data() == entity.mStr);
1381 UniToEntity.WithEntryHandle(entity.mUnicode, [](auto&& entry) {
1382 EXPECT_TRUE(entry);
1383 entry.OrRemove();
1386 ASSERT_TRUE(0 == UniToEntity.Count());
1389 TEST(Hashtables, ClassHashtable_WithEntryHandle)
1391 // check a class-hashtable WithEntryHandle with null values
1392 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1394 for (auto& entity : gEntities) {
1395 EntToUniClass.WithEntryHandle(
1396 nsDependentCString(entity.mStr), [](auto&& entry) {
1397 EXPECT_FALSE(entry);
1398 const TestUniChar* val = entry.OrInsert(nullptr).get();
1399 EXPECT_TRUE(entry);
1400 EXPECT_TRUE(val == nullptr);
1401 EXPECT_TRUE(entry.Data() == nullptr);
1405 for (auto& entity : gEntities) {
1406 EntToUniClass.WithEntryHandle(nsDependentCString(entity.mStr),
1407 [](auto&& entry) { EXPECT_TRUE(entry); });
1408 EntToUniClass.WithEntryHandle(
1409 nsDependentCString(entity.mStr),
1410 [](auto&& entry) { EXPECT_TRUE(entry.Data() == nullptr); });
1413 // "" should not be found
1414 size_t count = EntToUniClass.Count();
1415 EntToUniClass.Lookup(nsDependentCString("")).Remove();
1416 ASSERT_TRUE(count == EntToUniClass.Count());
1418 // Lookup should find all entries.
1419 count = 0;
1420 for (auto& entity : gEntities) {
1421 if (EntToUniClass.Lookup(nsDependentCString(entity.mStr))) {
1422 count++;
1425 ASSERT_TRUE(count == EntToUniClass.Count());
1427 for (auto& entity : gEntities) {
1428 EntToUniClass.WithEntryHandle(nsDependentCString(entity.mStr),
1429 [](auto&& entry) { EXPECT_TRUE(entry); });
1432 // Lookup().Remove() should remove all entries.
1433 for (auto& entity : gEntities) {
1434 if (auto entry = EntToUniClass.Lookup(nsDependentCString(entity.mStr))) {
1435 entry.Remove();
1438 ASSERT_TRUE(0 == EntToUniClass.Count());
1440 // Remove newly added entries via OrRemove.
1441 for (auto& entity : gEntities) {
1442 EntToUniClass.WithEntryHandle(nsDependentCString(entity.mStr),
1443 [](auto&& entry) {
1444 EXPECT_FALSE(entry);
1445 entry.OrRemove();
1448 ASSERT_TRUE(0 == EntToUniClass.Count());
1450 // Remove existing entries via OrRemove.
1451 for (auto& entity : gEntities) {
1452 EntToUniClass.WithEntryHandle(
1453 nsDependentCString(entity.mStr), [](auto&& entry) {
1454 EXPECT_FALSE(entry);
1455 const TestUniChar* val = entry.OrInsert(nullptr).get();
1456 EXPECT_TRUE(entry);
1457 EXPECT_TRUE(val == nullptr);
1458 EXPECT_TRUE(entry.Data() == nullptr);
1461 EntToUniClass.WithEntryHandle(nsDependentCString(entity.mStr),
1462 [](auto&& entry) {
1463 EXPECT_TRUE(entry);
1464 entry.OrRemove();
1467 ASSERT_TRUE(0 == EntToUniClass.Count());
1470 TEST(Hashtables, ClassHashtable_GetOrInsertNew_Present)
1472 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1474 for (const auto& entity : gEntities) {
1475 EntToUniClass.InsertOrUpdate(
1476 nsDependentCString(entity.mStr),
1477 mozilla::MakeUnique<TestUniCharDerived>(entity.mUnicode));
1480 auto* entry = EntToUniClass.GetOrInsertNew("uml"_ns, 42);
1481 EXPECT_EQ(168u, entry->GetChar());
1484 TEST(Hashtables, ClassHashtable_GetOrInsertNew_NotPresent)
1486 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1488 // This is going to insert a TestUniChar.
1489 auto* entry = EntToUniClass.GetOrInsertNew("uml"_ns, 42);
1490 EXPECT_EQ(42u, entry->GetChar());
1493 TEST(Hashtables, ClassHashtable_LookupOrInsertWith_Present)
1495 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1497 for (const auto& entity : gEntities) {
1498 EntToUniClass.InsertOrUpdate(
1499 nsDependentCString(entity.mStr),
1500 mozilla::MakeUnique<TestUniCharDerived>(entity.mUnicode));
1503 const auto& entry = EntToUniClass.LookupOrInsertWith(
1504 "uml"_ns, [] { return mozilla::MakeUnique<TestUniCharDerived>(42); });
1505 EXPECT_EQ(168u, entry->GetChar());
1508 TEST(Hashtables, ClassHashtable_LookupOrInsertWith_NotPresent)
1510 nsClassHashtable<nsCStringHashKey, TestUniChar> EntToUniClass(ENTITY_COUNT);
1512 // This is going to insert a TestUniCharDerived.
1513 const auto& entry = EntToUniClass.LookupOrInsertWith(
1514 "uml"_ns, [] { return mozilla::MakeUnique<TestUniCharDerived>(42); });
1515 EXPECT_EQ(42u, entry->GetChar());
1518 TEST(Hashtables, RefPtrHashtable)
1520 // check a RefPtr-hashtable
1521 nsRefPtrHashtable<nsCStringHashKey, TestUniCharRefCounted> EntToUniClass(
1522 ENTITY_COUNT);
1524 for (auto& entity : gEntities) {
1525 EntToUniClass.InsertOrUpdate(
1526 nsDependentCString(entity.mStr),
1527 MakeRefPtr<TestUniCharRefCounted>(entity.mUnicode));
1530 TestUniCharRefCounted* myChar;
1532 for (auto& entity : gEntities) {
1533 ASSERT_TRUE(EntToUniClass.Get(nsDependentCString(entity.mStr), &myChar));
1536 ASSERT_FALSE(EntToUniClass.Get("xxxx"_ns, &myChar));
1538 uint32_t count = 0;
1539 for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
1540 count++;
1542 ASSERT_EQ(count, ENTITY_COUNT);
1544 EntToUniClass.Clear();
1546 count = 0;
1547 for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
1548 count++;
1550 ASSERT_EQ(count, uint32_t(0));
1553 TEST(Hashtables, RefPtrHashtable_Clone)
1555 // check a RefPtr-hashtable
1556 nsRefPtrHashtable<nsCStringHashKey, TestUniCharRefCounted> EntToUniClass(
1557 ENTITY_COUNT);
1559 for (auto& entity : gEntities) {
1560 EntToUniClass.InsertOrUpdate(
1561 nsDependentCString(entity.mStr),
1562 MakeRefPtr<TestUniCharRefCounted>(entity.mUnicode));
1565 auto clone = EntToUniClass.Clone();
1566 static_assert(std::is_same_v<decltype(clone), decltype(EntToUniClass)>);
1568 EXPECT_EQ(clone.Count(), EntToUniClass.Count());
1570 for (const auto& entry : EntToUniClass) {
1571 auto cloneEntry = clone.Lookup(entry.GetKey());
1573 EXPECT_TRUE(cloneEntry);
1574 EXPECT_EQ(cloneEntry.Data(), entry.GetWeak());
1578 TEST(Hashtables, Clone)
1580 static constexpr uint64_t count = 10;
1582 nsTHashMap<nsUint64HashKey, uint64_t> table;
1583 for (uint64_t i = 0; i < count; i++) {
1584 table.InsertOrUpdate(42 + i, i);
1587 auto clone = table.Clone();
1589 static_assert(std::is_same_v<decltype(clone), decltype(table)>);
1591 EXPECT_EQ(clone.Count(), table.Count());
1593 for (const auto& entry : table) {
1594 auto cloneEntry = clone.Lookup(entry.GetKey());
1596 EXPECT_TRUE(cloneEntry);
1597 EXPECT_EQ(cloneEntry.Data(), entry.GetData());
1601 TEST(Hashtables, Values)
1603 static constexpr uint64_t count = 10;
1605 nsTHashMap<nsUint64HashKey, uint64_t> table;
1606 for (uint64_t i = 0; i < count; i++) {
1607 table.InsertOrUpdate(42 + i, i);
1610 nsTArray<uint64_t> values;
1611 for (const uint64_t& value : table.Values()) {
1612 values.AppendElement(value);
1614 values.Sort();
1616 EXPECT_EQ((nsTArray<uint64_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), values);