LCOV - code coverage report
Current view: directory - xpcom/ds - nsHashtable.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 404 180 44.6 %
Date: 2012-06-02 Functions: 63 33 52.4 %

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

Generated by: LCOV version 1.7