/gecko_api/include/nsBaseHashtable.h
C++ Header | 455 lines | 246 code | 69 blank | 140 comment | 9 complexity | d2b77f38d4e26081f13d2329d3af467d MD5 | raw file
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 C++ hashtable templates. 16 * 17 * The Initial Developer of the Original Code is 18 * Benjamin Smedberg. 19 * Portions created by the Initial Developer are Copyright (C) 2002 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 the GNU General Public License Version 2 or later (the "GPL"), or 26 * 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 38#ifndef nsBaseHashtable_h__ 39#define nsBaseHashtable_h__ 40 41#include "nsTHashtable.h" 42#include "prlock.h" 43#include "nsDebug.h" 44 45template<class KeyClass,class DataType,class UserDataType> 46class nsBaseHashtable; // forward declaration 47 48/** 49 * the private nsTHashtable::EntryType class used by nsBaseHashtable 50 * @see nsTHashtable for the specification of this class 51 * @see nsBaseHashtable for template parameters 52 */ 53template<class KeyClass,class DataType> 54class nsBaseHashtableET : public KeyClass 55{ 56public: 57 DataType mData; 58 friend class nsTHashtable< nsBaseHashtableET<KeyClass,DataType> >; 59 60private: 61 typedef typename KeyClass::KeyType KeyType; 62 typedef typename KeyClass::KeyTypePointer KeyTypePointer; 63 64 nsBaseHashtableET(KeyTypePointer aKey); 65 nsBaseHashtableET(nsBaseHashtableET<KeyClass,DataType>& toCopy); 66 ~nsBaseHashtableET(); 67}; 68 69/** 70 * templated hashtable for simple data types 71 * This class manages simple data types that do not need construction or 72 * destruction. 73 * 74 * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h 75 * for a complete specification. 76 * @param DataType the datatype stored in the hashtable, 77 * for example, PRUint32 or nsCOMPtr. If UserDataType is not the same, 78 * DataType must implicitly cast to UserDataType 79 * @param UserDataType the user sees, for example PRUint32 or nsISupports* 80 */ 81template<class KeyClass,class DataType,class UserDataType> 82class nsBaseHashtable : 83 protected nsTHashtable< nsBaseHashtableET<KeyClass,DataType> > 84{ 85public: 86 typedef typename KeyClass::KeyType KeyType; 87 typedef nsBaseHashtableET<KeyClass,DataType> EntryType; 88 89 // default constructor+destructor are fine 90 91 /** 92 * Initialize the object. 93 * @param initSize the initial number of buckets in the hashtable, 94 * default 16 95 * locking on all class methods 96 * @return PR_TRUE if the object was initialized properly. 97 */ 98 PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) 99 { return nsTHashtable<EntryType>::Init(initSize); } 100 101 /** 102 * Check whether the table has been initialized. 103 * This function is especially useful for static hashtables. 104 * @return PR_TRUE if the table has been initialized. 105 */ 106 PRBool IsInitialized() const { return !!this->mTable.entrySize; } 107 108 /** 109 * Return the number of entries in the table. 110 * @return number of entries 111 */ 112 PRUint32 Count() const 113 { return nsTHashtable<EntryType>::Count(); } 114 115 /** 116 * retrieve the value for a key. 117 * @param aKey the key to retreive 118 * @param pData data associated with this key will be placed at this 119 * pointer. If you only need to check if the key exists, pData 120 * may be null. 121 * @return PR_TRUE if the key exists. If key does not exist, pData is not 122 * modified. 123 */ 124 PRBool Get(KeyType aKey, UserDataType* pData) const 125 { 126 EntryType* ent = GetEntry(aKey); 127 128 if (!ent) 129 return PR_FALSE; 130 131 if (pData) 132 *pData = ent->mData; 133 134 return PR_TRUE; 135 } 136 137 /** 138 * put a new value for the associated key 139 * @param aKey the key to put 140 * @param aData the new data 141 * @return always PR_TRUE, unless memory allocation failed 142 */ 143 PRBool Put(KeyType aKey, UserDataType aData) 144 { 145 EntryType* ent = PutEntry(aKey); 146 147 if (!ent) 148 return PR_FALSE; 149 150 ent->mData = aData; 151 152 return PR_TRUE; 153 } 154 155 /** 156 * remove the data for the associated key 157 * @param aKey the key to remove from the hashtable 158 */ 159 void Remove(KeyType aKey) { RemoveEntry(aKey); } 160 161 /** 162 * function type provided by the application for enumeration. 163 * @param aKey the key being enumerated 164 * @param aData data being enumerated 165 * @parm userArg passed unchanged from Enumerate 166 * @return either 167 * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or 168 * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink 169 */ 170 typedef PLDHashOperator 171 (*PR_CALLBACK EnumReadFunction)(KeyType aKey, 172 UserDataType aData, 173 void* userArg); 174 175 /** 176 * enumerate entries in the hashtable, without allowing changes 177 * @param enumFunc enumeration callback 178 * @param userArg passed unchanged to the EnumReadFunction 179 */ 180 PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const 181 { 182 NS_ASSERTION(this->mTable.entrySize, 183 "nsBaseHashtable was not initialized properly."); 184 185 s_EnumReadArgs enumData = { enumFunc, userArg }; 186 return PL_DHashTableEnumerate(const_cast<PLDHashTable*>(&this->mTable), 187 s_EnumReadStub, 188 &enumData); 189 } 190 191 /** 192 * function type provided by the application for enumeration. 193 * @param aKey the key being enumerated 194 * @param aData Reference to data being enumerated, may be altered. e.g. for 195 * nsInterfaceHashtable this is an nsCOMPtr reference... 196 * @parm userArg passed unchanged from Enumerate 197 * @return bitflag combination of 198 * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, 199 * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or 200 * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink 201 */ 202 typedef PLDHashOperator 203 (*PR_CALLBACK EnumFunction)(KeyType aKey, 204 DataType& aData, 205 void* userArg); 206 207 /** 208 * enumerate entries in the hashtable, allowing changes. This 209 * functions write-locks the hashtable. 210 * @param enumFunc enumeration callback 211 * @param userArg passed unchanged to the EnumFunction 212 */ 213 PRUint32 Enumerate(EnumFunction enumFunc, void* userArg) 214 { 215 NS_ASSERTION(this->mTable.entrySize, 216 "nsBaseHashtable was not initialized properly."); 217 218 s_EnumArgs enumData = { enumFunc, userArg }; 219 return PL_DHashTableEnumerate(&this->mTable, 220 s_EnumStub, 221 &enumData); 222 } 223 224 /** 225 * reset the hashtable, removing all entries 226 */ 227 void Clear() { nsTHashtable<EntryType>::Clear(); } 228 229protected: 230 /** 231 * used internally during EnumerateRead. Allocated on the stack. 232 * @param func the enumerator passed to EnumerateRead 233 * @param userArg the userArg passed to EnumerateRead 234 */ 235 struct s_EnumReadArgs 236 { 237 EnumReadFunction func; 238 void* userArg; 239 }; 240 241 static PLDHashOperator s_EnumReadStub(PLDHashTable *table, 242 PLDHashEntryHdr *hdr, 243 PRUint32 number, 244 void *arg); 245 246 struct s_EnumArgs 247 { 248 EnumFunction func; 249 void* userArg; 250 }; 251 252 static PLDHashOperator s_EnumStub(PLDHashTable *table, 253 PLDHashEntryHdr *hdr, 254 PRUint32 number, 255 void *arg); 256}; 257 258/** 259 * This class is a thread-safe version of nsBaseHashtable. 260 */ 261template<class KeyClass,class DataType,class UserDataType> 262class nsBaseHashtableMT : 263 protected nsBaseHashtable<KeyClass,DataType,UserDataType> 264{ 265public: 266 typedef typename 267 nsBaseHashtable<KeyClass,DataType,UserDataType>::EntryType EntryType; 268 typedef typename 269 nsBaseHashtable<KeyClass,DataType,UserDataType>::KeyType KeyType; 270 typedef typename 271 nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumFunction EnumFunction; 272 typedef typename 273 nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumReadFunction EnumReadFunction; 274 275 nsBaseHashtableMT() : mLock(nsnull) { } 276 ~nsBaseHashtableMT(); 277 278 PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); 279 PRBool IsInitialized() const { return mLock != nsnull; } 280 PRUint32 Count() const; 281 PRBool Get(KeyType aKey, UserDataType* pData) const; 282 PRBool Put(KeyType aKey, UserDataType aData); 283 void Remove(KeyType aKey); 284 285 PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const; 286 PRUint32 Enumerate(EnumFunction enumFunc, void* userArg); 287 void Clear(); 288 289protected: 290 PRLock* mLock; 291}; 292 293 294// 295// nsBaseHashtableET definitions 296// 297 298template<class KeyClass,class DataType> 299nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET(KeyTypePointer aKey) : 300 KeyClass(aKey) 301{ } 302 303template<class KeyClass,class DataType> 304nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET 305 (nsBaseHashtableET<KeyClass,DataType>& toCopy) : 306 KeyClass(toCopy), 307 mData(toCopy.mData) 308{ } 309 310template<class KeyClass,class DataType> 311nsBaseHashtableET<KeyClass,DataType>::~nsBaseHashtableET() 312{ } 313 314 315// 316// nsBaseHashtable definitions 317// 318 319template<class KeyClass,class DataType,class UserDataType> 320PLDHashOperator 321nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumReadStub 322 (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) 323{ 324 EntryType* ent = static_cast<EntryType*>(hdr); 325 s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; 326 327 PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); 328 329 NS_ASSERTION( !(res & PL_DHASH_REMOVE ), 330 "PL_DHASH_REMOVE return during const enumeration; ignoring."); 331 332 if (res & PL_DHASH_STOP) 333 return PL_DHASH_STOP; 334 335 return PL_DHASH_NEXT; 336} 337 338template<class KeyClass,class DataType,class UserDataType> 339PLDHashOperator 340nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumStub 341 (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) 342{ 343 EntryType* ent = static_cast<EntryType*>(hdr); 344 s_EnumArgs* eargs = (s_EnumArgs*) arg; 345 346 return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); 347} 348 349 350// 351// nsBaseHashtableMT definitions 352// 353 354template<class KeyClass,class DataType,class UserDataType> 355nsBaseHashtableMT<KeyClass,DataType,UserDataType>::~nsBaseHashtableMT() 356{ 357 if (this->mLock) 358 PR_DestroyLock(this->mLock); 359} 360 361template<class KeyClass,class DataType,class UserDataType> 362PRBool 363nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Init(PRUint32 initSize) 364{ 365 if (!nsTHashtable<EntryType>::IsInitialized() && !nsTHashtable<EntryType>::Init(initSize)) 366 return PR_FALSE; 367 368 this->mLock = PR_NewLock(); 369 NS_ASSERTION(this->mLock, "Error creating lock during nsBaseHashtableL::Init()"); 370 371 return (this->mLock != nsnull); 372} 373 374template<class KeyClass,class DataType,class UserDataType> 375PRUint32 376nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Count() const 377{ 378 PR_Lock(this->mLock); 379 PRUint32 count = nsTHashtable<EntryType>::Count(); 380 PR_Unlock(this->mLock); 381 382 return count; 383} 384 385template<class KeyClass,class DataType,class UserDataType> 386PRBool 387nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Get(KeyType aKey, 388 UserDataType* pData) const 389{ 390 PR_Lock(this->mLock); 391 PRBool res = 392 nsBaseHashtable<KeyClass,DataType,UserDataType>::Get(aKey, pData); 393 PR_Unlock(this->mLock); 394 395 return res; 396} 397 398template<class KeyClass,class DataType,class UserDataType> 399PRBool 400nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Put(KeyType aKey, 401 UserDataType aData) 402{ 403 PR_Lock(this->mLock); 404 PRBool res = 405 nsBaseHashtable<KeyClass,DataType,UserDataType>::Put(aKey, aData); 406 PR_Unlock(this->mLock); 407 408 return res; 409} 410 411template<class KeyClass,class DataType,class UserDataType> 412void 413nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Remove(KeyType aKey) 414{ 415 PR_Lock(this->mLock); 416 nsBaseHashtable<KeyClass,DataType,UserDataType>::Remove(aKey); 417 PR_Unlock(this->mLock); 418} 419 420template<class KeyClass,class DataType,class UserDataType> 421PRUint32 422nsBaseHashtableMT<KeyClass,DataType,UserDataType>::EnumerateRead 423 (EnumReadFunction fEnumCall, void* userArg) const 424{ 425 PR_Lock(this->mLock); 426 PRUint32 count = 427 nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead(fEnumCall, userArg); 428 PR_Unlock(this->mLock); 429 430 return count; 431} 432 433template<class KeyClass,class DataType,class UserDataType> 434PRUint32 435nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Enumerate 436 (EnumFunction fEnumCall, void* userArg) 437{ 438 PR_Lock(this->mLock); 439 PRUint32 count = 440 nsBaseHashtable<KeyClass,DataType,UserDataType>::Enumerate(fEnumCall, userArg); 441 PR_Unlock(this->mLock); 442 443 return count; 444} 445 446template<class KeyClass,class DataType,class UserDataType> 447void 448nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Clear() 449{ 450 PR_Lock(this->mLock); 451 nsBaseHashtable<KeyClass,DataType,UserDataType>::Clear(); 452 PR_Unlock(this->mLock); 453} 454 455#endif // nsBaseHashtable_h__