1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is C++ hashtable templates.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2002
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsTHashtable.h"
39 #include "nsBaseHashtable.h"
40 #include "nsDataHashtable.h"
41 #include "nsInterfaceHashtable.h"
42 #include "nsClassHashtable.h"
45 #include "nsISupports.h"
46 #include "nsCOMArray.h"
50 namespace TestHashtables
{
52 class TestUniChar
// for nsClassHashtable
55 TestUniChar(PRUint32 aWord
)
57 printf(" TestUniChar::TestUniChar() %u\n", aWord
);
63 printf(" TestUniChar::~TestUniChar() %u\n", mWord
);
66 PRUint32
GetChar() const { return mWord
; }
73 const char* mStr
; // never owns buffer
77 EntityNode gEntities
[] = {
96 #define ENTITY_COUNT (sizeof(gEntities)/sizeof(EntityNode))
98 class EntityToUnicodeEntry
: public PLDHashEntryHdr
101 typedef const char* KeyType
;
102 typedef const char* KeyTypePointer
;
104 EntityToUnicodeEntry(const char* aKey
) { mNode
= nsnull
; }
105 EntityToUnicodeEntry(const EntityToUnicodeEntry
& aEntry
) { mNode
= aEntry
.mNode
; }
106 ~EntityToUnicodeEntry() { };
108 PRBool
KeyEquals(const char* aEntity
) const { return !strcmp(mNode
->mStr
, aEntity
); }
109 static const char* KeyToPointer(const char* aEntity
) { return aEntity
; }
110 static PLDHashNumber
HashKey(const char* aEntity
) { return HashString(aEntity
); }
111 enum { ALLOW_MEMMOVE
= PR_TRUE
};
113 const EntityNode
* mNode
;
117 nsTEnumGo(EntityToUnicodeEntry
* aEntry
, void* userArg
) {
118 printf(" enumerated \"%s\" = %u\n",
119 aEntry
->mNode
->mStr
, aEntry
->mNode
->mUnicode
);
121 return PL_DHASH_NEXT
;
125 nsTEnumStop(EntityToUnicodeEntry
* aEntry
, void* userArg
) {
126 printf(" enumerated \"%s\" = %u\n",
127 aEntry
->mNode
->mStr
, aEntry
->mNode
->mUnicode
);
129 return PL_DHASH_REMOVE
;
133 testTHashtable(nsTHashtable
<EntityToUnicodeEntry
>& hash
, PRUint32 numEntries
) {
134 printf("Filling hash with %d entries.\n", numEntries
);
137 for (i
= 0; i
< numEntries
; ++i
) {
138 printf(" Putting entry \"%s\"...", gEntities
[i
].mStr
);
139 EntityToUnicodeEntry
* entry
=
140 hash
.PutEntry(gEntities
[i
].mStr
);
149 printf("entry already exists!\n");
154 entry
->mNode
= &gEntities
[i
];
157 printf("Testing Get:\n");
159 for (i
= 0; i
< numEntries
; ++i
) {
160 printf(" Getting entry \"%s\"...", gEntities
[i
].mStr
);
161 EntityToUnicodeEntry
* entry
=
162 hash
.GetEntry(gEntities
[i
].mStr
);
169 printf("Found %u\n", entry
->mNode
->mUnicode
);
172 printf("Testing non-existent entries...");
174 EntityToUnicodeEntry
* entry
=
175 hash
.GetEntry("xxxy");
178 printf("FOUND! BAD!\n");
182 printf("not found; good.\n");
184 printf("Enumerating:\n");
185 PRUint32 count
= hash
.EnumerateEntries(nsTEnumGo
, nsnull
);
186 if (count
!= numEntries
) {
187 printf(" Bad count!\n");
193 nsDEnumRead(const PRUint32
& aKey
, const char* aData
, void* userArg
) {
194 printf(" enumerated %u = \"%s\"\n", aKey
, aData
);
195 return PL_DHASH_NEXT
;
199 nsDEnum(const PRUint32
& aKey
, const char*& aData
, void* userArg
) {
200 printf(" enumerated %u = \"%s\"\n", aKey
, aData
);
201 return PL_DHASH_NEXT
;
205 nsCEnumRead(const nsACString
& aKey
, TestUniChar
* aData
, void* userArg
) {
206 printf(" enumerated \"%s\" = %c\n",
207 PromiseFlatCString(aKey
).get(), aData
->GetChar());
208 return PL_DHASH_NEXT
;
212 nsCEnum(const nsACString
& aKey
, nsAutoPtr
<TestUniChar
>& aData
, void* userArg
) {
213 printf(" enumerated \"%s\" = %c\n",
214 PromiseFlatCString(aKey
).get(), aData
->GetChar());
215 return PL_DHASH_NEXT
;
219 // all this nsIFoo stuff was copied wholesale from TestCOMPtr.cpp
222 #define NS_IFOO_IID \
223 { 0x6f7652e0, 0xee43, 0x11d1, \
224 { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } }
226 class IFoo
: public nsISupports
229 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID
)
233 NS_IMETHOD_(nsrefcnt
) AddRef();
234 NS_IMETHOD_(nsrefcnt
) Release();
235 NS_IMETHOD
QueryInterface( const nsIID
&, void** );
237 NS_IMETHOD
SetString(const nsACString
& /*in*/ aString
);
238 NS_IMETHOD
GetString(nsACString
& /*out*/ aString
);
240 static void print_totals();
245 unsigned int refcount_
;
247 static unsigned int total_constructions_
;
248 static unsigned int total_destructions_
;
252 NS_DEFINE_STATIC_IID_ACCESSOR(IFoo
, NS_IFOO_IID
)
254 unsigned int IFoo::total_constructions_
;
255 unsigned int IFoo::total_destructions_
;
260 printf("total constructions/destructions --> %d/%d\n",
261 total_constructions_
, total_destructions_
);
267 ++total_constructions_
;
268 printf(" new IFoo@%p [#%d]\n",
269 static_cast<void*>(this), total_constructions_
);
274 ++total_destructions_
;
275 printf("IFoo@%p::~IFoo() [#%d]\n",
276 static_cast<void*>(this), total_destructions_
);
283 printf("IFoo@%p::AddRef(), refcount --> %d\n",
284 static_cast<void*>(this), refcount_
);
291 int newcount
= --refcount_
;
295 printf("IFoo@%p::Release(), refcount --> %d\n",
296 static_cast<void*>(this), refcount_
);
300 printf(" delete IFoo@%p\n", static_cast<void*>(this));
301 printf("<<IFoo@%p::Release()\n", static_cast<void*>(this));
309 IFoo::QueryInterface( const nsIID
& aIID
, void** aResult
)
311 printf("IFoo@%p::QueryInterface()\n", static_cast<void*>(this));
312 nsISupports
* rawPtr
= 0;
313 nsresult status
= NS_OK
;
315 if ( aIID
.Equals(GetIID()) )
319 nsID iid_of_ISupports
= NS_ISUPPORTS_IID
;
320 if ( aIID
.Equals(iid_of_ISupports
) )
321 rawPtr
= static_cast<nsISupports
*>(this);
323 status
= NS_ERROR_NO_INTERFACE
;
326 NS_IF_ADDREF(rawPtr
);
333 IFoo::SetString(const nsACString
& aString
)
340 IFoo::GetString(nsACString
& aString
)
347 CreateIFoo( IFoo
** result
)
348 // a typical factory function (that calls AddRef)
350 printf(" >>CreateIFoo() --> ");
351 IFoo
* foop
= new IFoo();
352 printf("IFoo@%p\n", static_cast<void*>(foop
));
357 printf("<<CreateIFoo()\n");
362 nsIEnumRead(const PRUint32
& aKey
, IFoo
* aFoo
, void* userArg
) {
364 aFoo
->GetString(str
);
366 printf(" enumerated %u = \"%s\"\n", aKey
, str
.get());
367 return PL_DHASH_NEXT
;
371 nsIEnum(const PRUint32
& aKey
, nsCOMPtr
<IFoo
>& aData
, void* userArg
) {
373 aData
->GetString(str
);
375 printf(" enumerated %u = \"%s\"\n", aKey
, str
.get());
376 return PL_DHASH_NEXT
;
380 nsIEnum2Read(nsISupports
* aKey
, PRUint32 aData
, void* userArg
) {
382 nsCOMPtr
<IFoo
> foo
= do_QueryInterface(aKey
);
386 printf(" enumerated \"%s\" = %u\n", str
.get(), aData
);
387 return PL_DHASH_NEXT
;
391 nsIEnum2(nsISupports
* aKey
, PRUint32
& aData
, void* userArg
) {
393 nsCOMPtr
<IFoo
> foo
= do_QueryInterface(aKey
);
396 printf(" enumerated \"%s\" = %u\n", str
.get(), aData
);
397 return PL_DHASH_NEXT
;
402 using namespace TestHashtables
;
406 // check an nsTHashtable
407 nsTHashtable
<EntityToUnicodeEntry
> EntityToUnicode
;
409 printf("Initializing nsTHashtable...");
410 if (!EntityToUnicode
.Init(ENTITY_COUNT
)) {
416 printf("Partially filling nsTHashtable:\n");
417 testTHashtable(EntityToUnicode
, 5);
419 printf("Enumerate-removing...\n");
420 PRUint32 count
= EntityToUnicode
.EnumerateEntries(nsTEnumStop
, nsnull
);
422 printf("wrong count\n");
427 printf("Check enumeration...");
428 count
= EntityToUnicode
.EnumerateEntries(nsTEnumGo
, nsnull
);
430 printf("entries remain in table!\n");
435 printf("Filling nsTHashtable:\n");
436 testTHashtable(EntityToUnicode
, ENTITY_COUNT
);
438 printf("Clearing...");
439 EntityToUnicode
.Clear();
442 printf("Check enumeration...");
443 count
= EntityToUnicode
.EnumerateEntries(nsTEnumGo
, nsnull
);
445 printf("entries remain in table!\n");
451 // now check a data-hashtable
454 nsDataHashtable
<nsUint32HashKey
,const char*> UniToEntity
;
456 printf("Initializing nsDataHashtable...");
457 if (!UniToEntity
.Init(ENTITY_COUNT
)) {
463 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
466 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
467 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
468 if (!UniToEntity
.Put(gEntities
[i
].mUnicode
, gEntities
[i
].mStr
)) {
475 printf("Testing Get:\n");
478 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
479 printf(" Getting entry %u...", gEntities
[i
].mUnicode
);
480 if (!UniToEntity
.Get(gEntities
[i
].mUnicode
, &str
)) {
485 printf("Found %s\n", str
);
488 printf("Testing non-existent entries...");
489 if (UniToEntity
.Get(99446, &str
)) {
490 printf("FOUND! BAD!\n");
494 printf("not found; good.\n");
496 printf("Enumerating:\n");
498 count
= UniToEntity
.EnumerateRead(nsDEnumRead
, nsnull
);
499 if (count
!= ENTITY_COUNT
) {
500 printf(" Bad count!\n");
504 printf("Clearing...");
508 printf("Checking count...");
509 count
= UniToEntity
.Enumerate(nsDEnum
, nsnull
);
511 printf(" Clear did not remove all entries.\n");
518 // now check a thread-safe data-hashtable
521 nsDataHashtableMT
<nsUint32HashKey
,const char*> UniToEntityL
;
523 printf("Initializing nsDataHashtableMT...");
524 if (!UniToEntityL
.Init(ENTITY_COUNT
)) {
530 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
532 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
533 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
534 if (!UniToEntityL
.Put(gEntities
[i
].mUnicode
, gEntities
[i
].mStr
)) {
541 printf("Testing Get:\n");
543 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
544 printf(" Getting entry %u...", gEntities
[i
].mUnicode
);
545 if (!UniToEntityL
.Get(gEntities
[i
].mUnicode
, &str
)) {
550 printf("Found %s\n", str
);
553 printf("Testing non-existent entries...");
554 if (UniToEntityL
.Get(99446, &str
)) {
555 printf("FOUND! BAD!\n");
559 printf("not found; good.\n");
561 printf("Enumerating:\n");
563 count
= UniToEntityL
.EnumerateRead(nsDEnumRead
, nsnull
);
564 if (count
!= ENTITY_COUNT
) {
565 printf(" Bad count!\n");
569 printf("Clearing...");
570 UniToEntityL
.Clear();
573 printf("Checking count...");
574 count
= UniToEntityL
.Enumerate(nsDEnum
, nsnull
);
576 printf(" Clear did not remove all entries.\n");
583 // now check a class-hashtable
586 nsClassHashtable
<nsCStringHashKey
,TestUniChar
> EntToUniClass
;
588 printf("Initializing nsClassHashtable...");
589 if (!EntToUniClass
.Init(ENTITY_COUNT
)) {
595 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
597 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
598 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
599 TestUniChar
* temp
= new TestUniChar(gEntities
[i
].mUnicode
);
601 if (!EntToUniClass
.Put(nsDependentCString(gEntities
[i
].mStr
), temp
)) {
609 printf("Testing Get:\n");
612 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
613 printf(" Getting entry %s...", gEntities
[i
].mStr
);
614 if (!EntToUniClass
.Get(nsDependentCString(gEntities
[i
].mStr
), &myChar
)) {
619 printf("Found %c\n", myChar
->GetChar());
622 printf("Testing non-existent entries...");
623 if (EntToUniClass
.Get(NS_LITERAL_CSTRING("xxxx"), &myChar
)) {
624 printf("FOUND! BAD!\n");
628 printf("not found; good.\n");
630 printf("Enumerating:\n");
632 count
= EntToUniClass
.EnumerateRead(nsCEnumRead
, nsnull
);
633 if (count
!= ENTITY_COUNT
) {
634 printf(" Bad count!\n");
638 printf("Clearing...\n");
639 EntToUniClass
.Clear();
640 printf(" Clearing OK\n");
642 printf("Checking count...");
643 count
= EntToUniClass
.Enumerate(nsCEnum
, nsnull
);
645 printf(" Clear did not remove all entries.\n");
652 // now check a thread-safe class-hashtable
655 nsClassHashtableMT
<nsCStringHashKey
,TestUniChar
> EntToUniClassL
;
657 printf("Initializing nsClassHashtableMT...");
658 if (!EntToUniClassL
.Init(ENTITY_COUNT
)) {
664 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
666 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
667 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
668 TestUniChar
* temp
= new TestUniChar(gEntities
[i
].mUnicode
);
670 if (!EntToUniClassL
.Put(nsDependentCString(gEntities
[i
].mStr
), temp
)) {
678 printf("Testing Get:\n");
680 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
681 printf(" Getting entry %s...", gEntities
[i
].mStr
);
682 if (!EntToUniClassL
.Get(nsDependentCString(gEntities
[i
].mStr
), &myChar
)) {
687 printf("Found %c\n", myChar
->GetChar());
690 printf("Testing non-existent entries...");
691 if (EntToUniClassL
.Get(NS_LITERAL_CSTRING("xxxx"), &myChar
)) {
692 printf("FOUND! BAD!\n");
696 printf("not found; good.\n");
698 printf("Enumerating:\n");
700 count
= EntToUniClassL
.EnumerateRead(nsCEnumRead
, nsnull
);
701 if (count
!= ENTITY_COUNT
) {
702 printf(" Bad count!\n");
706 printf("Clearing...\n");
707 EntToUniClassL
.Clear();
708 printf(" Clearing OK\n");
710 printf("Checking count...");
711 count
= EntToUniClassL
.Enumerate(nsCEnum
, nsnull
);
713 printf(" Clear did not remove all entries.\n");
720 // now check a data-hashtable with an interface key
723 nsDataHashtable
<nsISupportsHashKey
,PRUint32
> EntToUniClass2
;
725 printf("Initializing nsDataHashtable with interface key...");
726 if (!EntToUniClass2
.Init(ENTITY_COUNT
)) {
732 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
734 nsCOMArray
<IFoo
> fooArray
;
736 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
737 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
739 CreateIFoo(getter_AddRefs(foo
));
740 foo
->SetString(nsDependentCString(gEntities
[i
].mStr
));
743 fooArray
.InsertObjectAt(foo
, i
);
745 if (!EntToUniClass2
.Put(foo
, gEntities
[i
].mUnicode
)) {
752 printf("Testing Get:\n");
755 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
756 printf(" Getting entry %s...", gEntities
[i
].mStr
);
758 if (!EntToUniClass2
.Get(fooArray
[i
], &myChar2
)) {
763 printf("Found %c\n", myChar2
);
766 printf("Testing non-existent entries...");
767 if (EntToUniClass2
.Get((nsISupports
*) 0x55443316, &myChar2
)) {
768 printf("FOUND! BAD!\n");
772 printf("not found; good.\n");
774 printf("Enumerating:\n");
776 count
= EntToUniClass2
.EnumerateRead(nsIEnum2Read
, nsnull
);
777 if (count
!= ENTITY_COUNT
) {
778 printf(" Bad count!\n");
782 printf("Clearing...\n");
783 EntToUniClass2
.Clear();
784 printf(" Clearing OK\n");
786 printf("Checking count...");
787 count
= EntToUniClass2
.Enumerate(nsIEnum2
, nsnull
);
789 printf(" Clear did not remove all entries.\n");
796 // now check an interface-hashtable with an PRUint32 key
799 nsInterfaceHashtable
<nsUint32HashKey
,IFoo
> UniToEntClass2
;
801 printf("Initializing nsInterfaceHashtable...");
802 if (!UniToEntClass2
.Init(ENTITY_COUNT
)) {
808 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
810 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
811 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
813 CreateIFoo(getter_AddRefs(foo
));
814 foo
->SetString(nsDependentCString(gEntities
[i
].mStr
));
816 if (!UniToEntClass2
.Put(gEntities
[i
].mUnicode
, foo
)) {
823 printf("Testing Get:\n");
825 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
826 printf(" Getting entry %s...", gEntities
[i
].mStr
);
828 nsCOMPtr
<IFoo
> myEnt
;
829 if (!UniToEntClass2
.Get(gEntities
[i
].mUnicode
, getter_AddRefs(myEnt
))) {
835 myEnt
->GetString(str
);
836 printf("Found %s\n", str
.get());
839 printf("Testing non-existent entries...");
840 nsCOMPtr
<IFoo
> myEnt
;
841 if (UniToEntClass2
.Get(9462, getter_AddRefs(myEnt
))) {
842 printf("FOUND! BAD!\n");
846 printf("not found; good.\n");
848 printf("Enumerating:\n");
850 count
= UniToEntClass2
.EnumerateRead(nsIEnumRead
, nsnull
);
851 if (count
!= ENTITY_COUNT
) {
852 printf(" Bad count!\n");
856 printf("Clearing...\n");
857 UniToEntClass2
.Clear();
858 printf(" Clearing OK\n");
860 printf("Checking count...");
861 count
= UniToEntClass2
.Enumerate(nsIEnum
, nsnull
);
863 printf(" Clear did not remove all entries.\n");
870 // now check a thread-safe interface hashtable
873 nsInterfaceHashtableMT
<nsUint32HashKey
,IFoo
> UniToEntClass2L
;
875 printf("Initializing nsInterfaceHashtableMT...");
876 if (!UniToEntClass2L
.Init(ENTITY_COUNT
)) {
882 printf("Filling hash with %d entries.\n", ENTITY_COUNT
);
884 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
885 printf(" Putting entry %u...", gEntities
[i
].mUnicode
);
887 CreateIFoo(getter_AddRefs(foo
));
888 foo
->SetString(nsDependentCString(gEntities
[i
].mStr
));
890 if (!UniToEntClass2L
.Put(gEntities
[i
].mUnicode
, foo
)) {
897 printf("Testing Get:\n");
899 for (i
= 0; i
< ENTITY_COUNT
; ++i
) {
900 printf(" Getting entry %s...", gEntities
[i
].mStr
);
902 nsCOMPtr
<IFoo
> myEnt
;
903 if (!UniToEntClass2L
.Get(gEntities
[i
].mUnicode
, getter_AddRefs(myEnt
))) {
909 myEnt
->GetString(str
);
910 printf("Found %s\n", str
.get());
913 printf("Testing non-existent entries...");
914 if (UniToEntClass2L
.Get(9462, getter_AddRefs(myEnt
))) {
915 printf("FOUND! BAD!\n");
919 printf("not found; good.\n");
921 printf("Enumerating:\n");
923 count
= UniToEntClass2L
.EnumerateRead(nsIEnumRead
, nsnull
);
924 if (count
!= ENTITY_COUNT
) {
925 printf(" Bad count!\n");
929 printf("Clearing...\n");
930 UniToEntClass2L
.Clear();
931 printf(" Clearing OK\n");
933 printf("Checking count...");
934 count
= UniToEntClass2L
.Enumerate(nsIEnum
, nsnull
);
936 printf(" Clear did not remove all entries.\n");