~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpcom/ds/nsHashtable.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

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