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