Commit 6c2bec59 authored by bsmedberg%covad.net's avatar bsmedberg%covad.net
Browse files

Bug 201034 non-const enumeration in nsBaseHashtable, add

nsTHashtable::RawRemove. Add a hashtable test-suite, and
clean up some codesize issues. Also fixes bug 203030 and
hopefully SunOS build bustage. r=jkeiser sr=alecf a=asa
parent 893ea237
Loading
Loading
Loading
Loading
+83 −13
Original line number Original line Diff line number Diff line
@@ -136,8 +136,6 @@ public:


  /**
  /**
   * function type provided by the application for enumeration.
   * function type provided by the application for enumeration.
   * currently, only "read" enumeration is supported.  If you need to change
   * or remove entries during enumeration, it might could be arranged.
   * @param aKey the key being enumerated
   * @param aKey the key being enumerated
   * @param aData data being enumerated
   * @param aData data being enumerated
   * @parm userArg passed unchanged from Enumerate
   * @parm userArg passed unchanged from Enumerate
@@ -147,7 +145,7 @@ public:
   */
   */
  typedef PLDHashOperator
  typedef PLDHashOperator
    (*PR_CALLBACK EnumReadFunction)(KeyType      aKey,
    (*PR_CALLBACK EnumReadFunction)(KeyType      aKey,
                                    DataType aData,
                                    UserDataType aData,
                                    void*        userArg);
                                    void*        userArg);


  /**
  /**
@@ -157,7 +155,31 @@ public:
   * @param enumFunc enumeration callback
   * @param enumFunc enumeration callback
   * @param userArg passed unchanged to the EnumReadFunction
   * @param userArg passed unchanged to the EnumReadFunction
   */
   */
  void EnumerateRead(EnumReadFunction enumFunc, void* userArg) const;
  PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const;

  /**
   * function type provided by the application for enumeration.
   * @param aKey the key being enumerated
   * @param aData Reference to data being enumerated, may be altered. e.g. for
   *        nsInterfaceHashtable this is an nsCOMPtr reference...
   * @parm userArg passed unchanged from Enumerate
   * @return bitflag combination of
   *   @link PLDHashOperator::PL_DHASH_REMOVE @endlink,
   *   @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or
   *   @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
   */
  typedef PLDHashOperator
    (*PR_CALLBACK EnumFunction)(KeyType       aKey,
                                DataType&     aData,
                                void*         userArg);

  /**
   * enumerate entries in the hashtable, allowing changes. This
   * functions write-locks the hashtable.
   * @param enumFunc enumeration callback
   * @param userArg passed unchanged to the EnumFunction
   */
  PRUint32 Enumerate(EnumFunction enumFunc, void* userArg);


  /**
  /**
   * reset the hashtable, removing all entries
   * reset the hashtable, removing all entries
@@ -182,6 +204,17 @@ protected:
                                        PLDHashEntryHdr *hdr,
                                        PLDHashEntryHdr *hdr,
                                        PRUint32         number,
                                        PRUint32         number,
                                        void            *arg);
                                        void            *arg);

  struct s_EnumArgs
  {
    EnumFunction func;
    void* userArg;
  };

  static PLDHashOperator s_EnumStub(PLDHashTable      *table,
                                    PLDHashEntryHdr   *hdr,
                                    PRUint32           number,
                                    void              *arg);
};
};


//
//
@@ -251,7 +284,7 @@ nsBaseHashtable<KeyClass,DataType,UserDataType>::Get(KeyType aKey,
  if (mLock)
  if (mLock)
    PR_RWLock_Rlock(mLock);
    PR_RWLock_Rlock(mLock);


  EntryType* ent = GetEntry(KeyClass::KeyToPointer(aKey));
  EntryType* ent = GetEntry(aKey);


  if (ent)
  if (ent)
  {
  {
@@ -278,7 +311,7 @@ nsBaseHashtable<KeyClass,DataType,UserDataType>::Put(KeyType aKey,
  if (mLock)
  if (mLock)
    PR_RWLock_Wlock(mLock);
    PR_RWLock_Wlock(mLock);


  EntryType* ent = PutEntry(KeyClass::KeyToPointer(aKey));
  EntryType* ent = PutEntry(aKey);


  if (!ent)
  if (!ent)
  {
  {
@@ -303,14 +336,14 @@ nsBaseHashtable<KeyClass,DataType,UserDataType>::Remove(KeyType aKey)
  if (mLock)
  if (mLock)
    PR_RWLock_Wlock(mLock);
    PR_RWLock_Wlock(mLock);


  RemoveEntry(KeyClass::KeyToPointer(aKey));
  RemoveEntry(aKey);


  if (mLock)
  if (mLock)
    PR_RWLock_Unlock(mLock);
    PR_RWLock_Unlock(mLock);
}
}


template<class KeyClass,class DataType,class UserDataType>
template<class KeyClass,class DataType,class UserDataType>
void
PRUint32
nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead
nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead
  (EnumReadFunction fEnumCall, void* userArg) const
  (EnumReadFunction fEnumCall, void* userArg) const
{
{
@@ -321,12 +354,38 @@ nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead
    PR_RWLock_Rlock(mLock);
    PR_RWLock_Rlock(mLock);


  s_EnumReadArgs enumData = { fEnumCall, userArg };
  s_EnumReadArgs enumData = { fEnumCall, userArg };
  PRUint32 count =
    PL_DHashTableEnumerate(NS_CONST_CAST(PLDHashTable*,&mTable),
    PL_DHashTableEnumerate(NS_CONST_CAST(PLDHashTable*,&mTable),
                           s_EnumReadStub,
                           &enumData);

  if (mLock)
    PR_RWLock_Unlock(mLock);

  return count;
}

template<class KeyClass,class DataType,class UserDataType>
PRUint32
nsBaseHashtable<KeyClass,DataType,UserDataType>::Enumerate
  (EnumFunction fEnumCall, void* userArg)
{
  NS_ASSERTION(mTable.entrySize,
               "nsBaseHashtable was not initialized properly.");

  if (mLock)
    PR_RWLock_Wlock(mLock);

  s_EnumArgs enumData = { fEnumCall, userArg };
  PRUint32 count =
    PL_DHashTableEnumerate(&mTable,
                           s_EnumStub,
                           s_EnumStub,
                           &enumData);
                           &enumData);


  if (mLock)
  if (mLock)
    PR_RWLock_Unlock(mLock);
    PR_RWLock_Unlock(mLock);

  return count;
}
}


template<class KeyClass,class DataType,class UserDataType>
template<class KeyClass,class DataType,class UserDataType>
@@ -360,4 +419,15 @@ nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumReadStub
  return PL_DHASH_NEXT;
  return PL_DHASH_NEXT;
}
}


template<class KeyClass,class DataType,class UserDataType>
PLDHashOperator
nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumStub
  (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg)
{
  EntryType* ent = NS_STATIC_CAST(EntryType*, hdr);
  s_EnumArgs* eargs = (s_EnumArgs*) arg;

  return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg);
}

#endif // nsBaseHashtable_h__
#endif // nsBaseHashtable_h__
+5 −3
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@


#include "nsBaseHashtable.h"
#include "nsBaseHashtable.h"
#include "nsHashKeys.h"
#include "nsHashKeys.h"
#include "nsAutoPtr.h"


/**
/**
 * templated hashtable class maps keys to C++ object pointers.
 * templated hashtable class maps keys to C++ object pointers.
@@ -55,7 +56,7 @@ class nsClassHashtable :
{
{
public:
public:
  typedef typename KeyClass::KeyType KeyType;
  typedef typename KeyClass::KeyType KeyType;
  typedef typename T* UserDataType;
  typedef T* UserDataType;


  /**
  /**
   * @copydoc nsBaseHashtable::nsBaseHashtable
   * @copydoc nsBaseHashtable::nsBaseHashtable
@@ -74,6 +75,7 @@ public:
  PRBool Get(KeyType aKey, UserDataType* pData) const;
  PRBool Get(KeyType aKey, UserDataType* pData) const;
};
};



//
//
// nsClassHashtable definitions
// nsClassHashtable definitions
//
//
@@ -86,7 +88,7 @@ nsClassHashtable<KeyClass,T>::Get(KeyType aKey, T** retVal) const
    PR_RWLock_Rlock(mLock);
    PR_RWLock_Rlock(mLock);


  typename nsBaseHashtable<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent =
  typename nsBaseHashtable<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent =
    GetEntry(KeyClass::KeyToPointer(aKey));
    GetEntry(aKey);


  if (ent)
  if (ent)
  {
  {
+10 −13
Original line number Original line Diff line number Diff line
@@ -49,19 +49,15 @@
#include NEW_H
#include NEW_H


/** @file nsHashKeys.h
/** @file nsHashKeys.h
 * standard HashKey classes for nsDataHashtable and relatives. Each of these
 * standard HashKey classes for nsBaseHashtable and relatives. Each of these
 * classes follows the nsTHashtable::EntryType specification
 * classes follows the nsTHashtable::EntryType specification
 *
 *
 * Lightweight keytypes are provided here:
 * Lightweight keytypes provided here:
 * nsStringHashKey
 * nsStringHashKey
 * nsCStringHashKey
 * nsCStringHashKey
 * nsUint32HashKey
 * nsUint32HashKey
 * nsISupportsHashKey
 * nsISupportsHashKey
 * nsIDHashKey
 * nsIDHashKey
 *
 * Use these keytypes if possible; the templates are already instantiated
 * for them, and they can be dynamically linked and therefore reduce code
 * size!
 */
 */


/**
/**
@@ -91,7 +87,7 @@ public:
  {
  {
    return HashString(*aKey);
    return HashString(*aKey);
  }
  }
  static PRBool AllowMemMove() { return PR_TRUE; }
  enum { ALLOW_MEMMOVE = PR_TRUE };


private:
private:
  const nsString mStr;
  const nsString mStr;
@@ -122,7 +118,7 @@ public:
  {
  {
    return HashString(*aKey);
    return HashString(*aKey);
  }
  }
  static PRBool AllowMemMove() { return PR_TRUE; }
  enum { ALLOW_MEMMOVE = PR_TRUE };


private:
private:
  const nsCString mStr;
  const nsCString mStr;
@@ -149,7 +145,7 @@ public:


  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
  static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; }
  static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; }
  static PRBool AllowMemMove() { return PR_TRUE; }
  enum { ALLOW_MEMMOVE = PR_TRUE };


private:
private:
  const PRUint32 mValue;
  const PRUint32 mValue;
@@ -166,7 +162,8 @@ public:
  typedef nsISupports* KeyType;
  typedef nsISupports* KeyType;
  typedef const nsISupports* KeyTypePointer;
  typedef const nsISupports* KeyTypePointer;


  nsISupportsHashKey(nsISupports* key) : mSupports(key) { }
  nsISupportsHashKey(const nsISupports* key) :
    mSupports(NS_CONST_CAST(nsISupports*,key)) { }
  nsISupportsHashKey(const nsISupportsHashKey& toCopy) :
  nsISupportsHashKey(const nsISupportsHashKey& toCopy) :
    mSupports(toCopy.mSupports) { }
    mSupports(toCopy.mSupports) { }
  ~nsISupportsHashKey() { }
  ~nsISupportsHashKey() { }
@@ -181,10 +178,10 @@ public:
  {
  {
    return NS_PTR_TO_INT32(aKey) >>2;
    return NS_PTR_TO_INT32(aKey) >>2;
  }
  }
  static PRBool AllowMemMove() { return PR_TRUE; }
  enum { ALLOW_MEMMOVE = PR_TRUE };


private:
private:
  const nsCOMPtr<nsISupports> mSupports;
  nsCOMPtr<nsISupports> mSupports;
};
};


/**
/**
@@ -208,7 +205,7 @@ public:


  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
  static PLDHashNumber HashKey(KeyTypePointer aKey);
  static PLDHashNumber HashKey(KeyTypePointer aKey);
  static PRBool AllowMemMove() { return PR_TRUE; }
  enum { ALLOW_MEMMOVE = PR_TRUE };


private:
private:
  const nsID mID;
  const nsID mID;
+1 −1
Original line number Original line Diff line number Diff line
@@ -89,7 +89,7 @@ nsInterfaceHashtable<KeyClass,Interface>::Get
    PR_RWLock_Rlock(mLock);
    PR_RWLock_Rlock(mLock);


  typename nsBaseHashtable<KeyClass, nsCOMPtr<Interface>, Interface*>::EntryType* ent =
  typename nsBaseHashtable<KeyClass, nsCOMPtr<Interface>, Interface*>::EntryType* ent =
    GetEntry(KeyClass::KeyToPointer(aKey));
    GetEntry(aKey);


  if (ent)
  if (ent)
  {
  {
+71 −64
Original line number Original line Diff line number Diff line
@@ -53,7 +53,7 @@
 *   and <strong>must not declare any virtual functions or derive from classes
 *   and <strong>must not declare any virtual functions or derive from classes
 *   with virtual functions.</strong>  Any vtable pointer would break the
 *   with virtual functions.</strong>  Any vtable pointer would break the
 *   PLDHashTable code.
 *   PLDHashTable code.
 *<pre>   class EntryType : PLDHashEntryHdr
 *<pre>   class EntryType : public PLDHashEntryHdr
 *   {
 *   {
 *   public: or friend nsTHashtable<EntryType>;
 *   public: or friend nsTHashtable<EntryType>;
 *     // KeyType is what we use when Get()ing or Put()ing this entry
 *     // KeyType is what we use when Get()ing or Put()ing this entry
@@ -85,9 +85,9 @@
 *     // HashKey(): calculate the hash number
 *     // HashKey(): calculate the hash number
 *     static PLDHashNumber HashKey(KeyTypePointer aKey);
 *     static PLDHashNumber HashKey(KeyTypePointer aKey);
 *
 *
 *     // AllowMemMove(): can we move this class with memmove(), or do we have
 *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
 *     // to use the copy constructor?
 *     // to use the copy constructor?
 *     static PRBool AllowMemMove();
 *     enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) };
 *   }</pre>
 *   }</pre>
 *
 *
 * @see nsInterfaceHashtable
 * @see nsInterfaceHashtable
@@ -111,13 +111,19 @@ public:
  ~nsTHashtable();
  ~nsTHashtable();


  /**
  /**
   * Initialize the class.  This function must be called before any other
   * Initialize the table.  This function must be called before any other
   * class operations.  This can fail due to OOM conditions.
   * class operations.  This can fail due to OOM conditions.
   * @param initSize the initial number of buckets in the hashtable, default 16
   * @param initSize the initial number of buckets in the hashtable, default 16
   * @return PR_TRUE if the class was initialized properly.
   * @return PR_TRUE if the class was initialized properly.
   */
   */
  PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE);
  PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE);


  /**
   * Check whether the table has been initialized. This can be useful for static hashtables.
   * @return the initialization state of the class.
   */
  PRBool IsInitialized() const { return mTable.entrySize; }

  /**
  /**
   * KeyType is typedef'ed for ease of use.
   * KeyType is typedef'ed for ease of use.
   */
   */
@@ -134,7 +140,18 @@ public:
   * @return    pointer to the entry class, if the key exists; nsnull if the
   * @return    pointer to the entry class, if the key exists; nsnull if the
   *            key doesn't exist
   *            key doesn't exist
   */
   */
  EntryType* GetEntry(KeyTypePointer aKey) const;
  EntryType* GetEntry(KeyType aKey) const
  {
    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
  
    EntryType* entry =
      NS_REINTERPRET_CAST(EntryType*,
                          PL_DHashTableOperate(
                            NS_CONST_CAST(PLDHashTable*,&mTable),
                            EntryType::KeyToPointer(aKey),
                            PL_DHASH_LOOKUP));
    return PL_DHASH_ENTRY_IS_BUSY(entry) ?  entry : nsnull;
  }


  /**
  /**
   * Get the entry associated with a key, or create a new entry,
   * Get the entry associated with a key, or create a new entry,
@@ -142,13 +159,42 @@ public:
   * @return    pointer to the entry class retreived; nsnull only if memory
   * @return    pointer to the entry class retreived; nsnull only if memory
                can't be allocated
                can't be allocated
   */
   */
  EntryType* PutEntry(KeyTypePointer aKey);
  EntryType* PutEntry(KeyType aKey)
  {
    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
    
    return NS_STATIC_CAST(EntryType*,
                          PL_DHashTableOperate(
                            &mTable,
                            EntryType::KeyToPointer(aKey),
                            PL_DHASH_ADD));
  }


  /**
  /**
   * Remove the entry associated with a key.
   * Remove the entry associated with a key.
   * @param     aKey of the entry to remove
   * @param     aKey of the entry to remove
   */
   */
  void RemoveEntry(KeyTypePointer aKey);
  void RemoveEntry(KeyType aKey)
  {
    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

    PL_DHashTableOperate(&mTable,
                         EntryType::KeyToPointer(aKey),
                         PL_DHASH_REMOVE);
  }

  /**
   * Remove the entry associated with a key, but don't resize the hashtable.
   * This is a low-level method, and is not recommended unless you know what
   * you're doing and you need the extra performance. This method can be used
   * during enumeration, while RemoveEntry() cannot.
   * @param aEntry   the entry-pointer to remove (obtained from GetEntry or
   *                 the enumerator
   */
  void RawRemoveEntry(EntryType* aEntry)
  {
    PL_DHashTableRawRemove(&mTable, aEntry);
  }


  /**
  /**
   * client must provide an <code>Enumerator</code> function for
   * client must provide an <code>Enumerator</code> function for
@@ -169,12 +215,23 @@ public:
   *            <code>Enumerator</code> function
   *            <code>Enumerator</code> function
   * @return    the number of entries actually enumerated
   * @return    the number of entries actually enumerated
   */
   */
  PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg);
  PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg)
  {
    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
    
    s_EnumArgs args = { enumFunc, userArg };
    return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args);
  }


  /**
  /**
   * remove all entries, return hashtable to "pristine" state ;)
   * remove all entries, return hashtable to "pristine" state ;)
   */
   */
  void Clear();
  void Clear()
  {
    NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

    PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull);
  }


protected:
protected:
  PLDHashTable mTable;
  PLDHashTable mTable;
@@ -254,9 +311,12 @@ nsTHashtable<EntryType>::Init(PRUint32 initSize)
  if (mTable.entrySize)
  if (mTable.entrySize)
  {
  {
    NS_ERROR("nsTHashtable::Init() should not be called twice.");
    NS_ERROR("nsTHashtable::Init() should not be called twice.");
    return PR_FALSE;
    return PR_TRUE;
  }
  }


  if (!EntryType::ALLOW_MEMMOVE)
    sOps.moveEntry = s_CopyEntry;
  
  if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize))
  if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize))
  {
  {
    // if failed, reset "flag"
    // if failed, reset "flag"
@@ -267,59 +327,6 @@ nsTHashtable<EntryType>::Init(PRUint32 initSize)
  return PR_TRUE;
  return PR_TRUE;
}
}


template<class EntryType>
EntryType*
nsTHashtable<EntryType>::GetEntry(KeyTypePointer aKey) const
{
  NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
  
  return NS_REINTERPRET_CAST(EntryType*,
                             PL_DHashTableOperate(
                               NS_CONST_CAST(PLDHashTable*,&mTable),
                               aKey,
                               PL_DHASH_LOOKUP));
}

template<class EntryType>
EntryType*
nsTHashtable<EntryType>::PutEntry(KeyTypePointer aKey)
{
  NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

  return (EntryType*) PL_DHashTableOperate(&mTable, aKey, PL_DHASH_ADD);
}

template<class EntryType>
void
nsTHashtable<EntryType>::RemoveEntry(KeyTypePointer aKey)
{
  NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

  PL_DHashTableOperate(&mTable, aKey, PL_DHASH_REMOVE);

  return;
}

template<class EntryType>
PRUint32
nsTHashtable<EntryType>::EnumerateEntries(Enumerator enumFunc, void* userArg)
{
  NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

  s_EnumArgs args = { enumFunc, userArg };
  
  return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args);
}

template<class EntryType>
void
nsTHashtable<EntryType>::Clear()
{
  NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");

  PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull);
}

// static definitions
// static definitions


template<class EntryType>
template<class EntryType>
@@ -331,7 +338,7 @@ nsTHashtable<EntryType>::sOps =
  s_GetKey,
  s_GetKey,
  s_HashKey,
  s_HashKey,
  s_MatchEntry,
  s_MatchEntry,
  EntryType::AllowMemMove() ? ::PL_DHashMoveEntryStub : s_CopyEntry,
  PL_DHashMoveEntryStub,
  s_ClearEntry,
  s_ClearEntry,
  ::PL_DHashFinalizeStub,
  ::PL_DHashFinalizeStub,
  s_InitEntry
  s_InitEntry