Commit a46c85f5 authored by Mark Olesen's avatar Mark Olesen
Browse files

HashTable changes

- make table power-of-two, but since it seems to give 1-2% performance
  improvement, maybe forget it too.

- remove two-argument form of hashing classes and do the modulus direclty
  within HashTable instead. This simplifies things a fair bit.

- migrate Hash<void*> from db/dlLibrary to primitives/hashes/Hash
parent 2aeee852
......@@ -57,7 +57,7 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class multiphaseMixture Declaration
Class multiphaseMixture Declaration
\*---------------------------------------------------------------------------*/
class multiphaseMixture
......@@ -85,15 +85,6 @@ public:
{
return word::hash()(key.first()) + word::hash()(key.second());
}
label operator()
(
const interfacePair& key,
const label tableSize
) const
{
return mag(operator()(key)) % tableSize;
}
};
......
......@@ -30,20 +30,49 @@ License
#include "HashTable.H"
#include "List.H"
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::label Foam::HashTable<T, Key, Hash>::canonicalSize(const label size)
{
if (size < 1)
{
return 0;
}
// enforce power of two
unsigned int goodSize = size;
if (goodSize & (goodSize - 1))
{
// brute-force is fast enough
goodSize = 1;
while (goodSize < unsigned(size))
{
goodSize <<= 1;
}
}
return goodSize;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(const label size)
:
tableSize_(size),
table_(NULL),
HashTableName(),
nElmts_(0),
tableSize_(canonicalSize(size)),
table_(NULL),
endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0)
{
if (tableSize_)
{
table_ = new hashedEntry*[tableSize_];
for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
{
table_[hashIdx] = 0;
......@@ -56,9 +85,9 @@ template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
:
HashTableName(),
nElmts_(0),
tableSize_(ht.tableSize_),
table_(NULL),
nElmts_(0),
endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0)
{
......@@ -85,9 +114,9 @@ Foam::HashTable<T, Key, Hash>::HashTable
)
:
HashTableName(),
nElmts_(0),
tableSize_(0),
table_(NULL),
nElmts_(0),
endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0)
{
......@@ -115,7 +144,7 @@ bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
{
if (nElmts_)
{
const label hashIdx = Hash()(key, tableSize_);
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
......@@ -147,7 +176,7 @@ Foam::HashTable<T, Key, Hash>::find
{
if (nElmts_)
{
const label hashIdx = Hash()(key, tableSize_);
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
......@@ -179,7 +208,7 @@ Foam::HashTable<T, Key, Hash>::find
{
if (nElmts_)
{
label hashIdx = Hash()(key, tableSize_);
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
......@@ -231,7 +260,8 @@ bool Foam::HashTable<T, Key, Hash>::set
resize(2);
}
label hashIdx = Hash()(key, tableSize_);
const label hashIdx = hashKeyIndex(key);
hashedEntry* existing = 0;
hashedEntry* prev = 0;
......@@ -449,14 +479,16 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::resize(const label newSize)
void Foam::HashTable<T, Key, Hash>::resize(const label sz)
{
label newSize = canonicalSize(sz);
if (newSize == tableSize_)
{
# ifdef FULLDEBUG
if (debug)
{
Info<< "HashTable<T, Key, Hash>::resize(const label newSize) : "
Info<< "HashTable<T, Key, Hash>::resize(const label) : "
<< "new table size == old table size\n";
}
# endif
......
......@@ -108,18 +108,25 @@ class HashTable
// Private data: size of table, the table and current number of elements
//- The current number of elements in table
label nElmts_;
//- Number of primary entries allocated in table (not necessarily used)
label tableSize_;
//- The table of primary entries
hashedEntry** table_;
//- The current number of elements in table
label nElmts_;
// Private Member Functions
//- Return a canonical (power-of-two) size
static label canonicalSize(const label);
//- Return the hash index of the Key within the current table size.
// No checks for zero-sized tables.
inline label hashKeyIndex(const Key&) const;
//- Assign a new hashedEntry to a possibly already existing key
bool set(const Key&, const T& newElmt, bool protect);
......
......@@ -42,6 +42,17 @@ inline Foam::HashTable<T, Key, Hash>::hashedEntry::hashedEntry
{}
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::label
Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
{
// size is power of two - this is the modulus
return Hash()(key) & (tableSize_ - 1);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
......
......@@ -33,15 +33,16 @@ License
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
:
tableSize_(size),
table_(new hashedEntry*[tableSize_]),
HashTableName(),
nElmts_(0),
tableSize_(canonicalSize(size)),
table_(new hashedEntry*[tableSize_]),
endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0)
{
for (label i=0; i < tableSize_; i++)
for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
{
table_[i] = 0;
table_[hashIdx] = 0;
}
operator>>(is, *this);
......
......@@ -31,6 +31,33 @@ License
#include "List.H"
#include "IOstreams.H"
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::label Foam::StaticHashTable<T, Key, Hash>::canonicalSize(const label size)
{
if (size < 1)
{
return 0;
}
// enforce power of two
unsigned int goodSize = size;
if (goodSize & (goodSize - 1))
{
// brute-force is fast enough
goodSize = 1;
while (goodSize < unsigned(size))
{
goodSize <<= 1;
}
}
return goodSize;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct given initial table size
......@@ -38,8 +65,8 @@ template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable(const label size)
:
StaticHashTableName(),
keys_(size),
objects_(size),
keys_(canonicalSize(size)),
objects_(keys_.size()),
nElmts_(0),
endIter_(*this, keys_.size(), 0),
endConstIter_(*this, keys_.size(), 0)
......@@ -75,7 +102,7 @@ Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
(
const Xfer<StaticHashTable<T, Key, Hash> >& ht
const Xfer< StaticHashTable<T, Key, Hash> >& ht
)
:
StaticHashTableName(),
......@@ -103,7 +130,7 @@ bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const
{
if (nElmts_)
{
label hashIdx = Hash()(key, keys_.size());
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
......@@ -136,7 +163,7 @@ Foam::StaticHashTable<T, Key, Hash>::find
{
if (nElmts_)
{
label hashIdx = Hash()(key, keys_.size());
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
......@@ -167,14 +194,17 @@ Foam::StaticHashTable<T, Key, Hash>::find
const Key& key
) const
{
label hashIdx = Hash()(key, keys_.size());
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
if (nElmts_)
{
if (key == localKeys[elemIdx])
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
{
return const_iterator(*this, hashIdx, elemIdx);
if (key == localKeys[elemIdx])
{
return const_iterator(*this, hashIdx, elemIdx);
}
}
}
......@@ -186,7 +216,7 @@ Foam::StaticHashTable<T, Key, Hash>::find
}
# endif
return end();
return cend();
}
......@@ -197,7 +227,7 @@ Foam::List<Key> Foam::StaticHashTable<T, Key, Hash>::toc() const
List<Key> tofc(nElmts_);
label i = 0;
for (const_iterator iter = begin(); iter != end(); ++iter)
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{
tofc[i++] = iter.key();
}
......@@ -214,7 +244,7 @@ bool Foam::StaticHashTable<T, Key, Hash>::set
const bool protect
)
{
label hashIdx = Hash()(key, keys_.size());
const label hashIdx = hashKeyIndex(key);
List<Key>& localKeys = keys_[hashIdx];
label existing = localKeys.size();
......@@ -375,8 +405,10 @@ Foam::label Foam::StaticHashTable<T, Key, Hash>::erase
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::resize(const label newSize)
void Foam::StaticHashTable<T, Key, Hash>::resize(const label sz)
{
label newSize = canonicalSize(sz);
if (newSize == keys_.size())
{
# ifdef FULLDEBUG
......@@ -394,7 +426,7 @@ void Foam::StaticHashTable<T, Key, Hash>::resize(const label newSize)
{
FatalErrorIn
(
"StaticHashTable<T, Key, Hash>::StaticHashTable(const label size)"
"StaticHashTable<T, Key, Hash>::resize(const label)"
) << "Illegal size " << newSize << " for StaticHashTable."
<< " Minimum size is 1" << abort(FatalError);
}
......@@ -402,7 +434,7 @@ void Foam::StaticHashTable<T, Key, Hash>::resize(const label newSize)
StaticHashTable<T, Key, Hash> newTable(newSize);
for (iterator iter = begin(); iter != end(); ++iter)
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{
newTable.insert(iter.key(), *iter);
}
......@@ -499,7 +531,7 @@ void Foam::StaticHashTable<T, Key, Hash>::operator=
}
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter)
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{
insert(iter.key(), *iter);
}
......@@ -512,22 +544,22 @@ bool Foam::StaticHashTable<T, Key, Hash>::operator==
) const
{
// Are all my elements in rhs?
for (const_iterator iter = begin(); iter != end(); ++iter)
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{
const_iterator fnd = rhs.find(iter.key());
if (fnd == rhs.end() || fnd() != iter())
if (fnd == rhs.cend() || fnd() != iter())
{
return false;
}
}
// Are all rhs elements in me?
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter)
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{
const_iterator fnd = find(iter.key());
if (fnd == end() || fnd() != iter())
if (fnd == cend() || fnd() != iter())
{
return false;
}
......
......@@ -99,6 +99,13 @@ class StaticHashTable
//- The current number of elements in table
label nElmts_;
//- Return a canonical (power-of-two) size
static label canonicalSize(const label);
//- Return the hash index of the Key within the current table size.
// No checks for zero-sized tables.
inline label hashKeyIndex(const Key&) const;
//- Assign a new hashed entry to a possibly already existing key
bool set(const Key&, const T& newElmt, bool protect);
......@@ -150,7 +157,7 @@ public:
StaticHashTable(const StaticHashTable<T, Key, Hash>&);
//- Construct by transferring the parameter contents
StaticHashTable(const Xfer<StaticHashTable<T, Key, Hash> >&);
StaticHashTable(const Xfer< StaticHashTable<T, Key, Hash> >&);
// Destructor
......@@ -218,7 +225,7 @@ public:
void transfer(StaticHashTable<T, Key, Hash>&);
//- Transfer contents to the Xfer container
inline Xfer<StaticHashTable<T, Key, Hash> > xfer();
inline Xfer< StaticHashTable<T, Key, Hash> > xfer();
// Member Operators
......
......@@ -29,6 +29,17 @@ License
// * * * * * * * * * * * * * Private Member Classes * * * * * * * * * * * * //
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::label
Foam::StaticHashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
{
// size is power of two - this is the modulus
return Hash()(key) & (keys_.size() - 1);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
......@@ -68,7 +79,7 @@ inline bool Foam::StaticHashTable<T, Key, Hash>::set
template<class T, class Key, class Hash>
inline Foam::Xfer<Foam::StaticHashTable<T, Key, Hash> >
inline Foam::Xfer< Foam::StaticHashTable<T, Key, Hash> >
Foam::StaticHashTable<T, Key, Hash>::xfer()
{
return xferMove(*this);
......
......@@ -80,17 +80,12 @@ public:
// Rotating hash from http://burtleburtle.net/bob/hash/doobs.html
template<class HashT=Hash<T> >
class Hash
:
public Foam::Hash<FixedList<T, Size> >
{
public:
inline Hash();
Hash()
{}
label operator()(const FixedList<T, Size>&) const;
label operator()
(
const FixedList<T, Size>&,
const label tableSize
) const;
};
// Static Member Functions
......
......@@ -403,11 +403,6 @@ inline bool Foam::FixedList<T, Size>::empty() const
#ifndef __CINT__
template<class T, Foam::label Size>
template<class HashT>
inline Foam::FixedList<T, Size>::Hash<HashT>::Hash()
{}
// Rotating Hash
template<class T, Foam::label Size>
......@@ -429,17 +424,6 @@ inline Foam::label Foam::FixedList<T, Size>::Hash<HashT>::operator()
return val;
}
template<class T, Foam::label Size>
template<class HashT>
inline Foam::label Foam::FixedList<T, Size>::Hash<HashT>::operator()
(
const FixedList<T, Size>& lst,
const label tableSize
) const
{
return ::abs(operator()(lst)) % tableSize;
}
#endif
#endif // __CINT__
// ************************************************************************* //
......@@ -38,7 +38,7 @@ SourceFiles
#include "HashTable.H"
#include "label.H"
#include "pTraits.H"
#include "Hash.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -46,31 +46,9 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class dlLibraryTable Declaration
Class dlLibraryTable Declaration
\*---------------------------------------------------------------------------*/
//- A means of hashing pointer addresses
template<>
class Hash<void*>
{
public:
Hash()
{}
long operator()(const void* const& p) const
{
return long(p);
}
label operator()(const void* const& p, const label tableSize) const
{
return abs(operator()(p)) % tableSize;
}
};
class dlLibraryTable
:
public HashTable<fileName, void*, Hash<void*> >
......
......@@ -133,12 +133,12 @@ public:
};
//- Hash<edge> specialisation
//- Hash specialization for hashing edges
// Simple commutative hash.
template<>
inline label Hash<edge>::operator()(const edge& e) const
{
return e[0]*e[1] + e[0]+e[1];
return (e[0]*e[1] + e[0]+e[1]);
}
template<>
......
......@@ -164,7 +164,7 @@ public:
};
//- Hash<triFace> specialisation
//- Hash specialization for hashing triFace
// Simple commutative hash.
template<>
inline label Hash<triFace>::operator()(const triFace& t) const
......
......@@ -27,7 +27,7 @@ Class
Description
Hash function class for primitives. All non-primitives used to hash
entries on hash tables need a specialised version of this class.
entries on hash tables need a specialized version of this class.
\*---------------------------------------------------------------------------*/
......@@ -35,6 +35,7 @@ Description
#define Hash_H
#include "label.H"