VirtualBox

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

最後變更 在這個檔案從104488是 101997,由 vboxsync 提交於 13 月 前

libs/xpcom/xpcom: Convert from PR_ASSERT to IPRT assertions, bugref:10545

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

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