xpcom/ds/nsHashtable.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/ds/nsHashtable.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,608 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.8 + * This Original Code has been modified by IBM Corporation.
     1.9 + * Modifications made by IBM described herein are
    1.10 + * Copyright (c) International Business Machines
    1.11 + * Corporation, 2000
    1.12 + *
    1.13 + * Modifications to Mozilla code or documentation
    1.14 + * identified per MPL Section 3.3
    1.15 + *
    1.16 + * Date         Modified by     Description of modification
    1.17 + * 04/20/2000   IBM Corp.       Added PR_CALLBACK for Optlink use in OS2
    1.18 + */
    1.19 +
    1.20 +#include <string.h>
    1.21 +#include "prlog.h"
    1.22 +#include "prlock.h"
    1.23 +#include "nsHashtable.h"
    1.24 +#include "nsIObjectInputStream.h"
    1.25 +#include "nsIObjectOutputStream.h"
    1.26 +#include "nsCRTGlue.h"
    1.27 +#include "mozilla/HashFunctions.h"
    1.28 +
    1.29 +using namespace mozilla;
    1.30 +
    1.31 +struct HTEntry : PLDHashEntryHdr
    1.32 +{
    1.33 +    nsHashKey* key;
    1.34 +    void* value;
    1.35 +};
    1.36 +
    1.37 +//
    1.38 +// Key operations
    1.39 +//
    1.40 +
    1.41 +static bool
    1.42 +matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
    1.43 +              const void* key)
    1.44 +{
    1.45 +    const HTEntry* hashEntry =
    1.46 +        static_cast<const HTEntry*>(entry);
    1.47 +
    1.48 +    if (hashEntry->key == key)
    1.49 +        return true;
    1.50 +
    1.51 +    const nsHashKey* otherKey = reinterpret_cast<const nsHashKey*>(key);
    1.52 +    return otherKey->Equals(hashEntry->key);
    1.53 +}
    1.54 +
    1.55 +static PLDHashNumber
    1.56 +hashKey(PLDHashTable* table, const void* key)
    1.57 +{
    1.58 +    const nsHashKey* hashKey = static_cast<const nsHashKey*>(key);
    1.59 +
    1.60 +    return hashKey->HashCode();
    1.61 +}
    1.62 +
    1.63 +static void
    1.64 +clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry)
    1.65 +{
    1.66 +    HTEntry* hashEntry = static_cast<HTEntry*>(entry);
    1.67 +
    1.68 +    // leave it up to the nsHashKey destructor to free the "value"
    1.69 +    delete hashEntry->key;
    1.70 +    hashEntry->key = nullptr;
    1.71 +    hashEntry->value = nullptr;  // probably not necessary, but for
    1.72 +                                // sanity's sake
    1.73 +}
    1.74 +
    1.75 +
    1.76 +static const PLDHashTableOps hashtableOps = {
    1.77 +    PL_DHashAllocTable,
    1.78 +    PL_DHashFreeTable,
    1.79 +    hashKey,
    1.80 +    matchKeyEntry,
    1.81 +    PL_DHashMoveEntryStub,
    1.82 +    clearHashEntry,
    1.83 +    PL_DHashFinalizeStub,
    1.84 +    nullptr,
    1.85 +};
    1.86 +
    1.87 +
    1.88 +//
    1.89 +// Enumerator callback
    1.90 +//
    1.91 +
    1.92 +struct _HashEnumerateArgs {
    1.93 +    nsHashtableEnumFunc fn;
    1.94 +    void* arg;
    1.95 +};
    1.96 +
    1.97 +static PLDHashOperator
    1.98 +hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, uint32_t i, void *arg)
    1.99 +{
   1.100 +    _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
   1.101 +    HTEntry* entry = static_cast<HTEntry*>(hdr);
   1.102 +
   1.103 +    if (thunk->fn(entry->key, entry->value, thunk->arg))
   1.104 +        return PL_DHASH_NEXT;
   1.105 +    return PL_DHASH_STOP;
   1.106 +}
   1.107 +
   1.108 +//
   1.109 +// HashKey
   1.110 +//
   1.111 +
   1.112 +nsHashKey::~nsHashKey(void)
   1.113 +{
   1.114 +    MOZ_COUNT_DTOR(nsHashKey);
   1.115 +}
   1.116 +
   1.117 +nsresult
   1.118 +nsHashKey::Write(nsIObjectOutputStream* aStream) const
   1.119 +{
   1.120 +    NS_NOTREACHED("oops");
   1.121 +    return NS_ERROR_NOT_IMPLEMENTED;
   1.122 +}
   1.123 +
   1.124 +nsHashtable::nsHashtable(uint32_t aInitSize, bool aThreadSafe)
   1.125 +  : mLock(nullptr), mEnumerating(false)
   1.126 +{
   1.127 +    MOZ_COUNT_CTOR(nsHashtable);
   1.128 +
   1.129 +    bool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nullptr,
   1.130 +                                    sizeof(HTEntry), aInitSize, fallible_t());
   1.131 +    NS_ASSERTION(result, "Hashtable failed to initialize");
   1.132 +
   1.133 +    // make sure we detect this later
   1.134 +    if (!result)
   1.135 +        mHashtable.ops = nullptr;
   1.136 +
   1.137 +    if (aThreadSafe) {
   1.138 +        mLock = PR_NewLock();
   1.139 +        if (mLock == nullptr) {
   1.140 +            // Cannot create a lock. If running on a multiprocessing system
   1.141 +            // we are sure to die.
   1.142 +            PR_ASSERT(mLock != nullptr);
   1.143 +        }
   1.144 +    }
   1.145 +}
   1.146 +
   1.147 +nsHashtable::~nsHashtable() {
   1.148 +    MOZ_COUNT_DTOR(nsHashtable);
   1.149 +    if (mHashtable.ops)
   1.150 +        PL_DHashTableFinish(&mHashtable);
   1.151 +    if (mLock) PR_DestroyLock(mLock);
   1.152 +}
   1.153 +
   1.154 +bool nsHashtable::Exists(nsHashKey *aKey)
   1.155 +{
   1.156 +    if (mLock) PR_Lock(mLock);
   1.157 +
   1.158 +    if (!mHashtable.ops) {
   1.159 +        if (mLock) PR_Unlock(mLock);
   1.160 +        return false;
   1.161 +    }
   1.162 +
   1.163 +    PLDHashEntryHdr *entry =
   1.164 +        PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP);
   1.165 +
   1.166 +    bool exists = PL_DHASH_ENTRY_IS_BUSY(entry);
   1.167 +
   1.168 +    if (mLock) PR_Unlock(mLock);
   1.169 +
   1.170 +    return exists;
   1.171 +}
   1.172 +
   1.173 +void *nsHashtable::Put(nsHashKey *aKey, void *aData)
   1.174 +{
   1.175 +    void *res =  nullptr;
   1.176 +
   1.177 +    if (!mHashtable.ops) return nullptr;
   1.178 +
   1.179 +    if (mLock) PR_Lock(mLock);
   1.180 +
   1.181 +    // shouldn't be adding an item during enumeration
   1.182 +    PR_ASSERT(!mEnumerating);
   1.183 +
   1.184 +    HTEntry* entry =
   1.185 +        static_cast<HTEntry*>
   1.186 +                   (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
   1.187 +
   1.188 +    if (entry) {                // don't return early, or you'll be locked!
   1.189 +        if (entry->key) {
   1.190 +            // existing entry, need to boot the old value
   1.191 +            res = entry->value;
   1.192 +            entry->value = aData;
   1.193 +        } else {
   1.194 +            // new entry (leave res == null)
   1.195 +            entry->key = aKey->Clone();
   1.196 +            entry->value = aData;
   1.197 +        }
   1.198 +    }
   1.199 +
   1.200 +    if (mLock) PR_Unlock(mLock);
   1.201 +
   1.202 +    return res;
   1.203 +}
   1.204 +
   1.205 +void *nsHashtable::Get(nsHashKey *aKey)
   1.206 +{
   1.207 +    if (!mHashtable.ops) return nullptr;
   1.208 +
   1.209 +    if (mLock) PR_Lock(mLock);
   1.210 +
   1.211 +    HTEntry* entry =
   1.212 +        static_cast<HTEntry*>
   1.213 +                   (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
   1.214 +    void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nullptr;
   1.215 +
   1.216 +    if (mLock) PR_Unlock(mLock);
   1.217 +
   1.218 +    return ret;
   1.219 +}
   1.220 +
   1.221 +void *nsHashtable::Remove(nsHashKey *aKey)
   1.222 +{
   1.223 +    if (!mHashtable.ops) return nullptr;
   1.224 +
   1.225 +    if (mLock) PR_Lock(mLock);
   1.226 +
   1.227 +    // shouldn't be adding an item during enumeration
   1.228 +    PR_ASSERT(!mEnumerating);
   1.229 +
   1.230 +
   1.231 +    // need to see if the entry is actually there, in order to get the
   1.232 +    // old value for the result
   1.233 +    HTEntry* entry =
   1.234 +        static_cast<HTEntry*>
   1.235 +                   (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
   1.236 +    void *res;
   1.237 +
   1.238 +    if (PL_DHASH_ENTRY_IS_FREE(entry)) {
   1.239 +        // value wasn't in the table anyway
   1.240 +        res = nullptr;
   1.241 +    } else {
   1.242 +        res = entry->value;
   1.243 +        PL_DHashTableRawRemove(&mHashtable, entry);
   1.244 +    }
   1.245 +
   1.246 +    if (mLock) PR_Unlock(mLock);
   1.247 +
   1.248 +    return res;
   1.249 +}
   1.250 +
   1.251 +// XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
   1.252 +// I don't know how this was supposed to work since the elements are neither copied
   1.253 +// nor refcounted.
   1.254 +static PLDHashOperator
   1.255 +hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr,
   1.256 +                   uint32_t i, void *arg)
   1.257 +{
   1.258 +    nsHashtable *newHashtable = (nsHashtable *)arg;
   1.259 +    HTEntry * entry = static_cast<HTEntry*>(hdr);
   1.260 +
   1.261 +    newHashtable->Put(entry->key, entry->value);
   1.262 +    return PL_DHASH_NEXT;
   1.263 +}
   1.264 +
   1.265 +nsHashtable * nsHashtable::Clone()
   1.266 +{
   1.267 +    if (!mHashtable.ops) return nullptr;
   1.268 +
   1.269 +    bool threadSafe = (mLock != nullptr);
   1.270 +    nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe);
   1.271 +
   1.272 +    PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable);
   1.273 +    return newHashTable;
   1.274 +}
   1.275 +
   1.276 +void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
   1.277 +{
   1.278 +    if (!mHashtable.ops) return;
   1.279 +
   1.280 +    bool wasEnumerating = mEnumerating;
   1.281 +    mEnumerating = true;
   1.282 +    _HashEnumerateArgs thunk;
   1.283 +    thunk.fn = aEnumFunc;
   1.284 +    thunk.arg = aClosure;
   1.285 +    PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk);
   1.286 +    mEnumerating = wasEnumerating;
   1.287 +}
   1.288 +
   1.289 +static PLDHashOperator
   1.290 +hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, uint32_t i, void *arg)
   1.291 +{
   1.292 +    HTEntry* entry = static_cast<HTEntry*>(hdr);
   1.293 +    _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
   1.294 +    if (thunk) {
   1.295 +        return thunk->fn(entry->key, entry->value, thunk->arg)
   1.296 +            ? PL_DHASH_REMOVE
   1.297 +            : PL_DHASH_STOP;
   1.298 +    }
   1.299 +    return PL_DHASH_REMOVE;
   1.300 +}
   1.301 +
   1.302 +void nsHashtable::Reset() {
   1.303 +    Reset(nullptr);
   1.304 +}
   1.305 +
   1.306 +void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
   1.307 +{
   1.308 +    if (!mHashtable.ops) return;
   1.309 +
   1.310 +    _HashEnumerateArgs thunk, *thunkp;
   1.311 +    if (!destroyFunc) {
   1.312 +        thunkp = nullptr;
   1.313 +    } else {
   1.314 +        thunkp = &thunk;
   1.315 +        thunk.fn = destroyFunc;
   1.316 +        thunk.arg = aClosure;
   1.317 +    }
   1.318 +    PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp);
   1.319 +}
   1.320 +
   1.321 +// nsISerializable helpers
   1.322 +
   1.323 +nsHashtable::nsHashtable(nsIObjectInputStream* aStream,
   1.324 +                         nsHashtableReadEntryFunc aReadEntryFunc,
   1.325 +                         nsHashtableFreeEntryFunc aFreeEntryFunc,
   1.326 +                         nsresult *aRetVal)
   1.327 +  : mLock(nullptr),
   1.328 +    mEnumerating(false)
   1.329 +{
   1.330 +    MOZ_COUNT_CTOR(nsHashtable);
   1.331 +
   1.332 +    bool threadSafe;
   1.333 +    nsresult rv = aStream->ReadBoolean(&threadSafe);
   1.334 +    if (NS_SUCCEEDED(rv)) {
   1.335 +        if (threadSafe) {
   1.336 +            mLock = PR_NewLock();
   1.337 +            if (!mLock)
   1.338 +                rv = NS_ERROR_OUT_OF_MEMORY;
   1.339 +        }
   1.340 +
   1.341 +        if (NS_SUCCEEDED(rv)) {
   1.342 +            uint32_t count;
   1.343 +            rv = aStream->Read32(&count);
   1.344 +
   1.345 +            if (NS_SUCCEEDED(rv)) {
   1.346 +                bool status =
   1.347 +                    PL_DHashTableInit(&mHashtable, &hashtableOps,
   1.348 +                                      nullptr, sizeof(HTEntry), count,
   1.349 +                                      fallible_t());
   1.350 +                if (!status) {
   1.351 +                    mHashtable.ops = nullptr;
   1.352 +                    rv = NS_ERROR_OUT_OF_MEMORY;
   1.353 +                } else {
   1.354 +                    for (uint32_t i = 0; i < count; i++) {
   1.355 +                        nsHashKey* key;
   1.356 +                        void *data;
   1.357 +
   1.358 +                        rv = aReadEntryFunc(aStream, &key, &data);
   1.359 +                        if (NS_SUCCEEDED(rv)) {
   1.360 +                            Put(key, data);
   1.361 +
   1.362 +                            // XXXbe must we clone key? can't we hand off
   1.363 +                            aFreeEntryFunc(aStream, key, nullptr);
   1.364 +                        }
   1.365 +                    }
   1.366 +                }
   1.367 +            }
   1.368 +        }
   1.369 +    }
   1.370 +    *aRetVal = rv;
   1.371 +}
   1.372 +
   1.373 +struct WriteEntryArgs {
   1.374 +    nsIObjectOutputStream*    mStream;
   1.375 +    nsHashtableWriteDataFunc  mWriteDataFunc;
   1.376 +    nsresult                  mRetVal;
   1.377 +};
   1.378 +
   1.379 +static bool
   1.380 +WriteEntry(nsHashKey *aKey, void *aData, void* aClosure)
   1.381 +{
   1.382 +    WriteEntryArgs* args = (WriteEntryArgs*) aClosure;
   1.383 +    nsIObjectOutputStream* stream = args->mStream;
   1.384 +
   1.385 +    nsresult rv = aKey->Write(stream);
   1.386 +    if (NS_SUCCEEDED(rv))
   1.387 +        rv = args->mWriteDataFunc(stream, aData);
   1.388 +
   1.389 +    args->mRetVal = rv;
   1.390 +    return true;
   1.391 +}
   1.392 +
   1.393 +nsresult
   1.394 +nsHashtable::Write(nsIObjectOutputStream* aStream,
   1.395 +                   nsHashtableWriteDataFunc aWriteDataFunc) const
   1.396 +{
   1.397 +    if (!mHashtable.ops)
   1.398 +        return NS_ERROR_OUT_OF_MEMORY;
   1.399 +    bool threadSafe = (mLock != nullptr);
   1.400 +    nsresult rv = aStream->WriteBoolean(threadSafe);
   1.401 +    if (NS_FAILED(rv)) return rv;
   1.402 +
   1.403 +    // Write the entry count first, so we know how many key/value pairs to read.
   1.404 +    uint32_t count = mHashtable.entryCount;
   1.405 +    rv = aStream->Write32(count);
   1.406 +    if (NS_FAILED(rv)) return rv;
   1.407 +
   1.408 +    // Write all key/value pairs in the table.
   1.409 +    WriteEntryArgs args = {aStream, aWriteDataFunc};
   1.410 +    const_cast<nsHashtable*>(this)->Enumerate(WriteEntry, (void*) &args);
   1.411 +    return args.mRetVal;
   1.412 +}
   1.413 +
   1.414 +////////////////////////////////////////////////////////////////////////////////
   1.415 +
   1.416 +// Copy Constructor
   1.417 +// We need to free mStr if the object is passed with mOwnership as OWN. As the
   1.418 +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
   1.419 +
   1.420 +nsCStringKey::nsCStringKey(const nsCStringKey& aKey)
   1.421 +    : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
   1.422 +{
   1.423 +    if (mOwnership != NEVER_OWN) {
   1.424 +      uint32_t len = mStrLen * sizeof(char);
   1.425 +      char* str = reinterpret_cast<char*>(nsMemory::Alloc(len + sizeof(char)));
   1.426 +      if (!str) {
   1.427 +        // Pray we don't dangle!
   1.428 +        mOwnership = NEVER_OWN;
   1.429 +      } else {
   1.430 +        // Use memcpy in case there are embedded NULs.
   1.431 +        memcpy(str, mStr, len);
   1.432 +        str[mStrLen] = '\0';
   1.433 +        mStr = str;
   1.434 +        mOwnership = OWN;
   1.435 +      }
   1.436 +    }
   1.437 +#ifdef DEBUG
   1.438 +    mKeyType = CStringKey;
   1.439 +#endif
   1.440 +    MOZ_COUNT_CTOR(nsCStringKey);
   1.441 +}
   1.442 +
   1.443 +nsCStringKey::nsCStringKey(const nsAFlatCString& str)
   1.444 +    : mStr(const_cast<char*>(str.get())),
   1.445 +      mStrLen(str.Length()),
   1.446 +      mOwnership(OWN_CLONE)
   1.447 +{
   1.448 +    NS_ASSERTION(mStr, "null string key");
   1.449 +#ifdef DEBUG
   1.450 +    mKeyType = CStringKey;
   1.451 +#endif
   1.452 +    MOZ_COUNT_CTOR(nsCStringKey);
   1.453 +}
   1.454 +
   1.455 +nsCStringKey::nsCStringKey(const nsACString& str)
   1.456 +    : mStr(ToNewCString(str)),
   1.457 +      mStrLen(str.Length()),
   1.458 +      mOwnership(OWN)
   1.459 +{
   1.460 +    NS_ASSERTION(mStr, "null string key");
   1.461 +#ifdef DEBUG
   1.462 +    mKeyType = CStringKey;
   1.463 +#endif
   1.464 +    MOZ_COUNT_CTOR(nsCStringKey);
   1.465 +}
   1.466 +
   1.467 +nsCStringKey::nsCStringKey(const char* str, int32_t strLen, Ownership own)
   1.468 +    : mStr((char*)str), mStrLen(strLen), mOwnership(own)
   1.469 +{
   1.470 +    NS_ASSERTION(mStr, "null string key");
   1.471 +    if (mStrLen == uint32_t(-1))
   1.472 +        mStrLen = strlen(str);
   1.473 +#ifdef DEBUG
   1.474 +    mKeyType = CStringKey;
   1.475 +#endif
   1.476 +    MOZ_COUNT_CTOR(nsCStringKey);
   1.477 +}
   1.478 +
   1.479 +nsCStringKey::~nsCStringKey(void)
   1.480 +{
   1.481 +    if (mOwnership == OWN)
   1.482 +        nsMemory::Free(mStr);
   1.483 +    MOZ_COUNT_DTOR(nsCStringKey);
   1.484 +}
   1.485 +
   1.486 +uint32_t
   1.487 +nsCStringKey::HashCode(void) const
   1.488 +{
   1.489 +    return HashString(mStr, mStrLen);
   1.490 +}
   1.491 +
   1.492 +bool
   1.493 +nsCStringKey::Equals(const nsHashKey* aKey) const
   1.494 +{
   1.495 +    NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types");
   1.496 +    nsCStringKey* other = (nsCStringKey*)aKey;
   1.497 +    NS_ASSERTION(mStrLen != uint32_t(-1), "never called HashCode");
   1.498 +    NS_ASSERTION(other->mStrLen != uint32_t(-1), "never called HashCode");
   1.499 +    if (mStrLen != other->mStrLen)
   1.500 +        return false;
   1.501 +    return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
   1.502 +}
   1.503 +
   1.504 +nsHashKey*
   1.505 +nsCStringKey::Clone() const
   1.506 +{
   1.507 +    if (mOwnership == NEVER_OWN)
   1.508 +        return new nsCStringKey(mStr, mStrLen, NEVER_OWN);
   1.509 +
   1.510 +    // Since this might hold binary data OR a string, we ensure that the
   1.511 +    // clone string is zero terminated, but don't assume that the source
   1.512 +    // string was so terminated.
   1.513 +
   1.514 +    uint32_t len = mStrLen * sizeof(char);
   1.515 +    char* str = (char*)nsMemory::Alloc(len + sizeof(char));
   1.516 +    if (str == nullptr)
   1.517 +        return nullptr;
   1.518 +    memcpy(str, mStr, len);
   1.519 +    str[len] = 0;
   1.520 +    return new nsCStringKey(str, mStrLen, OWN);
   1.521 +}
   1.522 +
   1.523 +nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
   1.524 +    : mStr(nullptr), mStrLen(0), mOwnership(OWN)
   1.525 +{
   1.526 +    nsAutoCString str;
   1.527 +    nsresult rv = aStream->ReadCString(str);
   1.528 +    mStr = ToNewCString(str);
   1.529 +    if (NS_SUCCEEDED(rv))
   1.530 +        mStrLen = str.Length();
   1.531 +    *aResult = rv;
   1.532 +    MOZ_COUNT_CTOR(nsCStringKey);
   1.533 +}
   1.534 +
   1.535 +nsresult
   1.536 +nsCStringKey::Write(nsIObjectOutputStream* aStream) const
   1.537 +{
   1.538 +    return aStream->WriteStringZ(mStr);
   1.539 +}
   1.540 +
   1.541 +////////////////////////////////////////////////////////////////////////////////
   1.542 +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
   1.543 +// deleted
   1.544 +
   1.545 +nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
   1.546 +                                     void* cloneElementClosure,
   1.547 +                                     nsHashtableEnumFunc destroyElementFun,
   1.548 +                                     void* destroyElementClosure,
   1.549 +                                     uint32_t aSize, bool threadSafe)
   1.550 +    : nsHashtable(aSize, threadSafe),
   1.551 +      mCloneElementFun(cloneElementFun),
   1.552 +      mCloneElementClosure(cloneElementClosure),
   1.553 +      mDestroyElementFun(destroyElementFun),
   1.554 +      mDestroyElementClosure(destroyElementClosure)
   1.555 +{
   1.556 +}
   1.557 +
   1.558 +nsObjectHashtable::~nsObjectHashtable()
   1.559 +{
   1.560 +    Reset();
   1.561 +}
   1.562 +
   1.563 +
   1.564 +PLDHashOperator
   1.565 +nsObjectHashtable::CopyElement(PLDHashTable* table,
   1.566 +                               PLDHashEntryHdr* hdr,
   1.567 +                               uint32_t i, void *arg)
   1.568 +{
   1.569 +    nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
   1.570 +    HTEntry *entry = static_cast<HTEntry*>(hdr);
   1.571 +
   1.572 +    void* newElement =
   1.573 +        newHashtable->mCloneElementFun(entry->key, entry->value,
   1.574 +                                       newHashtable->mCloneElementClosure);
   1.575 +    if (newElement == nullptr)
   1.576 +        return PL_DHASH_STOP;
   1.577 +    newHashtable->Put(entry->key, newElement);
   1.578 +    return PL_DHASH_NEXT;
   1.579 +}
   1.580 +
   1.581 +nsHashtable*
   1.582 +nsObjectHashtable::Clone()
   1.583 +{
   1.584 +    if (!mHashtable.ops) return nullptr;
   1.585 +
   1.586 +    bool threadSafe = false;
   1.587 +    if (mLock)
   1.588 +        threadSafe = true;
   1.589 +    nsObjectHashtable* newHashTable =
   1.590 +        new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
   1.591 +                              mDestroyElementFun, mDestroyElementClosure,
   1.592 +                              mHashtable.entryCount, threadSafe);
   1.593 +
   1.594 +    PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
   1.595 +    return newHashTable;
   1.596 +}
   1.597 +
   1.598 +void
   1.599 +nsObjectHashtable::Reset()
   1.600 +{
   1.601 +    nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
   1.602 +}
   1.603 +
   1.604 +bool
   1.605 +nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
   1.606 +{
   1.607 +    void *value = Remove(aKey);
   1.608 +    if (value && mDestroyElementFun)
   1.609 +        return !!(*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
   1.610 +    return false;
   1.611 +}

mercurial