xpcom/ds/nsHashtable.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 5 * This Original Code has been modified by IBM Corporation.
michael@0 6 * Modifications made by IBM described herein are
michael@0 7 * Copyright (c) International Business Machines
michael@0 8 * Corporation, 2000
michael@0 9 *
michael@0 10 * Modifications to Mozilla code or documentation
michael@0 11 * identified per MPL Section 3.3
michael@0 12 *
michael@0 13 * Date Modified by Description of modification
michael@0 14 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
michael@0 15 */
michael@0 16
michael@0 17 #include <string.h>
michael@0 18 #include "prlog.h"
michael@0 19 #include "prlock.h"
michael@0 20 #include "nsHashtable.h"
michael@0 21 #include "nsIObjectInputStream.h"
michael@0 22 #include "nsIObjectOutputStream.h"
michael@0 23 #include "nsCRTGlue.h"
michael@0 24 #include "mozilla/HashFunctions.h"
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27
michael@0 28 struct HTEntry : PLDHashEntryHdr
michael@0 29 {
michael@0 30 nsHashKey* key;
michael@0 31 void* value;
michael@0 32 };
michael@0 33
michael@0 34 //
michael@0 35 // Key operations
michael@0 36 //
michael@0 37
michael@0 38 static bool
michael@0 39 matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
michael@0 40 const void* key)
michael@0 41 {
michael@0 42 const HTEntry* hashEntry =
michael@0 43 static_cast<const HTEntry*>(entry);
michael@0 44
michael@0 45 if (hashEntry->key == key)
michael@0 46 return true;
michael@0 47
michael@0 48 const nsHashKey* otherKey = reinterpret_cast<const nsHashKey*>(key);
michael@0 49 return otherKey->Equals(hashEntry->key);
michael@0 50 }
michael@0 51
michael@0 52 static PLDHashNumber
michael@0 53 hashKey(PLDHashTable* table, const void* key)
michael@0 54 {
michael@0 55 const nsHashKey* hashKey = static_cast<const nsHashKey*>(key);
michael@0 56
michael@0 57 return hashKey->HashCode();
michael@0 58 }
michael@0 59
michael@0 60 static void
michael@0 61 clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry)
michael@0 62 {
michael@0 63 HTEntry* hashEntry = static_cast<HTEntry*>(entry);
michael@0 64
michael@0 65 // leave it up to the nsHashKey destructor to free the "value"
michael@0 66 delete hashEntry->key;
michael@0 67 hashEntry->key = nullptr;
michael@0 68 hashEntry->value = nullptr; // probably not necessary, but for
michael@0 69 // sanity's sake
michael@0 70 }
michael@0 71
michael@0 72
michael@0 73 static const PLDHashTableOps hashtableOps = {
michael@0 74 PL_DHashAllocTable,
michael@0 75 PL_DHashFreeTable,
michael@0 76 hashKey,
michael@0 77 matchKeyEntry,
michael@0 78 PL_DHashMoveEntryStub,
michael@0 79 clearHashEntry,
michael@0 80 PL_DHashFinalizeStub,
michael@0 81 nullptr,
michael@0 82 };
michael@0 83
michael@0 84
michael@0 85 //
michael@0 86 // Enumerator callback
michael@0 87 //
michael@0 88
michael@0 89 struct _HashEnumerateArgs {
michael@0 90 nsHashtableEnumFunc fn;
michael@0 91 void* arg;
michael@0 92 };
michael@0 93
michael@0 94 static PLDHashOperator
michael@0 95 hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, uint32_t i, void *arg)
michael@0 96 {
michael@0 97 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
michael@0 98 HTEntry* entry = static_cast<HTEntry*>(hdr);
michael@0 99
michael@0 100 if (thunk->fn(entry->key, entry->value, thunk->arg))
michael@0 101 return PL_DHASH_NEXT;
michael@0 102 return PL_DHASH_STOP;
michael@0 103 }
michael@0 104
michael@0 105 //
michael@0 106 // HashKey
michael@0 107 //
michael@0 108
michael@0 109 nsHashKey::~nsHashKey(void)
michael@0 110 {
michael@0 111 MOZ_COUNT_DTOR(nsHashKey);
michael@0 112 }
michael@0 113
michael@0 114 nsresult
michael@0 115 nsHashKey::Write(nsIObjectOutputStream* aStream) const
michael@0 116 {
michael@0 117 NS_NOTREACHED("oops");
michael@0 118 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 119 }
michael@0 120
michael@0 121 nsHashtable::nsHashtable(uint32_t aInitSize, bool aThreadSafe)
michael@0 122 : mLock(nullptr), mEnumerating(false)
michael@0 123 {
michael@0 124 MOZ_COUNT_CTOR(nsHashtable);
michael@0 125
michael@0 126 bool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nullptr,
michael@0 127 sizeof(HTEntry), aInitSize, fallible_t());
michael@0 128 NS_ASSERTION(result, "Hashtable failed to initialize");
michael@0 129
michael@0 130 // make sure we detect this later
michael@0 131 if (!result)
michael@0 132 mHashtable.ops = nullptr;
michael@0 133
michael@0 134 if (aThreadSafe) {
michael@0 135 mLock = PR_NewLock();
michael@0 136 if (mLock == nullptr) {
michael@0 137 // Cannot create a lock. If running on a multiprocessing system
michael@0 138 // we are sure to die.
michael@0 139 PR_ASSERT(mLock != nullptr);
michael@0 140 }
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 nsHashtable::~nsHashtable() {
michael@0 145 MOZ_COUNT_DTOR(nsHashtable);
michael@0 146 if (mHashtable.ops)
michael@0 147 PL_DHashTableFinish(&mHashtable);
michael@0 148 if (mLock) PR_DestroyLock(mLock);
michael@0 149 }
michael@0 150
michael@0 151 bool nsHashtable::Exists(nsHashKey *aKey)
michael@0 152 {
michael@0 153 if (mLock) PR_Lock(mLock);
michael@0 154
michael@0 155 if (!mHashtable.ops) {
michael@0 156 if (mLock) PR_Unlock(mLock);
michael@0 157 return false;
michael@0 158 }
michael@0 159
michael@0 160 PLDHashEntryHdr *entry =
michael@0 161 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP);
michael@0 162
michael@0 163 bool exists = PL_DHASH_ENTRY_IS_BUSY(entry);
michael@0 164
michael@0 165 if (mLock) PR_Unlock(mLock);
michael@0 166
michael@0 167 return exists;
michael@0 168 }
michael@0 169
michael@0 170 void *nsHashtable::Put(nsHashKey *aKey, void *aData)
michael@0 171 {
michael@0 172 void *res = nullptr;
michael@0 173
michael@0 174 if (!mHashtable.ops) return nullptr;
michael@0 175
michael@0 176 if (mLock) PR_Lock(mLock);
michael@0 177
michael@0 178 // shouldn't be adding an item during enumeration
michael@0 179 PR_ASSERT(!mEnumerating);
michael@0 180
michael@0 181 HTEntry* entry =
michael@0 182 static_cast<HTEntry*>
michael@0 183 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
michael@0 184
michael@0 185 if (entry) { // don't return early, or you'll be locked!
michael@0 186 if (entry->key) {
michael@0 187 // existing entry, need to boot the old value
michael@0 188 res = entry->value;
michael@0 189 entry->value = aData;
michael@0 190 } else {
michael@0 191 // new entry (leave res == null)
michael@0 192 entry->key = aKey->Clone();
michael@0 193 entry->value = aData;
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 if (mLock) PR_Unlock(mLock);
michael@0 198
michael@0 199 return res;
michael@0 200 }
michael@0 201
michael@0 202 void *nsHashtable::Get(nsHashKey *aKey)
michael@0 203 {
michael@0 204 if (!mHashtable.ops) return nullptr;
michael@0 205
michael@0 206 if (mLock) PR_Lock(mLock);
michael@0 207
michael@0 208 HTEntry* entry =
michael@0 209 static_cast<HTEntry*>
michael@0 210 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
michael@0 211 void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nullptr;
michael@0 212
michael@0 213 if (mLock) PR_Unlock(mLock);
michael@0 214
michael@0 215 return ret;
michael@0 216 }
michael@0 217
michael@0 218 void *nsHashtable::Remove(nsHashKey *aKey)
michael@0 219 {
michael@0 220 if (!mHashtable.ops) return nullptr;
michael@0 221
michael@0 222 if (mLock) PR_Lock(mLock);
michael@0 223
michael@0 224 // shouldn't be adding an item during enumeration
michael@0 225 PR_ASSERT(!mEnumerating);
michael@0 226
michael@0 227
michael@0 228 // need to see if the entry is actually there, in order to get the
michael@0 229 // old value for the result
michael@0 230 HTEntry* entry =
michael@0 231 static_cast<HTEntry*>
michael@0 232 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
michael@0 233 void *res;
michael@0 234
michael@0 235 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
michael@0 236 // value wasn't in the table anyway
michael@0 237 res = nullptr;
michael@0 238 } else {
michael@0 239 res = entry->value;
michael@0 240 PL_DHashTableRawRemove(&mHashtable, entry);
michael@0 241 }
michael@0 242
michael@0 243 if (mLock) PR_Unlock(mLock);
michael@0 244
michael@0 245 return res;
michael@0 246 }
michael@0 247
michael@0 248 // XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
michael@0 249 // I don't know how this was supposed to work since the elements are neither copied
michael@0 250 // nor refcounted.
michael@0 251 static PLDHashOperator
michael@0 252 hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr,
michael@0 253 uint32_t i, void *arg)
michael@0 254 {
michael@0 255 nsHashtable *newHashtable = (nsHashtable *)arg;
michael@0 256 HTEntry * entry = static_cast<HTEntry*>(hdr);
michael@0 257
michael@0 258 newHashtable->Put(entry->key, entry->value);
michael@0 259 return PL_DHASH_NEXT;
michael@0 260 }
michael@0 261
michael@0 262 nsHashtable * nsHashtable::Clone()
michael@0 263 {
michael@0 264 if (!mHashtable.ops) return nullptr;
michael@0 265
michael@0 266 bool threadSafe = (mLock != nullptr);
michael@0 267 nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe);
michael@0 268
michael@0 269 PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable);
michael@0 270 return newHashTable;
michael@0 271 }
michael@0 272
michael@0 273 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
michael@0 274 {
michael@0 275 if (!mHashtable.ops) return;
michael@0 276
michael@0 277 bool wasEnumerating = mEnumerating;
michael@0 278 mEnumerating = true;
michael@0 279 _HashEnumerateArgs thunk;
michael@0 280 thunk.fn = aEnumFunc;
michael@0 281 thunk.arg = aClosure;
michael@0 282 PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk);
michael@0 283 mEnumerating = wasEnumerating;
michael@0 284 }
michael@0 285
michael@0 286 static PLDHashOperator
michael@0 287 hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, uint32_t i, void *arg)
michael@0 288 {
michael@0 289 HTEntry* entry = static_cast<HTEntry*>(hdr);
michael@0 290 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
michael@0 291 if (thunk) {
michael@0 292 return thunk->fn(entry->key, entry->value, thunk->arg)
michael@0 293 ? PL_DHASH_REMOVE
michael@0 294 : PL_DHASH_STOP;
michael@0 295 }
michael@0 296 return PL_DHASH_REMOVE;
michael@0 297 }
michael@0 298
michael@0 299 void nsHashtable::Reset() {
michael@0 300 Reset(nullptr);
michael@0 301 }
michael@0 302
michael@0 303 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
michael@0 304 {
michael@0 305 if (!mHashtable.ops) return;
michael@0 306
michael@0 307 _HashEnumerateArgs thunk, *thunkp;
michael@0 308 if (!destroyFunc) {
michael@0 309 thunkp = nullptr;
michael@0 310 } else {
michael@0 311 thunkp = &thunk;
michael@0 312 thunk.fn = destroyFunc;
michael@0 313 thunk.arg = aClosure;
michael@0 314 }
michael@0 315 PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp);
michael@0 316 }
michael@0 317
michael@0 318 // nsISerializable helpers
michael@0 319
michael@0 320 nsHashtable::nsHashtable(nsIObjectInputStream* aStream,
michael@0 321 nsHashtableReadEntryFunc aReadEntryFunc,
michael@0 322 nsHashtableFreeEntryFunc aFreeEntryFunc,
michael@0 323 nsresult *aRetVal)
michael@0 324 : mLock(nullptr),
michael@0 325 mEnumerating(false)
michael@0 326 {
michael@0 327 MOZ_COUNT_CTOR(nsHashtable);
michael@0 328
michael@0 329 bool threadSafe;
michael@0 330 nsresult rv = aStream->ReadBoolean(&threadSafe);
michael@0 331 if (NS_SUCCEEDED(rv)) {
michael@0 332 if (threadSafe) {
michael@0 333 mLock = PR_NewLock();
michael@0 334 if (!mLock)
michael@0 335 rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 336 }
michael@0 337
michael@0 338 if (NS_SUCCEEDED(rv)) {
michael@0 339 uint32_t count;
michael@0 340 rv = aStream->Read32(&count);
michael@0 341
michael@0 342 if (NS_SUCCEEDED(rv)) {
michael@0 343 bool status =
michael@0 344 PL_DHashTableInit(&mHashtable, &hashtableOps,
michael@0 345 nullptr, sizeof(HTEntry), count,
michael@0 346 fallible_t());
michael@0 347 if (!status) {
michael@0 348 mHashtable.ops = nullptr;
michael@0 349 rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 350 } else {
michael@0 351 for (uint32_t i = 0; i < count; i++) {
michael@0 352 nsHashKey* key;
michael@0 353 void *data;
michael@0 354
michael@0 355 rv = aReadEntryFunc(aStream, &key, &data);
michael@0 356 if (NS_SUCCEEDED(rv)) {
michael@0 357 Put(key, data);
michael@0 358
michael@0 359 // XXXbe must we clone key? can't we hand off
michael@0 360 aFreeEntryFunc(aStream, key, nullptr);
michael@0 361 }
michael@0 362 }
michael@0 363 }
michael@0 364 }
michael@0 365 }
michael@0 366 }
michael@0 367 *aRetVal = rv;
michael@0 368 }
michael@0 369
michael@0 370 struct WriteEntryArgs {
michael@0 371 nsIObjectOutputStream* mStream;
michael@0 372 nsHashtableWriteDataFunc mWriteDataFunc;
michael@0 373 nsresult mRetVal;
michael@0 374 };
michael@0 375
michael@0 376 static bool
michael@0 377 WriteEntry(nsHashKey *aKey, void *aData, void* aClosure)
michael@0 378 {
michael@0 379 WriteEntryArgs* args = (WriteEntryArgs*) aClosure;
michael@0 380 nsIObjectOutputStream* stream = args->mStream;
michael@0 381
michael@0 382 nsresult rv = aKey->Write(stream);
michael@0 383 if (NS_SUCCEEDED(rv))
michael@0 384 rv = args->mWriteDataFunc(stream, aData);
michael@0 385
michael@0 386 args->mRetVal = rv;
michael@0 387 return true;
michael@0 388 }
michael@0 389
michael@0 390 nsresult
michael@0 391 nsHashtable::Write(nsIObjectOutputStream* aStream,
michael@0 392 nsHashtableWriteDataFunc aWriteDataFunc) const
michael@0 393 {
michael@0 394 if (!mHashtable.ops)
michael@0 395 return NS_ERROR_OUT_OF_MEMORY;
michael@0 396 bool threadSafe = (mLock != nullptr);
michael@0 397 nsresult rv = aStream->WriteBoolean(threadSafe);
michael@0 398 if (NS_FAILED(rv)) return rv;
michael@0 399
michael@0 400 // Write the entry count first, so we know how many key/value pairs to read.
michael@0 401 uint32_t count = mHashtable.entryCount;
michael@0 402 rv = aStream->Write32(count);
michael@0 403 if (NS_FAILED(rv)) return rv;
michael@0 404
michael@0 405 // Write all key/value pairs in the table.
michael@0 406 WriteEntryArgs args = {aStream, aWriteDataFunc};
michael@0 407 const_cast<nsHashtable*>(this)->Enumerate(WriteEntry, (void*) &args);
michael@0 408 return args.mRetVal;
michael@0 409 }
michael@0 410
michael@0 411 ////////////////////////////////////////////////////////////////////////////////
michael@0 412
michael@0 413 // Copy Constructor
michael@0 414 // We need to free mStr if the object is passed with mOwnership as OWN. As the
michael@0 415 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
michael@0 416
michael@0 417 nsCStringKey::nsCStringKey(const nsCStringKey& aKey)
michael@0 418 : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
michael@0 419 {
michael@0 420 if (mOwnership != NEVER_OWN) {
michael@0 421 uint32_t len = mStrLen * sizeof(char);
michael@0 422 char* str = reinterpret_cast<char*>(nsMemory::Alloc(len + sizeof(char)));
michael@0 423 if (!str) {
michael@0 424 // Pray we don't dangle!
michael@0 425 mOwnership = NEVER_OWN;
michael@0 426 } else {
michael@0 427 // Use memcpy in case there are embedded NULs.
michael@0 428 memcpy(str, mStr, len);
michael@0 429 str[mStrLen] = '\0';
michael@0 430 mStr = str;
michael@0 431 mOwnership = OWN;
michael@0 432 }
michael@0 433 }
michael@0 434 #ifdef DEBUG
michael@0 435 mKeyType = CStringKey;
michael@0 436 #endif
michael@0 437 MOZ_COUNT_CTOR(nsCStringKey);
michael@0 438 }
michael@0 439
michael@0 440 nsCStringKey::nsCStringKey(const nsAFlatCString& str)
michael@0 441 : mStr(const_cast<char*>(str.get())),
michael@0 442 mStrLen(str.Length()),
michael@0 443 mOwnership(OWN_CLONE)
michael@0 444 {
michael@0 445 NS_ASSERTION(mStr, "null string key");
michael@0 446 #ifdef DEBUG
michael@0 447 mKeyType = CStringKey;
michael@0 448 #endif
michael@0 449 MOZ_COUNT_CTOR(nsCStringKey);
michael@0 450 }
michael@0 451
michael@0 452 nsCStringKey::nsCStringKey(const nsACString& str)
michael@0 453 : mStr(ToNewCString(str)),
michael@0 454 mStrLen(str.Length()),
michael@0 455 mOwnership(OWN)
michael@0 456 {
michael@0 457 NS_ASSERTION(mStr, "null string key");
michael@0 458 #ifdef DEBUG
michael@0 459 mKeyType = CStringKey;
michael@0 460 #endif
michael@0 461 MOZ_COUNT_CTOR(nsCStringKey);
michael@0 462 }
michael@0 463
michael@0 464 nsCStringKey::nsCStringKey(const char* str, int32_t strLen, Ownership own)
michael@0 465 : mStr((char*)str), mStrLen(strLen), mOwnership(own)
michael@0 466 {
michael@0 467 NS_ASSERTION(mStr, "null string key");
michael@0 468 if (mStrLen == uint32_t(-1))
michael@0 469 mStrLen = strlen(str);
michael@0 470 #ifdef DEBUG
michael@0 471 mKeyType = CStringKey;
michael@0 472 #endif
michael@0 473 MOZ_COUNT_CTOR(nsCStringKey);
michael@0 474 }
michael@0 475
michael@0 476 nsCStringKey::~nsCStringKey(void)
michael@0 477 {
michael@0 478 if (mOwnership == OWN)
michael@0 479 nsMemory::Free(mStr);
michael@0 480 MOZ_COUNT_DTOR(nsCStringKey);
michael@0 481 }
michael@0 482
michael@0 483 uint32_t
michael@0 484 nsCStringKey::HashCode(void) const
michael@0 485 {
michael@0 486 return HashString(mStr, mStrLen);
michael@0 487 }
michael@0 488
michael@0 489 bool
michael@0 490 nsCStringKey::Equals(const nsHashKey* aKey) const
michael@0 491 {
michael@0 492 NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types");
michael@0 493 nsCStringKey* other = (nsCStringKey*)aKey;
michael@0 494 NS_ASSERTION(mStrLen != uint32_t(-1), "never called HashCode");
michael@0 495 NS_ASSERTION(other->mStrLen != uint32_t(-1), "never called HashCode");
michael@0 496 if (mStrLen != other->mStrLen)
michael@0 497 return false;
michael@0 498 return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
michael@0 499 }
michael@0 500
michael@0 501 nsHashKey*
michael@0 502 nsCStringKey::Clone() const
michael@0 503 {
michael@0 504 if (mOwnership == NEVER_OWN)
michael@0 505 return new nsCStringKey(mStr, mStrLen, NEVER_OWN);
michael@0 506
michael@0 507 // Since this might hold binary data OR a string, we ensure that the
michael@0 508 // clone string is zero terminated, but don't assume that the source
michael@0 509 // string was so terminated.
michael@0 510
michael@0 511 uint32_t len = mStrLen * sizeof(char);
michael@0 512 char* str = (char*)nsMemory::Alloc(len + sizeof(char));
michael@0 513 if (str == nullptr)
michael@0 514 return nullptr;
michael@0 515 memcpy(str, mStr, len);
michael@0 516 str[len] = 0;
michael@0 517 return new nsCStringKey(str, mStrLen, OWN);
michael@0 518 }
michael@0 519
michael@0 520 nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
michael@0 521 : mStr(nullptr), mStrLen(0), mOwnership(OWN)
michael@0 522 {
michael@0 523 nsAutoCString str;
michael@0 524 nsresult rv = aStream->ReadCString(str);
michael@0 525 mStr = ToNewCString(str);
michael@0 526 if (NS_SUCCEEDED(rv))
michael@0 527 mStrLen = str.Length();
michael@0 528 *aResult = rv;
michael@0 529 MOZ_COUNT_CTOR(nsCStringKey);
michael@0 530 }
michael@0 531
michael@0 532 nsresult
michael@0 533 nsCStringKey::Write(nsIObjectOutputStream* aStream) const
michael@0 534 {
michael@0 535 return aStream->WriteStringZ(mStr);
michael@0 536 }
michael@0 537
michael@0 538 ////////////////////////////////////////////////////////////////////////////////
michael@0 539 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
michael@0 540 // deleted
michael@0 541
michael@0 542 nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
michael@0 543 void* cloneElementClosure,
michael@0 544 nsHashtableEnumFunc destroyElementFun,
michael@0 545 void* destroyElementClosure,
michael@0 546 uint32_t aSize, bool threadSafe)
michael@0 547 : nsHashtable(aSize, threadSafe),
michael@0 548 mCloneElementFun(cloneElementFun),
michael@0 549 mCloneElementClosure(cloneElementClosure),
michael@0 550 mDestroyElementFun(destroyElementFun),
michael@0 551 mDestroyElementClosure(destroyElementClosure)
michael@0 552 {
michael@0 553 }
michael@0 554
michael@0 555 nsObjectHashtable::~nsObjectHashtable()
michael@0 556 {
michael@0 557 Reset();
michael@0 558 }
michael@0 559
michael@0 560
michael@0 561 PLDHashOperator
michael@0 562 nsObjectHashtable::CopyElement(PLDHashTable* table,
michael@0 563 PLDHashEntryHdr* hdr,
michael@0 564 uint32_t i, void *arg)
michael@0 565 {
michael@0 566 nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
michael@0 567 HTEntry *entry = static_cast<HTEntry*>(hdr);
michael@0 568
michael@0 569 void* newElement =
michael@0 570 newHashtable->mCloneElementFun(entry->key, entry->value,
michael@0 571 newHashtable->mCloneElementClosure);
michael@0 572 if (newElement == nullptr)
michael@0 573 return PL_DHASH_STOP;
michael@0 574 newHashtable->Put(entry->key, newElement);
michael@0 575 return PL_DHASH_NEXT;
michael@0 576 }
michael@0 577
michael@0 578 nsHashtable*
michael@0 579 nsObjectHashtable::Clone()
michael@0 580 {
michael@0 581 if (!mHashtable.ops) return nullptr;
michael@0 582
michael@0 583 bool threadSafe = false;
michael@0 584 if (mLock)
michael@0 585 threadSafe = true;
michael@0 586 nsObjectHashtable* newHashTable =
michael@0 587 new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
michael@0 588 mDestroyElementFun, mDestroyElementClosure,
michael@0 589 mHashtable.entryCount, threadSafe);
michael@0 590
michael@0 591 PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
michael@0 592 return newHashTable;
michael@0 593 }
michael@0 594
michael@0 595 void
michael@0 596 nsObjectHashtable::Reset()
michael@0 597 {
michael@0 598 nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
michael@0 599 }
michael@0 600
michael@0 601 bool
michael@0 602 nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
michael@0 603 {
michael@0 604 void *value = Remove(aKey);
michael@0 605 if (value && mDestroyElementFun)
michael@0 606 return !!(*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
michael@0 607 return false;
michael@0 608 }

mercurial