mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 07:05:24 +00:00
282 lines
6.3 KiB
C++
282 lines
6.3 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "prmem.h"
|
|
#include "prlog.h"
|
|
#include "nsHashtable.h"
|
|
|
|
//
|
|
// Key operations
|
|
//
|
|
|
|
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
|
|
{
|
|
return ((const nsHashKey *) key)->HashValue();
|
|
}
|
|
|
|
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
|
|
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
|
|
}
|
|
|
|
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
|
|
const void *value2) {
|
|
// We're not going to make any assumptions about value equality
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Memory callbacks
|
|
//
|
|
|
|
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
|
|
return PR_MALLOC(size);
|
|
}
|
|
|
|
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
|
|
PR_DELETE(item);
|
|
}
|
|
|
|
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
|
|
return PR_NEW(PLHashEntry);
|
|
}
|
|
|
|
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
|
|
PRUintn flag) {
|
|
if (flag == HT_FREE_ENTRY) {
|
|
delete (nsHashKey *) (entry->key);
|
|
PR_DELETE(entry);
|
|
}
|
|
}
|
|
|
|
static PLHashAllocOps _hashAllocOps = {
|
|
_hashAllocTable, _hashFreeTable,
|
|
_hashAllocEntry, _hashFreeEntry
|
|
};
|
|
|
|
//
|
|
// Enumerator callback
|
|
//
|
|
|
|
struct _HashEnumerateArgs {
|
|
nsHashtableEnumFunc fn;
|
|
void* arg;
|
|
};
|
|
|
|
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
|
|
{
|
|
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
|
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
|
? HT_ENUMERATE_NEXT
|
|
: HT_ENUMERATE_STOP;
|
|
}
|
|
|
|
//
|
|
// HashKey
|
|
//
|
|
nsHashKey::nsHashKey(void)
|
|
{
|
|
}
|
|
|
|
nsHashKey::~nsHashKey(void)
|
|
{
|
|
}
|
|
|
|
nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
|
|
: mLock(NULL)
|
|
{
|
|
hashtable = PL_NewHashTable(aInitSize,
|
|
_hashValue,
|
|
_hashKeyCompare,
|
|
_hashValueCompare,
|
|
&_hashAllocOps,
|
|
NULL);
|
|
if (threadSafe == PR_TRUE)
|
|
{
|
|
mLock = PR_NewLock();
|
|
if (mLock == NULL)
|
|
{
|
|
// Cannot create a lock. If running on a multiprocessing system
|
|
// we are sure to die.
|
|
PR_ASSERT(mLock != NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsHashtable::~nsHashtable() {
|
|
PL_HashTableDestroy(hashtable);
|
|
if (mLock) PR_DestroyLock(mLock);
|
|
}
|
|
|
|
PRBool nsHashtable::Exists(nsHashKey *aKey)
|
|
{
|
|
PLHashNumber hash = aKey->HashValue();
|
|
|
|
if (mLock) PR_Lock(mLock);
|
|
|
|
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
|
|
|
if (mLock) PR_Unlock(mLock);
|
|
|
|
return *hep != NULL;
|
|
}
|
|
|
|
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
|
|
void *res = NULL;
|
|
PLHashNumber hash = aKey->HashValue();
|
|
PLHashEntry *he;
|
|
|
|
if (mLock) PR_Lock(mLock);
|
|
|
|
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
|
|
|
if ((he = *hep) != NULL) {
|
|
res = he->value;
|
|
he->value = aData;
|
|
} else {
|
|
PL_HashTableRawAdd(hashtable, hep, hash,
|
|
(void *) aKey->Clone(), aData);
|
|
}
|
|
|
|
if (mLock) PR_Unlock(mLock);
|
|
|
|
return res;
|
|
}
|
|
|
|
void *nsHashtable::Get(nsHashKey *aKey) {
|
|
|
|
if (mLock) PR_Lock(mLock);
|
|
|
|
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
|
|
|
|
if (mLock) PR_Unlock(mLock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void *nsHashtable::Remove(nsHashKey *aKey) {
|
|
PLHashNumber hash = aKey->HashValue();
|
|
PLHashEntry *he;
|
|
|
|
if (mLock) PR_Lock(mLock);
|
|
|
|
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
|
void *res = NULL;
|
|
|
|
if ((he = *hep) != NULL) {
|
|
res = he->value;
|
|
PL_HashTableRawRemove(hashtable, hep, he);
|
|
}
|
|
|
|
if (mLock) PR_Unlock(mLock);
|
|
|
|
return res;
|
|
}
|
|
|
|
static PR_CALLBACK PRIntn _hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
|
|
{
|
|
nsHashtable *newHashtable = (nsHashtable *)arg;
|
|
newHashtable->Put((nsHashKey *) he->key, he->value);
|
|
return HT_ENUMERATE_NEXT;
|
|
}
|
|
|
|
nsHashtable * nsHashtable::Clone() {
|
|
PRBool threadSafe = PR_FALSE;
|
|
if (mLock)
|
|
threadSafe = PR_TRUE;
|
|
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
|
|
|
|
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
|
|
return newHashTable;
|
|
}
|
|
|
|
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
|
|
_HashEnumerateArgs thunk;
|
|
thunk.fn = aEnumFunc;
|
|
thunk.arg = closure;
|
|
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
|
|
}
|
|
|
|
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
|
|
{
|
|
return HT_ENUMERATE_REMOVE;
|
|
}
|
|
|
|
void nsHashtable::Reset() {
|
|
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsStringKey::nsStringKey(const char* str)
|
|
{
|
|
mStr.Assign(str);
|
|
}
|
|
|
|
nsStringKey::nsStringKey(const PRUnichar* str)
|
|
{
|
|
mStr.Assign(str);
|
|
}
|
|
|
|
nsStringKey::nsStringKey(const nsStr& str)
|
|
{
|
|
mStr.Assign(str);
|
|
}
|
|
|
|
nsStringKey::~nsStringKey(void)
|
|
{
|
|
}
|
|
|
|
PRUint32 nsStringKey::HashValue(void) const
|
|
{
|
|
if(mStr.IsUnicode())
|
|
{
|
|
PRUint32 h;
|
|
PRUint32 n;
|
|
PRUint32 m;
|
|
const PRUnichar* c;
|
|
|
|
h = 0;
|
|
n = mStr.Length();
|
|
c = mStr.GetUnicode();
|
|
if(n < 16)
|
|
{ /* Hash every char in a short string. */
|
|
for(; n; c++, n--)
|
|
h = (h >> 28) ^ (h << 4) ^ *c;
|
|
}
|
|
else
|
|
{ /* Sample a la jave.lang.String.hash(). */
|
|
for(m = n / 8; n >= m; c += m, n -= m)
|
|
h = (h >> 28) ^ (h << 4) ^ *c;
|
|
}
|
|
return h;
|
|
}
|
|
return (PRUint32)PL_HashString((const void*) mStr.GetBuffer());
|
|
}
|
|
|
|
PRBool nsStringKey::Equals(const nsHashKey* aKey) const
|
|
{
|
|
return ((nsStringKey*)aKey)->mStr == mStr;
|
|
}
|
|
|
|
nsHashKey* nsStringKey::Clone() const
|
|
{
|
|
return new nsStringKey(mStr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|