зеркало из https://github.com/mozilla/pjs.git
Bug 722689 - remove nsHashSets from nsCheapSets; r=bsmedberg
This commit is contained in:
Родитель
6f155c6ec5
Коммит
a69419f13d
|
@ -202,8 +202,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
nsCheapStringSet mValues;
|
||||
nsCheapInt32Set mIndices;
|
||||
nsCheapSet<nsStringHashKey> mValues;
|
||||
nsCheapSet<nsUint32HashKey> mIndices;
|
||||
};
|
||||
|
||||
class NS_STACK_CLASS nsSafeOptionListMutation
|
||||
|
|
|
@ -54,7 +54,6 @@ CPPSRCS = \
|
|||
nsAtomTable.cpp \
|
||||
nsAtomService.cpp \
|
||||
nsByteBuffer.cpp \
|
||||
nsCheapSets.cpp \
|
||||
nsCRT.cpp \
|
||||
nsFixedSizeAllocator.cpp \
|
||||
nsHashPropertyBag.cpp \
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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 of 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 MPL, 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 MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsCheapSets.h"
|
||||
|
||||
nsCheapStringSet::~nsCheapStringSet()
|
||||
{
|
||||
nsStringHashSet* set = GetHash();
|
||||
if (set) {
|
||||
delete set;
|
||||
} else {
|
||||
delete GetStr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a string into the table
|
||||
*/
|
||||
nsresult
|
||||
nsCheapStringSet::Put(const nsAString& aVal)
|
||||
{
|
||||
// Add the value to the hash if it is there
|
||||
nsStringHashSet* set = GetHash();
|
||||
if (set) {
|
||||
return set->Put(aVal);
|
||||
}
|
||||
|
||||
// If a string is already there, create a hashtable and both of these to it
|
||||
if (GetStr()) {
|
||||
nsAString* oldStr = GetStr();
|
||||
nsresult rv = InitHash(&set);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = set->Put(*oldStr);
|
||||
delete oldStr;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return set->Put(aVal);
|
||||
}
|
||||
|
||||
// Nothing exists in the hash right now, so just set the single string
|
||||
return SetStr(aVal);
|
||||
}
|
||||
|
||||
void
|
||||
nsCheapStringSet::Remove(const nsAString& aVal)
|
||||
{
|
||||
// Remove from the hash if the hash is there
|
||||
nsStringHashSet* set = GetHash();
|
||||
if (set) {
|
||||
set->Remove(aVal);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the string if there is just a string
|
||||
nsAString* str = GetStr();
|
||||
if (str && str->Equals(aVal)) {
|
||||
delete str;
|
||||
mValOrHash = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCheapStringSet::InitHash(nsStringHashSet** aSet)
|
||||
{
|
||||
nsStringHashSet* newSet = new nsStringHashSet();
|
||||
if (!newSet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = newSet->Init(10);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mValOrHash = newSet;
|
||||
*aSet = newSet;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsCheapInt32Set::~nsCheapInt32Set()
|
||||
{
|
||||
delete GetHash();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCheapInt32Set::Put(PRInt32 aVal)
|
||||
{
|
||||
// Add the value to the hash or set the pointer as an int
|
||||
nsInt32HashSet* set = GetHash();
|
||||
if (set) {
|
||||
return set->Put(aVal);
|
||||
}
|
||||
|
||||
// Create the hash and add the value to it if there is an int already
|
||||
if (IsInt()) {
|
||||
PRInt32 oldInt = GetInt();
|
||||
|
||||
nsresult rv = InitHash(&set);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = set->Put(oldInt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return set->Put(aVal);
|
||||
}
|
||||
|
||||
// Create the hash anyway if the int is negative (negative numbers cannot
|
||||
// fit into our PtrBits abstraction)
|
||||
if (aVal < 0) {
|
||||
nsresult rv = InitHash(&set);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return set->Put(aVal);
|
||||
}
|
||||
|
||||
// Finally, just set the int if we can't do anything with hashes
|
||||
SetInt(aVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsCheapInt32Set::Remove(PRInt32 aVal)
|
||||
{
|
||||
nsInt32HashSet* set = GetHash();
|
||||
if (set) {
|
||||
set->Remove(aVal);
|
||||
} else if (IsInt() && GetInt() == aVal) {
|
||||
mValOrHash = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCheapInt32Set::InitHash(nsInt32HashSet** aSet)
|
||||
{
|
||||
nsInt32HashSet* newSet = new nsInt32HashSet();
|
||||
if (!newSet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = newSet->Init(10);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mValOrHash = newSet;
|
||||
*aSet = newSet;
|
||||
return NS_OK;
|
||||
}
|
|
@ -38,158 +38,135 @@
|
|||
#ifndef __nsCheapSets_h__
|
||||
#define __nsCheapSets_h__
|
||||
|
||||
#include "nsHashSets.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "mozilla/StdInt.h"
|
||||
|
||||
/**
|
||||
* A string set that takes up minimal size when there are 0 or 1 strings in the
|
||||
* set. Use for cases where sizes of 0 and 1 are even slightly common.
|
||||
* A set that takes up minimal size when there are 0 or 1 entries in the set.
|
||||
* Use for cases where sizes of 0 and 1 are even slightly common.
|
||||
*/
|
||||
class nsCheapStringSet {
|
||||
template<typename EntryType>
|
||||
class nsCheapSet
|
||||
{
|
||||
public:
|
||||
nsCheapStringSet() : mValOrHash(nsnull)
|
||||
typedef typename EntryType::KeyType KeyType;
|
||||
|
||||
nsCheapSet() : mState(ZERO)
|
||||
{
|
||||
}
|
||||
~nsCheapStringSet();
|
||||
|
||||
/**
|
||||
* Put a string into the set
|
||||
* @param aVal the value to put in
|
||||
*/
|
||||
nsresult Put(const nsAString& aVal);
|
||||
|
||||
/**
|
||||
* Remove a string from the set
|
||||
* @param aVal the string to remove
|
||||
*/
|
||||
void Remove(const nsAString& aVal);
|
||||
|
||||
/**
|
||||
* Check if the set contains a particular string
|
||||
* @param aVal the string to check for
|
||||
* @return whether the string is in the set
|
||||
*/
|
||||
bool Contains(const nsAString& aVal)
|
||||
~nsCheapSet()
|
||||
{
|
||||
nsStringHashSet* set = GetHash();
|
||||
// Check the value from the hash if the hash is there
|
||||
if (set) {
|
||||
return set->Contains(aVal);
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
break;
|
||||
case ONE:
|
||||
GetSingleEntry()->~EntryType();
|
||||
break;
|
||||
case MANY:
|
||||
delete mUnion.table;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the value is equal to the string if the string is there
|
||||
nsAString* str = GetStr();
|
||||
return str && str->Equals(aVal);
|
||||
nsresult Put(const KeyType aVal);
|
||||
|
||||
void Remove(const KeyType aVal);
|
||||
|
||||
bool Contains(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
return false;
|
||||
case ONE:
|
||||
return GetSingleEntry()->KeyEquals(EntryType::KeyToPointer(aVal));
|
||||
case MANY:
|
||||
return !!mUnion.table->GetEntry(aVal);
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef PRUword PtrBits;
|
||||
EntryType* GetSingleEntry()
|
||||
{
|
||||
return reinterpret_cast<EntryType*>(&mUnion.singleEntry[0]);
|
||||
}
|
||||
|
||||
/** Get the hash pointer (or null if we're not a hash) */
|
||||
nsStringHashSet* GetHash()
|
||||
{
|
||||
return (PtrBits(mValOrHash) & 0x1) ? nsnull : (nsStringHashSet*)mValOrHash;
|
||||
}
|
||||
/** Find out whether it is a string */
|
||||
nsAString* GetStr()
|
||||
{
|
||||
return (PtrBits(mValOrHash) & 0x1)
|
||||
? (nsAString*)(PtrBits(mValOrHash) & ~0x1)
|
||||
: nsnull;
|
||||
}
|
||||
/** Set the single string */
|
||||
nsresult SetStr(const nsAString& aVal)
|
||||
{
|
||||
nsString* str = new nsString(aVal);
|
||||
if (!str) {
|
||||
enum SetState {
|
||||
ZERO,
|
||||
ONE,
|
||||
MANY
|
||||
};
|
||||
|
||||
union {
|
||||
nsTHashtable<EntryType> *table;
|
||||
char singleEntry[sizeof(EntryType)];
|
||||
} mUnion;
|
||||
enum SetState mState;
|
||||
};
|
||||
|
||||
template<typename EntryType>
|
||||
nsresult
|
||||
nsCheapSet<EntryType>::Put(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
new (GetSingleEntry()) EntryType(EntryType::KeyToPointer(aVal));
|
||||
mState = ONE;
|
||||
return NS_OK;
|
||||
case ONE:
|
||||
{
|
||||
nsTHashtable<EntryType> *table = new nsTHashtable<EntryType>();
|
||||
if (!table) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!table->Init()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
EntryType *entry = GetSingleEntry();
|
||||
if (!table->PutEntry(entry->GetKey())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
entry->~EntryType();
|
||||
mUnion.table = table;
|
||||
mState = MANY;
|
||||
}
|
||||
// Fall through.
|
||||
case MANY:
|
||||
if (!mUnion.table->PutEntry(aVal)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mValOrHash = (nsAString*)(PtrBits(str) | 0x1);
|
||||
return NS_OK;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
return NS_OK;
|
||||
}
|
||||
/** Initialize the hash */
|
||||
nsresult InitHash(nsStringHashSet** aSet);
|
||||
}
|
||||
|
||||
private:
|
||||
/** A hash or string ptr, depending on the lower bit (0=hash, 1=string) */
|
||||
void* mValOrHash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An integer set that takes up only 4 bytes when there are 0 or 1 integers
|
||||
* in the set. Use for cases where sizes of 0 and 1 are even slightly common.
|
||||
*/
|
||||
class nsCheapInt32Set {
|
||||
public:
|
||||
nsCheapInt32Set() : mValOrHash(nsnull)
|
||||
{
|
||||
}
|
||||
~nsCheapInt32Set();
|
||||
|
||||
/**
|
||||
* Put an int into the set
|
||||
*/
|
||||
nsresult Put(PRInt32 aVal);
|
||||
|
||||
/**
|
||||
* Remove a int from the set
|
||||
* @param aVal the int to remove
|
||||
*/
|
||||
void Remove(PRInt32 aVal);
|
||||
|
||||
/**
|
||||
* Check if the set contains a particular int
|
||||
* @param aVal the int to check for
|
||||
* @return whether the int is in the set
|
||||
*/
|
||||
bool Contains(PRInt32 aVal)
|
||||
{
|
||||
nsInt32HashSet* set = GetHash();
|
||||
if (set) {
|
||||
return set->Contains(aVal);
|
||||
template<typename EntryType>
|
||||
void
|
||||
nsCheapSet<EntryType>::Remove(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
break;
|
||||
case ONE:
|
||||
if (Contains(aVal)) {
|
||||
GetSingleEntry()->~EntryType();
|
||||
mState = ZERO;
|
||||
}
|
||||
if (IsInt()) {
|
||||
return GetInt() == aVal;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case MANY:
|
||||
mUnion.table->RemoveEntry(aVal);
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
break;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef PRUword PtrBits;
|
||||
|
||||
/** Get the hash pointer (or null if we're not a hash) */
|
||||
nsInt32HashSet* GetHash()
|
||||
{
|
||||
return PtrBits(mValOrHash) & 0x1 ? nsnull : (nsInt32HashSet*)mValOrHash;
|
||||
}
|
||||
/** Find out whether it is an integer */
|
||||
bool IsInt()
|
||||
{
|
||||
return !!(PtrBits(mValOrHash) & 0x1);
|
||||
}
|
||||
/** Get the single integer */
|
||||
PRInt32 GetInt()
|
||||
{
|
||||
return PtrBits(mValOrHash) >> 1;
|
||||
}
|
||||
/** Set the single integer */
|
||||
void SetInt(PRInt32 aInt)
|
||||
{
|
||||
mValOrHash = (void*)(intptr_t)((aInt << 1) | 0x1);
|
||||
}
|
||||
/** Create the hash and initialize */
|
||||
nsresult InitHash(nsInt32HashSet** aSet);
|
||||
|
||||
private:
|
||||
/** A hash or int, depending on the lower bit (0=hash, 1=int) */
|
||||
void* mValOrHash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* XXX We may want an nsCheapVoidSet and nsCheapCStringSet at some point
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче