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"
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"
25 using mozilla::MakeRefPtr
;
26 using mozilla::MakeUnique
;
27 using mozilla::UniquePtr
;
29 namespace TestHashtables
{
31 class TestUniChar
// for nsClassHashtable
34 explicit TestUniChar(uint32_t aWord
) { mWord
= aWord
; }
36 ~TestUniChar() = default;
38 uint32_t GetChar() const { return mWord
; }
44 class TestUniCharDerived
: public TestUniChar
{
45 using TestUniChar::TestUniChar
;
48 class TestUniCharRefCounted
// for nsRefPtrHashtable
51 explicit TestUniCharRefCounted(uint32_t aWord
,
52 uint32_t aExpectedAddRefCnt
= 0)
53 : mExpectedAddRefCnt(aExpectedAddRefCnt
),
65 EXPECT_TRUE(mRefCnt
> 0);
74 uint32_t GetChar() const { return mWord
; }
77 ~TestUniCharRefCounted() {
78 if (mExpectedAddRefCnt
> 0) {
79 EXPECT_EQ(mAddRefCnt
, mExpectedAddRefCnt
);
83 uint32_t mExpectedAddRefCnt
;
90 const char* mStr
; // never owns buffer
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
{
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
) {
132 for (auto iter
= hash
.Iter(); !iter
.Done(); iter
.Next()) {
138 static uint32_t nsTIterPrintRemove(nsTHashtable
<EntityToUnicodeEntry
>& hash
) {
140 for (auto iter
= hash
.Iter(); !iter
.Done(); iter
.Next()) {
147 static void testTHashtable(nsTHashtable
<EntityToUnicodeEntry
>& hash
,
148 uint32_t numEntries
) {
150 for (i
= 0; i
< numEntries
; ++i
) {
151 EntityToUnicodeEntry
* entry
= hash
.PutEntry(gEntities
[i
].mStr
);
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
);
165 EntityToUnicodeEntry
* entry
= hash
.GetEntry("xxxy");
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;
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
{
199 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID
)
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();
215 unsigned int refcount_
;
217 static unsigned int total_constructions_
;
218 static unsigned int total_destructions_
;
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() {
238 MozExternalRefCountType
IFoo::Release() {
239 int newcount
= --refcount_
;
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
)))
254 nsID iid_of_ISupports
= NS_ISUPPORTS_IID
;
255 if (aIID
.Equals(iid_of_ISupports
))
256 rawPtr
= static_cast<nsISupports
*>(this);
258 status
= NS_ERROR_NO_INTERFACE
;
261 NS_IF_ADDREF(rawPtr
);
267 nsresult
IFoo::SetString(const nsACString
& aString
) {
272 nsresult
IFoo::GetString(nsACString
& aString
) {
277 static nsresult
CreateIFoo(IFoo
** result
)
278 // a typical factory function (that calls AddRef)
280 auto* foop
= new IFoo();
288 class DefaultConstructible
{
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;
306 RefPtr
<TestUniCharRefCounted
> mChar
;
309 class MovingNonDefaultConstructible
;
311 class NonDefaultConstructible
{
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)
326 NonDefaultConstructible(const NonDefaultConstructible
&) = default;
327 NonDefaultConstructible
& operator=(const NonDefaultConstructible
&) = default;
330 RefPtr
<TestUniCharRefCounted
> mChar
;
333 class MovingNonDefaultConstructible
{
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
&&) =
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!");
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 (
485 NonDefaultConstructible_MovingNonDefaultConstructible
>()) {
486 return "NonDefaultConstructible_MovingNonDefaultConstructible";
493 template <typename TypeParam
>
494 auto MakeEmptyBaseHashtable() {
495 nsBaseHashtable
<nsUint64HashKey
, typename
TypeParam::DataType
,
496 typename
TypeParam::UserDataType
>
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
)));
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
> ||
520 NonDefaultConstructible_NonDefaultConstructible
>) {
522 } else if constexpr (
523 std::is_same_v
<TypeParam
,
524 NonDefaultConstructible_MovingNonDefaultConstructible
>) {
525 return std::move(aUserData
);
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
++) {
599 nsTArray
<uint64_t> keys
;
600 for (const uint64_t& key
: table
.Keys()) {
601 keys
.AppendElement(key
);
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
) {
615 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Contains
);
617 auto res
= table
.Contains(1);
621 TYPED_TEST_P(BaseHashtableTest
, GetGeneration
) {
623 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_GetGeneration
);
625 auto res
= table
.GetGeneration();
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.
635 auto table
= MakeBaseHashtable
<TypeParam
>(
636 TypeParam::kExpectedAddRefCnt_SizeOfExcludingThis
);
638 auto res
= table
.SizeOfExcludingThis(MallocSizeOf
);
643 TYPED_TEST_P(BaseHashtableTest
, SizeOfIncludingThis
) {
644 // This doesn't compile at the moment, since nsBaseHashtableET lacks
645 // SizeOfIncludingThis implementation. Bug 1689214.
647 auto table
= MakeBaseHashtable
<TypeParam
>(
648 TypeParam::kExpectedAddRefCnt_SizeOfIncludingThis
);
650 auto res
= table
.SizeOfIncludingThis(MallocSizeOf
);
655 TYPED_TEST_P(BaseHashtableTest
, Count
) {
657 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Count
);
659 auto res
= table
.Count();
663 TYPED_TEST_P(BaseHashtableTest
, IsEmpty
) {
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
);
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
>) {
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
) {
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, [] {
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
)),
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
))),
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
);
814 EXPECT_EQ(data
.CharRef()->GetChar(), 42u);
818 TYPED_TEST_P(BaseHashtableTest
, Remove
) {
820 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Remove
);
822 auto res
= table
.Remove(1);
826 TYPED_TEST_P(BaseHashtableTest
, Extract
) {
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
) {
837 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_RemoveIf
);
839 table
.RemoveIf([](const auto&) { return true; });
842 TYPED_TEST_P(BaseHashtableTest
, Lookup
) {
844 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Lookup
);
846 auto res
= table
.Lookup(1);
848 EXPECT_EQ(res
.Data().CharRef()->GetChar(), 42u);
851 TYPED_TEST_P(BaseHashtableTest
, Lookup_Remove
) {
853 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Lookup_Remove
);
855 auto res
= table
.Lookup(1);
857 EXPECT_EQ(res
.Data().CharRef()->GetChar(), 42u);
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
{
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
) {
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
) {
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;
963 TYPED_TEST_P(BaseHashtableTest
, cbegin_cend
) {
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;
973 TYPED_TEST_P(BaseHashtableTest
, Clear
) {
975 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_Clear
);
980 TYPED_TEST_P(BaseHashtableTest
, ShallowSizeOfExcludingThis
) {
981 auto table
= MakeBaseHashtable
<TypeParam
>(
982 TypeParam::kExpectedAddRefCnt_ShallowSizeOfExcludingThis
);
984 auto res
= table
.ShallowSizeOfExcludingThis(MallocSizeOf
);
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
);
999 TYPED_TEST_P(BaseHashtableTest
, SwapElements
) {
1001 MakeBaseHashtable
<TypeParam
>(TypeParam::kExpectedAddRefCnt_SwapElements
);
1003 auto table2
= MakeEmptyBaseHashtable
<TypeParam
>();
1005 table
.SwapElements(table2
);
1008 TYPED_TEST_P(BaseHashtableTest
, MarkImmutable
) {
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
);
1048 for (auto& entity
: gEntities
) {
1049 ASSERT_TRUE(UniToEntity
.Get(entity
.mUnicode
, &str
));
1052 ASSERT_FALSE(UniToEntity
.Get(99446, &str
));
1055 for (auto iter
= UniToEntity
.Iter(); !iter
.Done(); iter
.Next()) {
1058 ASSERT_EQ(count
, ENTITY_COUNT
);
1060 UniToEntity
.Clear();
1063 for (auto iter
= UniToEntity
.Iter(); !iter
.Done(); iter
.Next()) {
1064 printf(" enumerated %u = \"%s\"\n", iter
.Key(), iter
.Data());
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();
1084 ASSERT_EQ(1, std::distance(UniToEntity
.cbegin(), ci
++));
1085 ASSERT_EQ(2, std::distance(UniToEntity
.cbegin(), ci
));
1086 ASSERT_TRUE(ci
== 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*>&>(
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
) {
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
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
));
1171 for (auto iter
= EntToUniClass
.Iter(); !iter
.Done(); iter
.Next()) {
1174 ASSERT_EQ(count
, ENTITY_COUNT
);
1176 EntToUniClass
.Clear();
1179 for (auto iter
= EntToUniClass
.Iter(); !iter
.Done(); iter
.Next()) {
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
>&>(
1202 entity
.GetKey().GetData(&str
);
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
) {
1214 entity
.GetKey().GetData(&str
);
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
) {
1234 CreateIFoo(getter_AddRefs(foo
));
1235 foo
->SetString(nsDependentCString(gEntities
[i
].mStr
));
1237 fooArray
.InsertObjectAt(foo
, i
);
1239 EntToUniClass2
.InsertOrUpdate(foo
, gEntities
[i
].mUnicode
);
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
));
1251 for (auto iter
= EntToUniClass2
.Iter(); !iter
.Done(); iter
.Next()) {
1253 nsCOMPtr
<IFoo
> foo
= do_QueryInterface(iter
.Key());
1257 ASSERT_EQ(count
, ENTITY_COUNT
);
1259 EntToUniClass2
.Clear();
1262 for (auto iter
= EntToUniClass2
.Iter(); !iter
.Done(); iter
.Next()) {
1264 nsCOMPtr
<IFoo
> foo
= do_QueryInterface(iter
.Key());
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
) {
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
)));
1296 for (auto iter
= UniToEntClass2
.Iter(); !iter
.Done(); iter
.Next()) {
1298 iter
.UserData()->GetString(s
);
1301 ASSERT_EQ(count
, ENTITY_COUNT
);
1303 UniToEntClass2
.Clear();
1306 for (auto iter
= UniToEntClass2
.Iter(); !iter
.Done(); iter
.Next()) {
1308 iter
.Data()->GetString(s
);
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
; });
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
1342 for (auto& entity
: gEntities
) {
1343 if (UniToEntity
.Lookup(entity
.mUnicode
)) {
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
)) {
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
);
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
);
1377 EXPECT_TRUE(val
== entity
.mStr
);
1378 EXPECT_TRUE(entry
.Data() == entity
.mStr
);
1381 UniToEntity
.WithEntryHandle(entity
.mUnicode
, [](auto&& entry
) {
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();
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.
1420 for (auto& entity
: gEntities
) {
1421 if (EntToUniClass
.Lookup(nsDependentCString(entity
.mStr
))) {
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
))) {
1438 ASSERT_TRUE(0 == EntToUniClass
.Count());
1440 // Remove newly added entries via OrRemove.
1441 for (auto& entity
: gEntities
) {
1442 EntToUniClass
.WithEntryHandle(nsDependentCString(entity
.mStr
),
1444 EXPECT_FALSE(entry
);
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();
1457 EXPECT_TRUE(val
== nullptr);
1458 EXPECT_TRUE(entry
.Data() == nullptr);
1461 EntToUniClass
.WithEntryHandle(nsDependentCString(entity
.mStr
),
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(
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
));
1539 for (auto iter
= EntToUniClass
.Iter(); !iter
.Done(); iter
.Next()) {
1542 ASSERT_EQ(count
, ENTITY_COUNT
);
1544 EntToUniClass
.Clear();
1547 for (auto iter
= EntToUniClass
.Iter(); !iter
.Done(); iter
.Next()) {
1550 ASSERT_EQ(count
, uint32_t(0));
1553 TEST(Hashtables
, RefPtrHashtable_Clone
)
1555 // check a RefPtr-hashtable
1556 nsRefPtrHashtable
<nsCStringHashKey
, TestUniCharRefCounted
> EntToUniClass(
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
);
1616 EXPECT_EQ((nsTArray
<uint64_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), values
);