VirtualBox

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

Last change on this file since 101975 was 101975, checked in by vboxsync, 12 months ago

libs/xpcom/xpcom: Convert some code from using PRLock to IPRT's RTSEMFASTMUTEX locks, bugref:10545

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette