VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
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/
9 *
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
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or 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.
35 *
36 * ***** END LICENSE BLOCK *****
37 * This Original Code has been modified by IBM Corporation.
38 * Modifications made by IBM described herein are
39 * Copyright (c) International Business Machines
40 * Corporation, 2000
41 *
42 * Modifications to Mozilla code or documentation
43 * identified per MPL Section 3.3
44 *
45 * Date Modified by Description of modification
46 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
47 */
48
49#include <string.h>
50#include "prmem.h"
51#include "prlog.h"
52#include "nsHashtable.h"
53#include "nsReadableUtils.h"
54#include "nsIObjectInputStream.h"
55#include "nsIObjectOutputStream.h"
56#include "nsCRT.h"
57
58struct HTEntry : PLDHashEntryHdr
59{
60 nsHashKey* key;
61 void* value;
62};
63
64//
65// Key operations
66//
67
68PR_STATIC_CALLBACK(PRBool)
69matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
70 const void* key)
71{
72 const HTEntry* hashEntry =
73 NS_STATIC_CAST(const HTEntry*, entry);
74
75 if (hashEntry->key == key)
76 return PR_TRUE;
77
78 const nsHashKey* otherKey = NS_REINTERPRET_CAST(const nsHashKey*, key);
79 return otherKey->Equals(hashEntry->key);
80}
81
82PR_STATIC_CALLBACK(PLDHashNumber)
83hashKey(PLDHashTable* table, const void* key)
84{
85 const nsHashKey* hashKey = NS_STATIC_CAST(const nsHashKey*, key);
86
87 return hashKey->HashCode();
88}
89
90PR_STATIC_CALLBACK(void)
91clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry)
92{
93 HTEntry* hashEntry = NS_STATIC_CAST(HTEntry*, entry);
94
95 // leave it up to the nsHashKey destructor to free the "value"
96 delete hashEntry->key;
97 hashEntry->key = nsnull;
98 hashEntry->value = nsnull; // probably not necessary, but for
99 // sanity's sake
100}
101
102
103static const PLDHashTableOps hashtableOps = {
104 PL_DHashAllocTable,
105 PL_DHashFreeTable,
106 PL_DHashGetKeyStub,
107 hashKey,
108 matchKeyEntry,
109 PL_DHashMoveEntryStub,
110 clearHashEntry,
111 PL_DHashFinalizeStub,
112 nsnull,
113};
114
115
116//
117// Enumerator callback
118//
119
120struct _HashEnumerateArgs {
121 nsHashtableEnumFunc fn;
122 void* arg;
123};
124
125PR_STATIC_CALLBACK(PLDHashOperator)
126hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, PRUint32 i, void *arg)
127{
128 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
129 HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr);
130
131 switch (thunk->fn(entry->key, entry->value, thunk->arg)) {
132 case kHashEnumerateNext:
133 return PL_DHASH_NEXT;
134 case kHashEnumerateRemove:
135 return PL_DHASH_REMOVE;
136 }
137 return PL_DHASH_STOP;
138}
139
140//
141// HashKey
142//
143
144nsHashKey::~nsHashKey(void)
145{
146 MOZ_COUNT_DTOR(nsHashKey);
147}
148
149nsresult
150nsHashKey::Write(nsIObjectOutputStream* aStream) const
151{
152 NS_NOTREACHED("oops");
153 return NS_ERROR_NOT_IMPLEMENTED;
154}
155
156MOZ_DECL_CTOR_COUNTER(nsHashtable)
157
158nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
159 : mLock(NULL), mEnumerating(PR_FALSE)
160{
161 MOZ_COUNT_CTOR(nsHashtable);
162
163 PRBool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nsnull,
164 sizeof(HTEntry), aInitSize);
165
166 NS_ASSERTION(result, "Hashtable failed to initialize");
167
168 // make sure we detect this later
169 if (!result)
170 mHashtable.ops = nsnull;
171
172 if (threadSafe) {
173 mLock = PR_NewLock();
174 if (mLock == NULL) {
175 // Cannot create a lock. If running on a multiprocessing system
176 // we are sure to die.
177 PR_ASSERT(mLock != NULL);
178 }
179 }
180}
181
182
183nsHashtable::~nsHashtable() {
184 MOZ_COUNT_DTOR(nsHashtable);
185 if (mHashtable.ops)
186 PL_DHashTableFinish(&mHashtable);
187 if (mLock) PR_DestroyLock(mLock);
188}
189
190PRBool nsHashtable::Exists(nsHashKey *aKey)
191{
192 if (mLock) PR_Lock(mLock);
193
194 if (!mHashtable.ops)
195 return PR_FALSE;
196
197 PLDHashEntryHdr *entry =
198 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP);
199
200 PRBool exists = PL_DHASH_ENTRY_IS_BUSY(entry);
201
202 if (mLock) PR_Unlock(mLock);
203
204 return exists;
205}
206
207void *nsHashtable::Put(nsHashKey *aKey, void *aData)
208{
209 void *res = NULL;
210
211 if (!mHashtable.ops) return nsnull;
212
213 if (mLock) PR_Lock(mLock);
214
215 // shouldn't be adding an item during enumeration
216 PR_ASSERT(!mEnumerating);
217
218 HTEntry* entry =
219 NS_STATIC_CAST(HTEntry*,
220 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
221
222 if (entry) { // don't return early, or you'll be locked!
223 if (entry->key) {
224 // existing entry, need to boot the old value
225 res = entry->value;
226 entry->value = aData;
227 } else {
228 // new entry (leave res == null)
229 entry->key = aKey->Clone();
230 entry->value = aData;
231 }
232 }
233
234 if (mLock) PR_Unlock(mLock);
235
236 return res;
237}
238
239void *nsHashtable::Get(nsHashKey *aKey)
240{
241 if (!mHashtable.ops) return nsnull;
242
243 if (mLock) PR_Lock(mLock);
244
245 HTEntry* entry =
246 NS_STATIC_CAST(HTEntry*,
247 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
248 void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nsnull;
249
250 if (mLock) PR_Unlock(mLock);
251
252 return ret;
253}
254
255void *nsHashtable::Remove(nsHashKey *aKey)
256{
257 if (!mHashtable.ops) return nsnull;
258
259 if (mLock) PR_Lock(mLock);
260
261 // shouldn't be adding an item during enumeration
262 PR_ASSERT(!mEnumerating);
263
264
265 // need to see if the entry is actually there, in order to get the
266 // old value for the result
267 HTEntry* entry =
268 NS_STATIC_CAST(HTEntry*,
269 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
270 void *res;
271
272 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
273 // value wasn't in the table anyway
274 res = nsnull;
275 } else {
276 res = entry->value;
277 PL_DHashTableRawRemove(&mHashtable, entry);
278 }
279
280 if (mLock) PR_Unlock(mLock);
281
282 return res;
283}
284
285// XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
286// I don't know how this was supposed to work since the elements are neither copied
287// nor refcounted.
288PR_STATIC_CALLBACK(PLDHashOperator)
289hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr,
290 PRUint32 i, void *arg)
291{
292 nsHashtable *newHashtable = (nsHashtable *)arg;
293 HTEntry * entry = NS_STATIC_CAST(HTEntry*, hdr);
294
295 newHashtable->Put(entry->key, entry->value);
296 return PL_DHASH_NEXT;
297}
298
299nsHashtable * nsHashtable::Clone()
300{
301 if (!mHashtable.ops) return nsnull;
302
303 PRBool threadSafe = (mLock != nsnull);
304 nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe);
305
306 PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable);
307 return newHashTable;
308}
309
310void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
311{
312 if (!mHashtable.ops) return;
313
314 PRBool wasEnumerating = mEnumerating;
315 mEnumerating = PR_TRUE;
316 _HashEnumerateArgs thunk;
317 thunk.fn = aEnumFunc;
318 thunk.arg = aClosure;
319 PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk);
320 mEnumerating = wasEnumerating;
321}
322
323PR_STATIC_CALLBACK(PLDHashOperator)
324hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, PRUint32 i, void *arg)
325{
326 HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr);
327 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
328 if (thunk) {
329 return thunk->fn(entry->key, entry->value, thunk->arg)
330 ? PL_DHASH_REMOVE
331 : PL_DHASH_STOP;
332 }
333 return PL_DHASH_REMOVE;
334}
335
336void nsHashtable::Reset() {
337 Reset(NULL);
338}
339
340void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
341{
342 if (!mHashtable.ops) return;
343
344 _HashEnumerateArgs thunk, *thunkp;
345 if (!destroyFunc) {
346 thunkp = nsnull;
347 } else {
348 thunkp = &thunk;
349 thunk.fn = destroyFunc;
350 thunk.arg = aClosure;
351 }
352 PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp);
353}
354
355// nsISerializable helpers
356
357nsHashtable::nsHashtable(nsIObjectInputStream* aStream,
358 nsHashtableReadEntryFunc aReadEntryFunc,
359 nsHashtableFreeEntryFunc aFreeEntryFunc,
360 nsresult *aRetVal)
361 : mLock(nsnull),
362 mEnumerating(PR_FALSE)
363{
364 MOZ_COUNT_CTOR(nsHashtable);
365
366 PRBool threadSafe;
367 nsresult rv = aStream->ReadBoolean(&threadSafe);
368 if (NS_SUCCEEDED(rv)) {
369 if (threadSafe) {
370 mLock = PR_NewLock();
371 if (!mLock)
372 rv = NS_ERROR_OUT_OF_MEMORY;
373 }
374
375 if (NS_SUCCEEDED(rv)) {
376 PRUint32 count;
377 rv = aStream->Read32(&count);
378
379 if (NS_SUCCEEDED(rv)) {
380 PRBool status =
381 PL_DHashTableInit(&mHashtable, &hashtableOps,
382 nsnull, sizeof(HTEntry), count);
383 if (!status) {
384 mHashtable.ops = nsnull;
385 rv = NS_ERROR_OUT_OF_MEMORY;
386 } else {
387 for (PRUint32 i = 0; i < count; i++) {
388 nsHashKey* key;
389 void *data;
390
391 rv = aReadEntryFunc(aStream, &key, &data);
392 if (NS_SUCCEEDED(rv)) {
393 if (!Put(key, data)) {
394 rv = NS_ERROR_OUT_OF_MEMORY;
395 aFreeEntryFunc(aStream, key, data);
396 } else {
397 // XXXbe must we clone key? can't we hand off
398 aFreeEntryFunc(aStream, key, nsnull);
399 }
400 if (NS_FAILED(rv))
401 break;
402 }
403 }
404 }
405 }
406 }
407 }
408 *aRetVal = rv;
409}
410
411struct WriteEntryArgs {
412 nsIObjectOutputStream* mStream;
413 nsHashtableWriteDataFunc mWriteDataFunc;
414 nsresult mRetVal;
415};
416
417PR_STATIC_CALLBACK(PRBool)
418WriteEntry(nsHashKey *aKey, void *aData, void* aClosure)
419{
420 WriteEntryArgs* args = (WriteEntryArgs*) aClosure;
421 nsIObjectOutputStream* stream = args->mStream;
422
423 nsresult rv = aKey->Write(stream);
424 if (NS_SUCCEEDED(rv))
425 rv = args->mWriteDataFunc(stream, aData);
426
427 args->mRetVal = rv;
428 return PR_TRUE;
429}
430
431nsresult
432nsHashtable::Write(nsIObjectOutputStream* aStream,
433 nsHashtableWriteDataFunc aWriteDataFunc) const
434{
435 if (!mHashtable.ops)
436 return NS_ERROR_OUT_OF_MEMORY;
437 PRBool threadSafe = (mLock != nsnull);
438 nsresult rv = aStream->WriteBoolean(threadSafe);
439 if (NS_FAILED(rv)) return rv;
440
441 // Write the entry count first, so we know how many key/value pairs to read.
442 PRUint32 count = mHashtable.entryCount;
443 rv = aStream->Write32(count);
444 if (NS_FAILED(rv)) return rv;
445
446 // Write all key/value pairs in the table.
447 WriteEntryArgs args = {aStream, aWriteDataFunc};
448 NS_CONST_CAST(nsHashtable*, this)->Enumerate(WriteEntry, (void*) &args);
449 return args.mRetVal;
450}
451
452////////////////////////////////////////////////////////////////////////////////
453
454nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult)
455 : mKey(nsnull)
456{
457 PRBool nonnull;
458 nsresult rv = aStream->ReadBoolean(&nonnull);
459 if (NS_SUCCEEDED(rv) && nonnull)
460 rv = aStream->ReadObject(PR_TRUE, &mKey);
461 *aResult = rv;
462}
463
464nsresult
465nsISupportsKey::Write(nsIObjectOutputStream* aStream) const
466{
467 PRBool nonnull = (mKey != nsnull);
468 nsresult rv = aStream->WriteBoolean(nonnull);
469 if (NS_SUCCEEDED(rv) && nonnull)
470 rv = aStream->WriteObject(mKey, PR_TRUE);
471 return rv;
472}
473
474nsIDKey::nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult)
475{
476 *aResult = aStream->ReadID(&mID);
477}
478
479nsresult nsIDKey::Write(nsIObjectOutputStream* aStream) const
480{
481 return aStream->WriteID(mID);
482}
483
484////////////////////////////////////////////////////////////////////////////////
485
486// Copy Constructor
487// We need to free mStr if the object is passed with mOwnership as OWN. As the
488// destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
489
490nsCStringKey::nsCStringKey(const nsCStringKey& aKey)
491 : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
492{
493 if (mOwnership != NEVER_OWN) {
494 PRUint32 len = mStrLen * sizeof(char);
495 char* str = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(len + sizeof(char)));
496 if (!str) {
497 // Pray we don't dangle!
498 mOwnership = NEVER_OWN;
499 } else {
500 // Use memcpy in case there are embedded NULs.
501 memcpy(str, mStr, len);
502 str[mStrLen] = '\0';
503 mStr = str;
504 mOwnership = OWN;
505 }
506 }
507#ifdef DEBUG
508 mKeyType = CStringKey;
509#endif
510 MOZ_COUNT_CTOR(nsCStringKey);
511}
512
513nsCStringKey::nsCStringKey(const nsAFlatCString& str)
514 : mStr(NS_CONST_CAST(char*, str.get())),
515 mStrLen(str.Length()),
516 mOwnership(OWN_CLONE)
517{
518 NS_ASSERTION(mStr, "null string key");
519#ifdef DEBUG
520 mKeyType = CStringKey;
521#endif
522 MOZ_COUNT_CTOR(nsCStringKey);
523}
524
525nsCStringKey::nsCStringKey(const nsACString& str)
526 : mStr(ToNewCString(str)),
527 mStrLen(str.Length()),
528 mOwnership(OWN)
529{
530 NS_ASSERTION(mStr, "null string key");
531#ifdef DEBUG
532 mKeyType = CStringKey;
533#endif
534 MOZ_COUNT_CTOR(nsCStringKey);
535}
536
537nsCStringKey::nsCStringKey(const char* str, PRInt32 strLen, Ownership own)
538 : mStr((char*)str), mStrLen(strLen), mOwnership(own)
539{
540 NS_ASSERTION(mStr, "null string key");
541 if (mStrLen == PRUint32(-1))
542 mStrLen = strlen(str);
543#ifdef DEBUG
544 mKeyType = CStringKey;
545#endif
546 MOZ_COUNT_CTOR(nsCStringKey);
547}
548
549nsCStringKey::~nsCStringKey(void)
550{
551 if (mOwnership == OWN)
552 nsMemory::Free(mStr);
553 MOZ_COUNT_DTOR(nsCStringKey);
554}
555
556PRUint32
557nsCStringKey::HashCode(void) const
558{
559 return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen);
560}
561
562PRBool
563nsCStringKey::Equals(const nsHashKey* aKey) const
564{
565 NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types");
566 nsCStringKey* other = (nsCStringKey*)aKey;
567 NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode");
568 NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode");
569 if (mStrLen != other->mStrLen)
570 return PR_FALSE;
571 return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
572}
573
574nsHashKey*
575nsCStringKey::Clone() const
576{
577 if (mOwnership == NEVER_OWN)
578 return new nsCStringKey(mStr, mStrLen, NEVER_OWN);
579
580 // Since this might hold binary data OR a string, we ensure that the
581 // clone string is zero terminated, but don't assume that the source
582 // string was so terminated.
583
584 PRUint32 len = mStrLen * sizeof(char);
585 char* str = (char*)nsMemory::Alloc(len + sizeof(char));
586 if (str == NULL)
587 return NULL;
588 memcpy(str, mStr, len);
589 str[len] = 0;
590 return new nsCStringKey(str, mStrLen, OWN);
591}
592
593nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
594 : mStr(nsnull), mStrLen(0), mOwnership(OWN)
595{
596 nsCAutoString str;
597 nsresult rv = aStream->ReadCString(str);
598 mStr = ToNewCString(str);
599 if (NS_SUCCEEDED(rv))
600 mStrLen = str.Length();
601 *aResult = rv;
602 MOZ_COUNT_CTOR(nsCStringKey);
603}
604
605nsresult
606nsCStringKey::Write(nsIObjectOutputStream* aStream) const
607{
608 return aStream->WriteStringZ(mStr);
609}
610
611////////////////////////////////////////////////////////////////////////////////
612
613// Copy Constructor
614// We need to free mStr if the object is passed with mOwnership as OWN. As the
615// destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
616
617nsStringKey::nsStringKey(const nsStringKey& aKey)
618 : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
619{
620 if (mOwnership != NEVER_OWN) {
621 PRUint32 len = mStrLen * sizeof(PRUnichar);
622 PRUnichar* str = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(len + sizeof(PRUnichar)));
623 if (!str) {
624 // Pray we don't dangle!
625 mOwnership = NEVER_OWN;
626 } else {
627 // Use memcpy in case there are embedded NULs.
628 memcpy(str, mStr, len);
629 str[mStrLen] = 0;
630 mStr = str;
631 mOwnership = OWN;
632 }
633 }
634#ifdef DEBUG
635 mKeyType = StringKey;
636#endif
637 MOZ_COUNT_CTOR(nsStringKey);
638}
639
640nsStringKey::nsStringKey(const nsAFlatString& str)
641 : mStr(NS_CONST_CAST(PRUnichar*, str.get())),
642 mStrLen(str.Length()),
643 mOwnership(OWN_CLONE)
644{
645 NS_ASSERTION(mStr, "null string key");
646#ifdef DEBUG
647 mKeyType = StringKey;
648#endif
649 MOZ_COUNT_CTOR(nsStringKey);
650}
651
652nsStringKey::nsStringKey(const nsAString& str)
653 : mStr(ToNewUnicode(str)),
654 mStrLen(str.Length()),
655 mOwnership(OWN)
656{
657 NS_ASSERTION(mStr, "null string key");
658#ifdef DEBUG
659 mKeyType = StringKey;
660#endif
661 MOZ_COUNT_CTOR(nsStringKey);
662}
663
664nsStringKey::nsStringKey(const PRUnichar* str, PRInt32 strLen, Ownership own)
665 : mStr((PRUnichar*)str), mStrLen(strLen), mOwnership(own)
666{
667 NS_ASSERTION(mStr, "null string key");
668 if (mStrLen == PRUint32(-1))
669 mStrLen = nsCRT::strlen(str);
670#ifdef DEBUG
671 mKeyType = StringKey;
672#endif
673 MOZ_COUNT_CTOR(nsStringKey);
674}
675
676nsStringKey::~nsStringKey(void)
677{
678 if (mOwnership == OWN)
679 nsMemory::Free(mStr);
680 MOZ_COUNT_DTOR(nsStringKey);
681}
682
683PRUint32
684nsStringKey::HashCode(void) const
685{
686 return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen);
687}
688
689PRBool
690nsStringKey::Equals(const nsHashKey* aKey) const
691{
692 NS_ASSERTION(aKey->GetKeyType() == StringKey, "mismatched key types");
693 nsStringKey* other = (nsStringKey*)aKey;
694 NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode");
695 NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode");
696 if (mStrLen != other->mStrLen)
697 return PR_FALSE;
698 return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0;
699}
700
701nsHashKey*
702nsStringKey::Clone() const
703{
704 if (mOwnership == NEVER_OWN)
705 return new nsStringKey(mStr, mStrLen, NEVER_OWN);
706
707 PRUint32 len = (mStrLen+1) * sizeof(PRUnichar);
708 PRUnichar* str = (PRUnichar*)nsMemory::Alloc(len);
709 if (str == NULL)
710 return NULL;
711 memcpy(str, mStr, len);
712 return new nsStringKey(str, mStrLen, OWN);
713}
714
715nsStringKey::nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
716 : mStr(nsnull), mStrLen(0), mOwnership(OWN)
717{
718 nsAutoString str;
719 nsresult rv = aStream->ReadString(str);
720 mStr = ToNewUnicode(str);
721 if (NS_SUCCEEDED(rv))
722 mStrLen = str.Length();
723 *aResult = rv;
724 MOZ_COUNT_CTOR(nsStringKey);
725}
726
727nsresult
728nsStringKey::Write(nsIObjectOutputStream* aStream) const
729{
730 return aStream->WriteWStringZ(mStr);
731}
732
733////////////////////////////////////////////////////////////////////////////////
734// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
735// deleted
736
737nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
738 void* cloneElementClosure,
739 nsHashtableEnumFunc destroyElementFun,
740 void* destroyElementClosure,
741 PRUint32 aSize, PRBool threadSafe)
742 : nsHashtable(aSize, threadSafe),
743 mCloneElementFun(cloneElementFun),
744 mCloneElementClosure(cloneElementClosure),
745 mDestroyElementFun(destroyElementFun),
746 mDestroyElementClosure(destroyElementClosure)
747{
748}
749
750nsObjectHashtable::~nsObjectHashtable()
751{
752 Reset();
753}
754
755
756PLDHashOperator PR_CALLBACK
757nsObjectHashtable::CopyElement(PLDHashTable* table,
758 PLDHashEntryHdr* hdr,
759 PRUint32 i, void *arg)
760{
761 nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
762 HTEntry *entry = NS_STATIC_CAST(HTEntry*, hdr);
763
764 void* newElement =
765 newHashtable->mCloneElementFun(entry->key, entry->value,
766 newHashtable->mCloneElementClosure);
767 if (newElement == nsnull)
768 return PL_DHASH_STOP;
769 newHashtable->Put(entry->key, newElement);
770 return PL_DHASH_NEXT;
771}
772
773nsHashtable*
774nsObjectHashtable::Clone()
775{
776 if (!mHashtable.ops) return nsnull;
777
778 PRBool threadSafe = PR_FALSE;
779 if (mLock)
780 threadSafe = PR_TRUE;
781 nsObjectHashtable* newHashTable =
782 new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
783 mDestroyElementFun, mDestroyElementClosure,
784 mHashtable.entryCount, threadSafe);
785
786 PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
787 return newHashTable;
788}
789
790void
791nsObjectHashtable::Reset()
792{
793 nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
794}
795
796PRBool
797nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
798{
799 void *value = Remove(aKey);
800 if (value && mDestroyElementFun)
801 return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
802 return PR_FALSE;
803}
804
805////////////////////////////////////////////////////////////////////////////////
806// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
807
808PRBool PR_CALLBACK
809nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure)
810{
811 nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
812 NS_IF_RELEASE(element);
813 return PR_TRUE;
814}
815
816nsSupportsHashtable::~nsSupportsHashtable()
817{
818 Enumerate(ReleaseElement, nsnull);
819}
820
821// Return true if we overwrote something
822
823PRBool
824nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value)
825{
826 NS_IF_ADDREF(aData);
827 void *prev = nsHashtable::Put(aKey, aData);
828 nsISupports *old = NS_REINTERPRET_CAST(nsISupports *, prev);
829 if (value) // pass own the ownership to the caller
830 *value = old;
831 else // the caller doesn't care, we do
832 NS_IF_RELEASE(old);
833 return prev != nsnull;
834}
835
836nsISupports *
837nsSupportsHashtable::Get(nsHashKey *aKey)
838{
839 void* data = nsHashtable::Get(aKey);
840 if (!data)
841 return nsnull;
842 nsISupports* element = NS_REINTERPRET_CAST(nsISupports*, data);
843 NS_IF_ADDREF(element);
844 return element;
845}
846
847// Return true if we found something (useful for checks)
848
849PRBool
850nsSupportsHashtable::Remove(nsHashKey *aKey, nsISupports **value)
851{
852 void* data = nsHashtable::Remove(aKey);
853 nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
854 if (value) // caller wants it
855 *value = element;
856 else // caller doesn't care, we do
857 NS_IF_RELEASE(element);
858 return data != nsnull;
859}
860
861PLDHashOperator PR_CALLBACK
862nsSupportsHashtable::EnumerateCopy(PLDHashTable*,
863 PLDHashEntryHdr* hdr,
864 PRUint32 i, void *arg)
865{
866 nsHashtable *newHashtable = (nsHashtable *)arg;
867 HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr);
868
869 nsISupports* element = NS_STATIC_CAST(nsISupports*, entry->value);
870 NS_IF_ADDREF(element);
871 newHashtable->Put(entry->key, entry->value);
872 return PL_DHASH_NEXT;
873}
874
875nsHashtable*
876nsSupportsHashtable::Clone()
877{
878 if (!mHashtable.ops) return nsnull;
879
880 PRBool threadSafe = (mLock != nsnull);
881 nsSupportsHashtable* newHashTable =
882 new nsSupportsHashtable(mHashtable.entryCount, threadSafe);
883
884 PL_DHashTableEnumerate(&mHashtable, EnumerateCopy, newHashTable);
885 return newHashTable;
886}
887
888void
889nsSupportsHashtable::Reset()
890{
891 Enumerate(ReleaseElement, nsnull);
892 nsHashtable::Reset();
893}
894
895////////////////////////////////////////////////////////////////////////////////
896
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use