PageRenderTime 226ms CodeModel.GetById 91ms app.highlight 30ms RepoModel.GetById 40ms app.codeStats 0ms

/gecko_api/include/nsTHashtable.h

http://firefox-mac-pdf.googlecode.com/
C++ Header | 417 lines | 192 code | 52 blank | 173 comment | 4 complexity | 8cf9eb6444acbf86a49634a425936bd9 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 nsTHashtable_h__
 39#define nsTHashtable_h__
 40
 41#include "nscore.h"
 42#include "pldhash.h"
 43#include "nsDebug.h"
 44#include NEW_H
 45
 46// helper function for nsTHashtable::Clear()
 47NS_COM_GLUE PLDHashOperator
 48PL_DHashStubEnumRemove(PLDHashTable    *table,
 49                       PLDHashEntryHdr *entry,
 50                       PRUint32         ordinal,
 51                       void            *userArg);
 52
 53
 54/**
 55 * a base class for templated hashtables.
 56 *
 57 * Clients will rarely need to use this class directly. Check the derived
 58 * classes first, to see if they will meet your needs.
 59 *
 60 * @param EntryType  the templated entry-type class that is managed by the
 61 *   hashtable. <code>EntryType</code> must extend the following declaration,
 62 *   and <strong>must not declare any virtual functions or derive from classes
 63 *   with virtual functions.</strong>  Any vtable pointer would break the
 64 *   PLDHashTable code.
 65 *<pre>   class EntryType : public PLDHashEntryHdr
 66 *   {
 67 *   public: or friend nsTHashtable<EntryType>;
 68 *     // KeyType is what we use when Get()ing or Put()ing this entry
 69 *     // this should either be a simple datatype (PRUint32, nsISupports*) or
 70 *     // a const reference (const nsAString&)
 71 *     typedef something KeyType;
 72 *     // KeyTypePointer is the pointer-version of KeyType, because pldhash.h
 73 *     // requires keys to cast to <code>const void*</code>
 74 *     typedef const something* KeyTypePointer;
 75 *
 76 *     EntryType(KeyTypePointer aKey);
 77 *
 78 *     // the copy constructor must be defined, even if AllowMemMove() == true
 79 *     // or you will cause link errors!
 80 *     EntryType(const EntryType& aEnt);
 81 *
 82 *     // the destructor must be defined... or you will cause link errors!
 83 *     ~EntryType();
 84 *
 85 *     // KeyEquals(): does this entry match this key?
 86 *     PRBool KeyEquals(KeyTypePointer aKey) const;
 87 *
 88 *     // KeyToPointer(): Convert KeyType to KeyTypePointer
 89 *     static KeyTypePointer KeyToPointer(KeyType aKey);
 90 *
 91 *     // HashKey(): calculate the hash number
 92 *     static PLDHashNumber HashKey(KeyTypePointer aKey);
 93 *
 94 *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
 95 *     // to use the copy constructor?
 96 *     enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) };
 97 *   }</pre>
 98 *
 99 * @see nsInterfaceHashtable
100 * @see nsDataHashtable
101 * @see nsClassHashtable
102 * @author "Benjamin Smedberg <bsmedberg@covad.net>"
103 */
104
105template<class EntryType>
106class nsTHashtable
107{
108public:
109  /**
110   * A dummy constructor; you must call Init() before using this class.
111   */
112  nsTHashtable();
113
114  /**
115   * destructor, cleans up and deallocates
116   */
117  ~nsTHashtable();
118
119  /**
120   * Initialize the table.  This function must be called before any other
121   * class operations.  This can fail due to OOM conditions.
122   * @param initSize the initial number of buckets in the hashtable, default 16
123   * @return PR_TRUE if the class was initialized properly.
124   */
125  PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE);
126
127  /**
128   * Check whether the table has been initialized. This can be useful for static hashtables.
129   * @return the initialization state of the class.
130   */
131  PRBool IsInitialized() const { return !!mTable.entrySize; }
132
133  /**
134   * KeyType is typedef'ed for ease of use.
135   */
136  typedef typename EntryType::KeyType KeyType;
137
138  /**
139   * KeyTypePointer is typedef'ed for ease of use.
140   */
141  typedef typename EntryType::KeyTypePointer KeyTypePointer;
142
143  /**
144   * Return the number of entries in the table.
145   * @return    number of entries
146   */
147  PRUint32 Count() const { return mTable.entryCount; }
148
149  /**
150   * Get the entry associated with a key.
151   * @param     aKey the key to retrieve
152   * @return    pointer to the entry class, if the key exists; nsnull if the
153   *            key doesn't exist
154   */
155  EntryType* GetEntry(KeyType aKey) const
156  {
157    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
158  
159    EntryType* entry =
160      reinterpret_cast<EntryType*>
161                      (PL_DHashTableOperate(
162                            const_cast<PLDHashTable*>(&mTable),
163                            EntryType::KeyToPointer(aKey),
164                            PL_DHASH_LOOKUP));
165    return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nsnull;
166  }
167
168  /**
169   * Get the entry associated with a key, or create a new entry,
170   * @param     aKey the key to retrieve
171   * @return    pointer to the entry class retreived; nsnull only if memory
172                can't be allocated
173   */
174  EntryType* PutEntry(KeyType aKey)
175  {
176    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
177    
178    return static_cast<EntryType*>
179                      (PL_DHashTableOperate(
180                            &mTable,
181                            EntryType::KeyToPointer(aKey),
182                            PL_DHASH_ADD));
183  }
184
185  /**
186   * Remove the entry associated with a key.
187   * @param     aKey of the entry to remove
188   */
189  void RemoveEntry(KeyType aKey)
190  {
191    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
192
193    PL_DHashTableOperate(&mTable,
194                         EntryType::KeyToPointer(aKey),
195                         PL_DHASH_REMOVE);
196  }
197
198  /**
199   * Remove the entry associated with a key, but don't resize the hashtable.
200   * This is a low-level method, and is not recommended unless you know what
201   * you're doing and you need the extra performance. This method can be used
202   * during enumeration, while RemoveEntry() cannot.
203   * @param aEntry   the entry-pointer to remove (obtained from GetEntry or
204   *                 the enumerator
205   */
206  void RawRemoveEntry(EntryType* aEntry)
207  {
208    PL_DHashTableRawRemove(&mTable, aEntry);
209  }
210
211  /**
212   * client must provide an <code>Enumerator</code> function for
213   *   EnumerateEntries
214   * @param     aEntry the entry being enumerated
215   * @param     userArg passed unchanged from <code>EnumerateEntries</code>
216   * @return    combination of flags
217   *            @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink ,
218   *            @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink ,
219   *            @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink
220   */
221  typedef PLDHashOperator (*PR_CALLBACK Enumerator)(EntryType* aEntry, void* userArg);
222
223  /**
224   * Enumerate all the entries of the function.
225   * @param     enumFunc the <code>Enumerator</code> function to call
226   * @param     userArg a pointer to pass to the
227   *            <code>Enumerator</code> function
228   * @return    the number of entries actually enumerated
229   */
230  PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg)
231  {
232    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
233    
234    s_EnumArgs args = { enumFunc, userArg };
235    return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args);
236  }
237
238  /**
239   * remove all entries, return hashtable to "pristine" state ;)
240   */
241  void Clear()
242  {
243    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
244
245    PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull);
246  }
247
248protected:
249  PLDHashTable mTable;
250
251  static const void* PR_CALLBACK s_GetKey(PLDHashTable    *table,
252                                          PLDHashEntryHdr *entry);
253
254  static PLDHashNumber PR_CALLBACK s_HashKey(PLDHashTable *table,
255                                             const void   *key);
256
257  static PRBool PR_CALLBACK s_MatchEntry(PLDHashTable           *table,
258                                         const PLDHashEntryHdr  *entry,
259                                         const void             *key);
260  
261  static void PR_CALLBACK s_CopyEntry(PLDHashTable          *table,
262                                      const PLDHashEntryHdr *from,
263                                      PLDHashEntryHdr       *to);
264  
265  static void PR_CALLBACK s_ClearEntry(PLDHashTable *table,
266                                       PLDHashEntryHdr *entry);
267
268  static PRBool PR_CALLBACK s_InitEntry(PLDHashTable     *table,
269                                        PLDHashEntryHdr  *entry,
270                                        const void       *key);
271
272  /**
273   * passed internally during enumeration.  Allocated on the stack.
274   *
275   * @param userFunc the Enumerator function passed to
276   *   EnumerateEntries by the client
277   * @param userArg the userArg passed unaltered
278   */
279  struct s_EnumArgs
280  {
281    Enumerator userFunc;
282    void* userArg;
283  };
284  
285  static PLDHashOperator PR_CALLBACK s_EnumStub(PLDHashTable    *table,
286                                                PLDHashEntryHdr *entry,
287                                                PRUint32         number,
288                                                void            *arg);
289private:
290  // copy constructor, not implemented
291  nsTHashtable(nsTHashtable<EntryType>& toCopy);
292
293  // assignment operator, not implemented
294  nsTHashtable<EntryType>& operator= (nsTHashtable<EntryType>& toEqual);
295};
296
297//
298// template definitions
299//
300
301template<class EntryType>
302nsTHashtable<EntryType>::nsTHashtable()
303{
304  // entrySize is our "I'm initialized" indicator
305  mTable.entrySize = 0;
306}
307
308template<class EntryType>
309nsTHashtable<EntryType>::~nsTHashtable()
310{
311  if (mTable.entrySize)
312    PL_DHashTableFinish(&mTable);
313}
314
315template<class EntryType>
316PRBool
317nsTHashtable<EntryType>::Init(PRUint32 initSize)
318{
319  if (mTable.entrySize)
320  {
321    NS_ERROR("nsTHashtable::Init() should not be called twice.");
322    return PR_TRUE;
323  }
324
325  static PLDHashTableOps sOps = 
326  {
327    ::PL_DHashAllocTable,
328    ::PL_DHashFreeTable,
329    s_HashKey,
330    s_MatchEntry,
331    ::PL_DHashMoveEntryStub,
332    s_ClearEntry,
333    ::PL_DHashFinalizeStub,
334    s_InitEntry
335  };
336
337  if (!EntryType::ALLOW_MEMMOVE)
338  {
339    sOps.moveEntry = s_CopyEntry;
340  }
341  
342  if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize))
343  {
344    // if failed, reset "flag"
345    mTable.entrySize = 0;
346    return PR_FALSE;
347  }
348
349  return PR_TRUE;
350}
351
352// static definitions
353
354template<class EntryType>
355PLDHashNumber
356nsTHashtable<EntryType>::s_HashKey(PLDHashTable  *table,
357                                   const void    *key)
358{
359  return EntryType::HashKey(reinterpret_cast<const KeyTypePointer>(key));
360}
361
362template<class EntryType>
363PRBool
364nsTHashtable<EntryType>::s_MatchEntry(PLDHashTable          *table,
365                                      const PLDHashEntryHdr *entry,
366                                      const void            *key)
367{
368  return ((const EntryType*) entry)->KeyEquals(
369    reinterpret_cast<const KeyTypePointer>(key));
370}
371
372template<class EntryType>
373void
374nsTHashtable<EntryType>::s_CopyEntry(PLDHashTable          *table,
375                                     const PLDHashEntryHdr *from,
376                                     PLDHashEntryHdr       *to)
377{
378  EntryType* fromEntry =
379    const_cast<EntryType*>(reinterpret_cast<const EntryType*>(from));
380
381  new(to) EntryType(*fromEntry);
382
383  fromEntry->~EntryType();
384}
385
386template<class EntryType>
387void
388nsTHashtable<EntryType>::s_ClearEntry(PLDHashTable    *table,
389                                      PLDHashEntryHdr *entry)
390{
391  reinterpret_cast<EntryType*>(entry)->~EntryType();
392}
393
394template<class EntryType>
395PRBool
396nsTHashtable<EntryType>::s_InitEntry(PLDHashTable    *table,
397                                     PLDHashEntryHdr *entry,
398                                     const void      *key)
399{
400  new(entry) EntryType(reinterpret_cast<KeyTypePointer>(key));
401  return PR_TRUE;
402}
403
404template<class EntryType>
405PLDHashOperator
406nsTHashtable<EntryType>::s_EnumStub(PLDHashTable    *table,
407                                    PLDHashEntryHdr *entry,
408                                    PRUint32         number,
409                                    void            *arg)
410{
411  // dereferences the function-pointer to the user's enumeration function
412  return (* reinterpret_cast<s_EnumArgs*>(arg)->userFunc)(
413    reinterpret_cast<EntryType*>(entry),
414    reinterpret_cast<s_EnumArgs*>(arg)->userArg);
415}
416
417#endif // nsTHashtable_h__