зеркало из https://github.com/mozilla/pjs.git
Add generalized macro-based PLDHashTable C++ wrapper (bug 125849), r=alecf, sr=brendan
This commit is contained in:
Родитель
a4a78a193b
Коммит
71f58218a9
|
@ -91,6 +91,21 @@ class nsFormControlList;
|
||||||
|
|
||||||
// nsHTMLFormElement
|
// nsHTMLFormElement
|
||||||
|
|
||||||
|
//
|
||||||
|
// PLDHashTable entry for radio button
|
||||||
|
//
|
||||||
|
class PLDHashStringRadioEntry : public PLDHashStringEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLDHashStringRadioEntry(const void* key) : PLDHashStringEntry(key), mVal(nsnull) { }
|
||||||
|
~PLDHashStringRadioEntry() { }
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMHTMLInputElement> mVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_DHASH_WRAPPER(nsDoubleHashtableStringRadio, PLDHashStringRadioEntry, nsAString&)
|
||||||
|
DHASH_WRAPPER(nsDoubleHashtableStringRadio, PLDHashStringRadioEntry, nsAString&)
|
||||||
|
|
||||||
class nsHTMLFormElement : public nsGenericHTMLContainerElement,
|
class nsHTMLFormElement : public nsGenericHTMLContainerElement,
|
||||||
public nsSupportsWeakReference,
|
public nsSupportsWeakReference,
|
||||||
public nsIDOMHTMLFormElement,
|
public nsIDOMHTMLFormElement,
|
||||||
|
@ -231,7 +246,7 @@ protected:
|
||||||
// Data members
|
// Data members
|
||||||
//
|
//
|
||||||
nsFormControlList *mControls;
|
nsFormControlList *mControls;
|
||||||
nsDoubleHashtableStringSupports mSelectedRadioButtons;
|
nsDoubleHashtableStringRadio mSelectedRadioButtons;
|
||||||
PRPackedBool mGeneratingSubmit;
|
PRPackedBool mGeneratingSubmit;
|
||||||
PRPackedBool mGeneratingReset;
|
PRPackedBool mGeneratingReset;
|
||||||
PRPackedBool mIsSubmitting;
|
PRPackedBool mIsSubmitting;
|
||||||
|
@ -387,7 +402,7 @@ nsHTMLFormElement::Init(nsINodeInfo *aNodeInfo)
|
||||||
}
|
}
|
||||||
NS_ADDREF(mControls);
|
NS_ADDREF(mControls);
|
||||||
|
|
||||||
rv = mSelectedRadioButtons.Init();
|
rv = mSelectedRadioButtons.Init(1);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1300,12 +1315,6 @@ nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex)
|
nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex)
|
||||||
{
|
{
|
||||||
|
@ -1318,14 +1327,21 @@ NS_IMETHODIMP
|
||||||
nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
|
nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
|
||||||
nsIDOMHTMLInputElement* aRadio)
|
nsIDOMHTMLInputElement* aRadio)
|
||||||
{
|
{
|
||||||
return mSelectedRadioButtons.Put(aName, (nsISupports*)aRadio);
|
PLDHashStringRadioEntry* entry = mSelectedRadioButtons.AddEntry(aName);
|
||||||
|
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
entry->mVal = aRadio;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName,
|
nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName,
|
||||||
nsIDOMHTMLInputElement** aRadio)
|
nsIDOMHTMLInputElement** aRadio)
|
||||||
{
|
{
|
||||||
*aRadio = (nsIDOMHTMLInputElement*)mSelectedRadioButtons.Get(aName).get();
|
PLDHashStringRadioEntry* entry = mSelectedRadioButtons.GetEntry(aName);
|
||||||
|
if (entry) {
|
||||||
|
*aRadio = entry->mVal;
|
||||||
|
NS_IF_ADDREF(*aRadio);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,10 @@ void XXXNeverCalled()
|
||||||
dummyComparitor dummy;
|
dummyComparitor dummy;
|
||||||
nsVoidArray();
|
nsVoidArray();
|
||||||
nsSmallVoidArray();
|
nsSmallVoidArray();
|
||||||
nsDoubleHashtableStringSupports dhss;
|
nsStringHashSet();
|
||||||
|
nsCStringHashSet();
|
||||||
|
nsInt32HashSet();
|
||||||
|
nsVoidHashSet();
|
||||||
nsValueArray(0);
|
nsValueArray(0);
|
||||||
nsAVLTree(dummy, nsnull);
|
nsAVLTree(dummy, nsnull);
|
||||||
nsSupportsArray();
|
nsSupportsArray();
|
||||||
|
|
|
@ -1,205 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* ***** BEGIN LICENSE BLOCK *****
|
|
||||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Netscape Public License
|
|
||||||
* Version 1.1 (the "License"); you may not use this file except in
|
|
||||||
* compliance with the License. You may obtain a copy of the License at
|
|
||||||
* http://www.mozilla.org/NPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing rights and limitations under the
|
|
||||||
* License.
|
|
||||||
*
|
|
||||||
* The Original Code is Mozilla Communicator client code.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is
|
|
||||||
* Netscape Communications Corporation.
|
|
||||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
||||||
* the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
||||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
||||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
||||||
* of those above. If you wish to allow use of your version of this file only
|
|
||||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
||||||
* use your version of this file under the terms of the NPL, indicate your
|
|
||||||
* decision by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
||||||
* the provisions above, a recipient may use your version of this file under
|
|
||||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
||||||
*
|
|
||||||
* ***** END LICENSE BLOCK ***** */
|
|
||||||
|
|
||||||
#include "nsDoubleHashtable.h"
|
|
||||||
#include "nsISupports.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "nsReadableUtils.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// KEY String
|
|
||||||
//
|
|
||||||
class PLDHashStringEntry : public PLDHashEntryHdr
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PLDHashStringEntry(const nsAString& aString) :
|
|
||||||
mKey(aString) { }
|
|
||||||
|
|
||||||
nsString mKey;
|
|
||||||
};
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(const void *)
|
|
||||||
PLDHashStringGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
|
|
||||||
{
|
|
||||||
PLDHashStringEntry *e = NS_STATIC_CAST(PLDHashStringEntry *, entry);
|
|
||||||
|
|
||||||
return NS_STATIC_CAST(const nsAString *, &e->mKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PLDHashNumber)
|
|
||||||
PLDHashStringHashKey(PLDHashTable *table, const void *key)
|
|
||||||
{
|
|
||||||
const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
|
|
||||||
|
|
||||||
return HashString(*str);
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(PRBool)
|
|
||||||
PLDHashStringMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
|
|
||||||
const void *key)
|
|
||||||
{
|
|
||||||
const PLDHashStringEntry *e =
|
|
||||||
NS_STATIC_CAST(const PLDHashStringEntry *, entry);
|
|
||||||
const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
|
|
||||||
|
|
||||||
return str->Equals(e->mKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ENTRY StringSupports
|
|
||||||
//
|
|
||||||
class PLDHashStringSupportsEntry : public PLDHashStringEntry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PLDHashStringSupportsEntry(const nsAString& aString) :
|
|
||||||
PLDHashStringEntry(aString)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~PLDHashStringSupportsEntry() {
|
|
||||||
}
|
|
||||||
nsCOMPtr<nsISupports> mVal;
|
|
||||||
};
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(void)
|
|
||||||
PLDHashStringSupportsClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
|
||||||
{
|
|
||||||
PLDHashStringSupportsEntry *e = NS_STATIC_CAST(PLDHashStringSupportsEntry *,
|
|
||||||
entry);
|
|
||||||
// An entry is being cleared, let the entry down its own cleanup.
|
|
||||||
e->~PLDHashStringSupportsEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_STATIC_CALLBACK(void)
|
|
||||||
PLDHashStringSupportsInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
|
|
||||||
const void *key)
|
|
||||||
{
|
|
||||||
const nsAString *keyStr = NS_STATIC_CAST(const nsAString *, key);
|
|
||||||
// Initialize the entry with placement new
|
|
||||||
new (entry) PLDHashStringSupportsEntry(*keyStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define INIT_STRING_HASH(_HASHNAME_) \
|
|
||||||
static PLDHashTableOps hash_table_ops = \
|
|
||||||
{ \
|
|
||||||
PL_DHashAllocTable, \
|
|
||||||
PL_DHashFreeTable, \
|
|
||||||
PLDHashStringGetKey, \
|
|
||||||
PLDHashStringHashKey, \
|
|
||||||
PLDHashStringMatchEntry, \
|
|
||||||
PL_DHashMoveEntryStub, \
|
|
||||||
_HASHNAME_##ClearEntry, \
|
|
||||||
PL_DHashFinalizeStub, \
|
|
||||||
_HASHNAME_##InitEntry \
|
|
||||||
}; \
|
|
||||||
if (!mHashTable.ops) { \
|
|
||||||
PRBool isLive = PL_DHashTableInit(&mHashTable, \
|
|
||||||
&hash_table_ops, nsnull, \
|
|
||||||
sizeof(_HASHNAME_##Entry), 16); \
|
|
||||||
if (!isLive) { \
|
|
||||||
mHashTable.ops = nsnull; \
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// HASH StringSupports
|
|
||||||
//
|
|
||||||
nsDoubleHashtableStringSupports::nsDoubleHashtableStringSupports()
|
|
||||||
{
|
|
||||||
// MUST init mHashTable.ops to nsnull so that we can detect that the
|
|
||||||
// hashtable has not been initialized.
|
|
||||||
mHashTable.ops = nsnull;
|
|
||||||
};
|
|
||||||
|
|
||||||
nsDoubleHashtableStringSupports::~nsDoubleHashtableStringSupports()
|
|
||||||
{
|
|
||||||
if (mHashTable.ops) {
|
|
||||||
PL_DHashTableFinish(&mHashTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsDoubleHashtableStringSupports::Init()
|
|
||||||
{
|
|
||||||
INIT_STRING_HASH(PLDHashStringSupports)
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsISupports>
|
|
||||||
nsDoubleHashtableStringSupports::Get(const nsAString& aKey)
|
|
||||||
{
|
|
||||||
PLDHashStringSupportsEntry * entry =
|
|
||||||
NS_STATIC_CAST(PLDHashStringSupportsEntry *,
|
|
||||||
PL_DHashTableOperate(&mHashTable, &aKey,
|
|
||||||
PL_DHASH_LOOKUP));
|
|
||||||
if (!PL_DHASH_ENTRY_IS_LIVE(entry)) {
|
|
||||||
return nsnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsISupports* supports = entry->mVal;
|
|
||||||
NS_IF_ADDREF(supports);
|
|
||||||
return supports;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsDoubleHashtableStringSupports::Put(const nsAString& aKey,
|
|
||||||
nsISupports* aResult)
|
|
||||||
{
|
|
||||||
PLDHashStringSupportsEntry * entry =
|
|
||||||
NS_STATIC_CAST(PLDHashStringSupportsEntry *,
|
|
||||||
PL_DHashTableOperate(&mHashTable, &aKey,
|
|
||||||
PL_DHASH_ADD));
|
|
||||||
|
|
||||||
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Add the entry
|
|
||||||
//
|
|
||||||
entry->mVal = aResult;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsDoubleHashtableStringSupports::Remove(nsAString& aKey)
|
|
||||||
{
|
|
||||||
PL_DHashTableOperate(&mHashTable, &aKey, PL_DHASH_REMOVE);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
|
@ -36,53 +36,521 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef __nsDoubleHashtable_h__
|
||||||
|
#define __nsDoubleHashtable_h__
|
||||||
|
|
||||||
#include "pldhash.h"
|
#include "pldhash.h"
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsString.h"
|
||||||
|
#include "nsReadableUtils.h"
|
||||||
|
|
||||||
class nsAString;
|
/*
|
||||||
class nsISupports;
|
* This file provides several major things to make PLDHashTable easier to use:
|
||||||
|
* - hash class macros for you to define a hashtable
|
||||||
/**
|
* - default key classes to use as superclasses for your entries
|
||||||
* nsDoubleHashtableStringSupports
|
* - empty maps for string, cstring, int and void
|
||||||
*
|
|
||||||
* A hashtable from string -> nsISupports*. Holds strong references.
|
|
||||||
*/
|
*/
|
||||||
class NS_COM nsDoubleHashtableStringSupports {
|
|
||||||
public:
|
|
||||||
nsDoubleHashtableStringSupports();
|
|
||||||
~nsDoubleHashtableStringSupports();
|
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Get the value referenced by the key.
|
* USAGE
|
||||||
* Being a getter, this returns a strong reference.
|
*
|
||||||
* @param aKey the key
|
* To use nsDoubleHashtable macros
|
||||||
* @return the object referenced by aKey, or nsnull if none
|
* (1) Define an entry class
|
||||||
*/
|
* (2) Create the hash class
|
||||||
already_AddRefed<nsISupports> Get(const nsAString& aKey);
|
* (3) Use the hash class
|
||||||
|
*
|
||||||
|
* EXAMPLE
|
||||||
|
*
|
||||||
|
* As an example, let's create a dictionary, a mapping from a string (the word)
|
||||||
|
* to the pronunciation and definition of those words.
|
||||||
|
*
|
||||||
|
* (1) Define an entry class
|
||||||
|
*
|
||||||
|
* What we want here is an entry class that contains the word, the
|
||||||
|
* pronunciation string, and the definition string. Since we have a string key
|
||||||
|
* we can use the standard PLDHashStringEntry class as our base, it will handle
|
||||||
|
* the key stuff for us automatically.
|
||||||
|
*
|
||||||
|
* #include "nsDoubleHashtable.h"
|
||||||
|
*
|
||||||
|
* // Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break.
|
||||||
|
* // This is because of the 4-byte pointer C++ magically prepends onto your
|
||||||
|
* // entry class. It interacts very unhappily with PLDHashTable.
|
||||||
|
* class DictionaryEntry : public PLDHashStringEntry {
|
||||||
|
* public:
|
||||||
|
* DictionaryEntry(const void* aKey) : PLDHashStringEntry(aKey) { }
|
||||||
|
* ~DictionaryEntry() { }
|
||||||
|
* nsString mPronunciation;
|
||||||
|
* nsString mDefinition;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* (2) Create the hash class
|
||||||
|
*
|
||||||
|
* The final hash class you will use in step 3 is defined by 2 macros.
|
||||||
|
*
|
||||||
|
* DECL_DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&)
|
||||||
|
* DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&)
|
||||||
|
*
|
||||||
|
* (3) Use the hash class
|
||||||
|
*
|
||||||
|
* Here is a simple main() that might look up a string:
|
||||||
|
*
|
||||||
|
* int main(void) {
|
||||||
|
* Dictionary d;
|
||||||
|
* nsresult rv = d.Init(10);
|
||||||
|
* if (NS_FAILED(rv)) return 1;
|
||||||
|
*
|
||||||
|
* // Put an entry
|
||||||
|
* DictionaryEntry* a = d.AddEntry(NS_LITERAL_STRING("doomed"));
|
||||||
|
* if (!a) return 1;
|
||||||
|
* a->mDefinition = NS_LITERAL_STRING("The state you get in when a Mozilla release is pending");
|
||||||
|
* a->mPronunciation = NS_LITERAL_STRING("doom-d");
|
||||||
|
*
|
||||||
|
* // Get the entry
|
||||||
|
* DictionaryEntry* b = d.GetEntry(NS_LITERAL_STRING("doomed"));
|
||||||
|
* printf("doomed: %s\n", NS_ConvertUCS2toUTF8(b->mDefinition).get());
|
||||||
|
*
|
||||||
|
* // Entries will be automagically cleaned up when the Dictionary object goes away
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* BONUS POINTS
|
||||||
|
*
|
||||||
|
* You may wish to extend this class and add helper functions like
|
||||||
|
* nsDependentString* GetDefinition(nsAString& aWord). For example:
|
||||||
|
*
|
||||||
|
* class MyDictionary : public Dictionary {
|
||||||
|
* public:
|
||||||
|
* MyDictionary() { }
|
||||||
|
* // Make SURE you have a virtual destructor
|
||||||
|
* virtual ~myDictionary() { }
|
||||||
|
* nsDependentString* GetDefinition(const nsAString& aWord) {
|
||||||
|
* DictionaryEntry* e = GetEntry(aWord);
|
||||||
|
* if (e) {
|
||||||
|
* // We're returning an nsDependentString here, callers need to delete it
|
||||||
|
* // and it doesn't last long, but at least it doesn't create a copy
|
||||||
|
* return new nsDependentString(e->mDefinition.get());
|
||||||
|
* } else {
|
||||||
|
* return nsnull;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* nsresult PutDefinition(const nsAString& aWord,
|
||||||
|
* const nsAString& aDefinition,
|
||||||
|
* const nsAString& aPronunciation) {
|
||||||
|
* DictionaryEntry* e = AddEntry(aWord);
|
||||||
|
* if (!e) {
|
||||||
|
* return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
* }
|
||||||
|
* e->mDefinition = aDefinition;
|
||||||
|
* e->mPronunciation = aPronunciation;
|
||||||
|
* return NS_OK;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Put the value into the hash to be referenced by the key.
|
* ENTRY CLASS DEFINITION
|
||||||
* @param aKey the key
|
*
|
||||||
* @param aResult the return value
|
* The simplifications of PLDHashTable all hinge upon the idea of an entry
|
||||||
*/
|
* class, which is a class you define, where you store the key and values that
|
||||||
nsresult Put(const nsAString& aKey, nsISupports* aResult);
|
* you will place in each hash entry. You must define six methods for an entry
|
||||||
|
* (the standard key classes, which you can extend from, define all of these
|
||||||
|
* for you except the constructor and destructor):
|
||||||
|
*
|
||||||
|
* CONSTRUCTOR(const void* aKey)
|
||||||
|
* When your entry is constructed it will only be given a pointer to the key.
|
||||||
|
*
|
||||||
|
* DESTRUCTOR
|
||||||
|
* Called when the entry is destroyed (of course).
|
||||||
|
*
|
||||||
|
* const void* GetKey()
|
||||||
|
* Must return a pointer to the key
|
||||||
|
*
|
||||||
|
* PRBool MatchEntry(const void* aKey) - return true or false depending on
|
||||||
|
* whether the key pointed to by aKey matches this entry
|
||||||
|
*
|
||||||
|
* static PLDHashNumber HashKey(const void* aKey) - get a hashcode based on the
|
||||||
|
* key (must be the same every time for the same key, but does not have
|
||||||
|
* to be unique)
|
||||||
|
*
|
||||||
|
* For a small hash that just does key->value, you will often just extend a
|
||||||
|
* standard key class and put a value member into it, and have a destructor and
|
||||||
|
* constructor--nothing else necessary.
|
||||||
|
*
|
||||||
|
* See the default key entry classes as example entry classes.
|
||||||
|
*
|
||||||
|
* NOTES:
|
||||||
|
* - Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break.
|
||||||
|
* This is because of the 4-byte pointer C++ magically prepends onto your
|
||||||
|
* entry class. It interacts very unhappily with PLDHashTable.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Remove the entry from the hash referenced by the key.
|
* PRIVATE HASHTABLE MACROS
|
||||||
* @param aKey the key
|
*
|
||||||
* @param aResult the return value
|
* These internal macros can be used to declare the callbacks for an entry
|
||||||
*/
|
* class, but the wrapper class macros call these for you so don't call them.
|
||||||
nsresult Remove(nsAString& aKey);
|
*/
|
||||||
|
|
||||||
/**
|
//
|
||||||
* Initialize this hashtable. This MUST be called for the hashtable
|
// DHASH_CALLBACKS
|
||||||
* to work.
|
//
|
||||||
*/
|
// Define the hashtable callback functions. Do this in one place only, as you
|
||||||
nsresult Init();
|
// will have redundant symbols otherwise.
|
||||||
|
//
|
||||||
|
// ENTRY_CLASS: the classname of the entry
|
||||||
|
//
|
||||||
|
#define DHASH_CALLBACKS(ENTRY_CLASS) \
|
||||||
|
PR_STATIC_CALLBACK(const void *) \
|
||||||
|
ENTRY_CLASS##GetKey(PLDHashTable* table, PLDHashEntryHdr* entry) \
|
||||||
|
{ \
|
||||||
|
ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, entry); \
|
||||||
|
return e->GetKey(); \
|
||||||
|
} \
|
||||||
|
PR_STATIC_CALLBACK(PLDHashNumber) \
|
||||||
|
ENTRY_CLASS##HashKey(PLDHashTable* table, const void* key) \
|
||||||
|
{ \
|
||||||
|
return ENTRY_CLASS::HashKey(key); \
|
||||||
|
} \
|
||||||
|
PR_STATIC_CALLBACK(PRBool) \
|
||||||
|
ENTRY_CLASS##MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, \
|
||||||
|
const void *key) \
|
||||||
|
{ \
|
||||||
|
const ENTRY_CLASS* e = NS_STATIC_CAST(const ENTRY_CLASS*, entry); \
|
||||||
|
return e->MatchEntry(key); \
|
||||||
|
} \
|
||||||
|
PR_STATIC_CALLBACK(void) \
|
||||||
|
ENTRY_CLASS##ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) \
|
||||||
|
{ \
|
||||||
|
ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS *, entry); \
|
||||||
|
e->~ENTRY_CLASS(); \
|
||||||
|
} \
|
||||||
|
PR_STATIC_CALLBACK(void) \
|
||||||
|
ENTRY_CLASS##InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, \
|
||||||
|
const void *key) \
|
||||||
|
{ \
|
||||||
|
new (entry) ENTRY_CLASS(key); \
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
//
|
||||||
// Init() is protected because I want people to just be able to use the class
|
// DHASH_INIT
|
||||||
// without fussing, so it's called in the constructor.
|
//
|
||||||
PLDHashTable mHashTable;
|
// Initialize hashtable to a certain class.
|
||||||
|
//
|
||||||
|
// HASHTABLE: the name of the PLDHashTable variable
|
||||||
|
// ENTRY_CLASS: the classname of the entry
|
||||||
|
// NUM_INITIAL_ENTRIES: the number of entry slots the hashtable should start
|
||||||
|
// with
|
||||||
|
// RV: an nsresult variable to hold the outcome of the initialization.
|
||||||
|
// Will be NS_ERROR_OUT_OF_MEMORY if failed, NS_OK otherwise.
|
||||||
|
//
|
||||||
|
#define DHASH_INIT(HASHTABLE,ENTRY_CLASS,NUM_INITIAL_ENTRIES,RV) \
|
||||||
|
PR_BEGIN_MACRO \
|
||||||
|
static PLDHashTableOps hash_table_ops = \
|
||||||
|
{ \
|
||||||
|
PL_DHashAllocTable, \
|
||||||
|
PL_DHashFreeTable, \
|
||||||
|
ENTRY_CLASS##GetKey, \
|
||||||
|
ENTRY_CLASS##HashKey, \
|
||||||
|
ENTRY_CLASS##MatchEntry, \
|
||||||
|
PL_DHashMoveEntryStub, \
|
||||||
|
ENTRY_CLASS##ClearEntry, \
|
||||||
|
PL_DHashFinalizeStub, \
|
||||||
|
ENTRY_CLASS##InitEntry \
|
||||||
|
}; \
|
||||||
|
PRBool isLive = PL_DHashTableInit(&(HASHTABLE), \
|
||||||
|
&hash_table_ops, nsnull, \
|
||||||
|
sizeof(ENTRY_CLASS), \
|
||||||
|
(NUM_INITIAL_ENTRIES)); \
|
||||||
|
if (!isLive) { \
|
||||||
|
(HASHTABLE).ops = nsnull; \
|
||||||
|
RV = NS_ERROR_OUT_OF_MEMORY; \
|
||||||
|
} else { \
|
||||||
|
RV = NS_OK; \
|
||||||
|
} \
|
||||||
|
PR_END_MACRO
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WRAPPER CLASS
|
||||||
|
*
|
||||||
|
* This class handles initialization and destruction of the hashtable
|
||||||
|
* (you must call Init() yourself). It defines these functions:
|
||||||
|
*
|
||||||
|
* Init(aNumInitialEntries)
|
||||||
|
* Initialize the hashtable. This must be called once, it is only separate
|
||||||
|
* from the constructor so that you can get the return value. You should pass
|
||||||
|
* in the number of entries you think the hashtable will typically hold (this
|
||||||
|
* will be the amount of space allocated initially so that it will not have to
|
||||||
|
* grow).
|
||||||
|
*
|
||||||
|
* ENTRY_CLASS* GetEntry(aKey):
|
||||||
|
* Get the entry referenced by aKey and return a pointer to it. THIS IS A
|
||||||
|
* TEMPORARY POINTER and is only guaranteed to exist until the next time you do
|
||||||
|
* an operation on the hashtable. But you can safely use it until then.
|
||||||
|
*
|
||||||
|
* Returns nsnull if the entry is not found.
|
||||||
|
*
|
||||||
|
* ENTRY_CLASS* AddEntry(aKey):
|
||||||
|
* Create a new, empty entry and return a pointer to it for you to fill values
|
||||||
|
* into. THIS IS A TEMPORARY POINTER and is only guaranteed to exist until the
|
||||||
|
* next time you do an operation on the hashtable. But you can safely fill it
|
||||||
|
* in.
|
||||||
|
*
|
||||||
|
* Returns nsnull if the entry cannot be created (usually a low memory
|
||||||
|
* constraint).
|
||||||
|
*
|
||||||
|
* void Remove(aKey)
|
||||||
|
* Remove the entry referenced by aKey. If the entry does not exist, nothing
|
||||||
|
* will happen.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE)
|
||||||
|
*
|
||||||
|
* Declare the hash class but do not define the functions.
|
||||||
|
*
|
||||||
|
* CLASSNAME: the name of the class to declare.
|
||||||
|
* ENTRY_CLASS: the class of the entry struct.
|
||||||
|
* KEY_TYPE: the name of the key type for GetEntry and AddEntry.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE)
|
||||||
|
*
|
||||||
|
* Define the functions for the hash class.
|
||||||
|
*
|
||||||
|
* CLASSNAME: the name of the class to declare.
|
||||||
|
* ENTRY_CLASS: the class of the entry struct.
|
||||||
|
* KEY_TYPE: the name of the key type for GetEntry and AddEntry.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* CAVEATS:
|
||||||
|
* - You may have only *one* wrapper class per entry class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \
|
||||||
|
class DHASH_EXPORT CLASSNAME { \
|
||||||
|
public: \
|
||||||
|
CLASSNAME(); \
|
||||||
|
~CLASSNAME(); \
|
||||||
|
nsresult Init(PRUint32 aNumInitialEntries); \
|
||||||
|
ENTRY_CLASS* GetEntry(const KEY_TYPE aKey); \
|
||||||
|
ENTRY_CLASS* AddEntry(const KEY_TYPE aKey); \
|
||||||
|
void Remove(const KEY_TYPE aKey); \
|
||||||
|
PLDHashTable mHashTable; \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \
|
||||||
|
DHASH_CALLBACKS(ENTRY_CLASS) \
|
||||||
|
CLASSNAME::CLASSNAME() { \
|
||||||
|
mHashTable.ops = nsnull; \
|
||||||
|
} \
|
||||||
|
CLASSNAME::~CLASSNAME() { \
|
||||||
|
if (mHashTable.ops) { \
|
||||||
|
PL_DHashTableFinish(&mHashTable); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
nsresult CLASSNAME::Init(PRUint32 aNumInitialEntries) { \
|
||||||
|
if (!mHashTable.ops) { \
|
||||||
|
nsresult rv; \
|
||||||
|
DHASH_INIT(mHashTable,ENTRY_CLASS,aNumInitialEntries,rv); \
|
||||||
|
return rv; \
|
||||||
|
} \
|
||||||
|
return NS_OK; \
|
||||||
|
} \
|
||||||
|
ENTRY_CLASS* CLASSNAME::GetEntry(const KEY_TYPE aKey) { \
|
||||||
|
ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, \
|
||||||
|
PL_DHashTableOperate(&mHashTable, &aKey, \
|
||||||
|
PL_DHASH_LOOKUP)); \
|
||||||
|
return PL_DHASH_ENTRY_IS_LIVE(e) ? e : nsnull; \
|
||||||
|
} \
|
||||||
|
ENTRY_CLASS* CLASSNAME::AddEntry(const KEY_TYPE aKey) { \
|
||||||
|
return NS_STATIC_CAST(ENTRY_CLASS*, \
|
||||||
|
PL_DHashTableOperate(&mHashTable, &aKey, \
|
||||||
|
PL_DHASH_ADD)); \
|
||||||
|
} \
|
||||||
|
void CLASSNAME::Remove(const KEY_TYPE aKey) { \
|
||||||
|
PL_DHashTableOperate(&mHashTable, &aKey, PL_DHASH_REMOVE); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* STANDARD KEY ENTRY CLASSES
|
||||||
|
*
|
||||||
|
* We have declared some standard key classes for you to make life a little
|
||||||
|
* easier. These include string, int and void* keys. You can extend these
|
||||||
|
* and add value data members to make a working hash entry class with your
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* PLDHashStringEntry: nsAString
|
||||||
|
* PLDHashCStringEntry: nsACString
|
||||||
|
* PLDHashInt32Entry: PRInt32
|
||||||
|
* PLDHashVoidEntry: void*
|
||||||
|
*
|
||||||
|
* As a short example, if you want to make a class that maps int to string,
|
||||||
|
* you could do:
|
||||||
|
*
|
||||||
|
* class MyIntStringEntry : public PLDHashInt32Entry
|
||||||
|
* {
|
||||||
|
* public:
|
||||||
|
* MyIntStringEntry(const void* aKey) : PLDHashInt32Entry(aKey) { }
|
||||||
|
* ~MyIntStringEntry() { };
|
||||||
|
* nsString mMyStr;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// String-key entry
|
||||||
|
//
|
||||||
|
class NS_COM PLDHashStringEntry : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLDHashStringEntry(const void* aKey) :
|
||||||
|
mKey(*NS_STATIC_CAST(const nsAString*, aKey)) { }
|
||||||
|
~PLDHashStringEntry() { }
|
||||||
|
|
||||||
|
const void* GetKey() const {
|
||||||
|
return NS_STATIC_CAST(const nsAString*, &mKey);
|
||||||
|
}
|
||||||
|
static PLDHashNumber HashKey(const void* key) {
|
||||||
|
return HashString(*NS_STATIC_CAST(const nsAString*, key));
|
||||||
|
}
|
||||||
|
PRBool MatchEntry(const void* key) const {
|
||||||
|
return NS_STATIC_CAST(const nsAString*, key)->Equals(mKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsString mKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// CString-key entry
|
||||||
|
//
|
||||||
|
class NS_COM PLDHashCStringEntry : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLDHashCStringEntry(const void* aKey) :
|
||||||
|
mKey(*NS_STATIC_CAST(const nsACString*, aKey)) { }
|
||||||
|
~PLDHashCStringEntry() { }
|
||||||
|
|
||||||
|
const void* GetKey() const {
|
||||||
|
return NS_STATIC_CAST(const nsACString*, &mKey);
|
||||||
|
}
|
||||||
|
static PLDHashNumber HashKey(const void* key) {
|
||||||
|
return HashString(*NS_STATIC_CAST(const nsACString*, key));
|
||||||
|
}
|
||||||
|
PRBool MatchEntry(const void* key) const {
|
||||||
|
return NS_STATIC_CAST(const nsACString*, key)->Equals(mKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsCString mKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Int-key entry
|
||||||
|
//
|
||||||
|
class NS_COM PLDHashInt32Entry : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLDHashInt32Entry(const void* aKey) :
|
||||||
|
mKey(*(NS_STATIC_CAST(const PRInt32*, aKey))) { }
|
||||||
|
~PLDHashInt32Entry() { }
|
||||||
|
|
||||||
|
const void* GetKey() const {
|
||||||
|
return NS_STATIC_CAST(const PRInt32*, &mKey);
|
||||||
|
}
|
||||||
|
static PLDHashNumber HashKey(const void* key) {
|
||||||
|
return *NS_STATIC_CAST(const PRInt32*, key);
|
||||||
|
}
|
||||||
|
PRBool MatchEntry(const void* key) const {
|
||||||
|
return *(NS_STATIC_CAST(const PRInt32*, key)) == mKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRInt32 mKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Void-key entry
|
||||||
|
//
|
||||||
|
class NS_COM PLDHashVoidEntry : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLDHashVoidEntry(const void* aKey) :
|
||||||
|
mKey(*(const void**)aKey) { }
|
||||||
|
~PLDHashVoidEntry() { }
|
||||||
|
|
||||||
|
const void* GetKey() const {
|
||||||
|
return (const void**)&mKey;
|
||||||
|
}
|
||||||
|
static PLDHashNumber HashKey(const void* key) {
|
||||||
|
return PLDHashNumber(NS_PTR_TO_INT32(*(const void**)key)) >> 2;
|
||||||
|
}
|
||||||
|
PRBool MatchEntry(const void* key) const {
|
||||||
|
return *(const void**)key == mKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* mKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HASH SETS
|
||||||
|
*
|
||||||
|
* These hash classes describe hashtables that contain keys without values.
|
||||||
|
* This is useful when you want to store things and then just test for their
|
||||||
|
* existence later. We have defined standard ones for string, int and void.
|
||||||
|
*
|
||||||
|
* nsStringHashSet: nsAString&
|
||||||
|
* nsCStringHashSet: nsACString&
|
||||||
|
* nsInt32HashSet: PRInt32
|
||||||
|
* nsVoidHashSet: void*
|
||||||
|
*
|
||||||
|
* USAGE:
|
||||||
|
* Put():
|
||||||
|
* To use, you just do: (for example)
|
||||||
|
*
|
||||||
|
* #include "nsDoubleHashtable.h"
|
||||||
|
* nsInt32HashSet mySet;
|
||||||
|
* mySet.Init(1);
|
||||||
|
* mySet.Put(5);
|
||||||
|
* if (mySet.Contains(5)) {
|
||||||
|
* printf("yay\n");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* There is a nice convenient macro for declaring empty map classes:
|
||||||
|
* DECL_DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE)
|
||||||
|
* - CLASSNAME: the name of the class
|
||||||
|
* - ENTRY_CLASS: the name of the entry class with the key in it
|
||||||
|
* - KEY_TYPE: the type of key for Put() and Contains()
|
||||||
|
*
|
||||||
|
* DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) is the companion macro
|
||||||
|
* you must put in the .cpp (implementation) code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DECL_DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \
|
||||||
|
DECL_DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) \
|
||||||
|
class DHASH_EXPORT CLASSNAME : public CLASSNAME##Super { \
|
||||||
|
public: \
|
||||||
|
CLASSNAME() : CLASSNAME##Super() { } \
|
||||||
|
~CLASSNAME() { } \
|
||||||
|
nsresult Put(const KEY_TYPE aKey) { \
|
||||||
|
return AddEntry(aKey) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; \
|
||||||
|
} \
|
||||||
|
PRBool Contains(const KEY_TYPE aKey) { \
|
||||||
|
return GetEntry(aKey) ? PR_TRUE : PR_FALSE; \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \
|
||||||
|
DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE)
|
||||||
|
|
||||||
|
#define DHASH_EXPORT NS_COM
|
||||||
|
|
||||||
|
DECL_DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&)
|
||||||
|
DECL_DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&)
|
||||||
|
DECL_DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32)
|
||||||
|
DECL_DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*)
|
||||||
|
|
||||||
|
#undef DHASH_EXPORT
|
||||||
|
#define DHASH_EXPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче