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 +}