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
This commit is contained in:
Mark Olesen
2009-02-26 17:49:47 +01:00
parent 2aeee852e8
commit a46c85f5a4
16 changed files with 177 additions and 124 deletions

View File

@ -57,7 +57,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class multiphaseMixture Declaration Class multiphaseMixture Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class multiphaseMixture class multiphaseMixture
@ -85,15 +85,6 @@ public:
{ {
return word::hash()(key.first()) + word::hash()(key.second()); return word::hash()(key.first()) + word::hash()(key.second());
} }
label operator()
(
const interfacePair& key,
const label tableSize
) const
{
return mag(operator()(key)) % tableSize;
}
}; };

View File

@ -30,20 +30,49 @@ License
#include "HashTable.H" #include "HashTable.H"
#include "List.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 * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(const label size) Foam::HashTable<T, Key, Hash>::HashTable(const label size)
: :
tableSize_(size), HashTableName(),
table_(NULL),
nElmts_(0), nElmts_(0),
tableSize_(canonicalSize(size)),
table_(NULL),
endIter_(*this, NULL, 0), endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0) endConstIter_(*this, NULL, 0)
{ {
if (tableSize_) if (tableSize_)
{ {
table_ = new hashedEntry*[tableSize_]; table_ = new hashedEntry*[tableSize_];
for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++) for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
{ {
table_[hashIdx] = 0; 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) Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
: :
HashTableName(), HashTableName(),
nElmts_(0),
tableSize_(ht.tableSize_), tableSize_(ht.tableSize_),
table_(NULL), table_(NULL),
nElmts_(0),
endIter_(*this, NULL, 0), endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0) endConstIter_(*this, NULL, 0)
{ {
@ -85,9 +114,9 @@ Foam::HashTable<T, Key, Hash>::HashTable
) )
: :
HashTableName(), HashTableName(),
nElmts_(0),
tableSize_(0), tableSize_(0),
table_(NULL), table_(NULL),
nElmts_(0),
endIter_(*this, NULL, 0), endIter_(*this, NULL, 0),
endConstIter_(*this, NULL, 0) endConstIter_(*this, NULL, 0)
{ {
@ -115,7 +144,7 @@ bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
{ {
if (nElmts_) if (nElmts_)
{ {
const label hashIdx = Hash()(key, tableSize_); const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{ {
@ -147,7 +176,7 @@ Foam::HashTable<T, Key, Hash>::find
{ {
if (nElmts_) if (nElmts_)
{ {
const label hashIdx = Hash()(key, tableSize_); const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{ {
@ -179,7 +208,7 @@ Foam::HashTable<T, Key, Hash>::find
{ {
if (nElmts_) if (nElmts_)
{ {
label hashIdx = Hash()(key, tableSize_); const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{ {
@ -231,7 +260,8 @@ bool Foam::HashTable<T, Key, Hash>::set
resize(2); resize(2);
} }
label hashIdx = Hash()(key, tableSize_); const label hashIdx = hashKeyIndex(key);
hashedEntry* existing = 0; hashedEntry* existing = 0;
hashedEntry* prev = 0; hashedEntry* prev = 0;
@ -449,14 +479,16 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
template<class T, class Key, class Hash> 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_) if (newSize == tableSize_)
{ {
# ifdef FULLDEBUG # ifdef FULLDEBUG
if (debug) 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"; << "new table size == old table size\n";
} }
# endif # endif

View File

@ -108,18 +108,25 @@ class HashTable
// Private data: size of table, the table and current number of elements // 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) //- Number of primary entries allocated in table (not necessarily used)
label tableSize_; label tableSize_;
//- The table of primary entries //- The table of primary entries
hashedEntry** table_; hashedEntry** table_;
//- The current number of elements in table
label nElmts_;
// Private Member Functions // 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 //- Assign a new hashedEntry to a possibly already existing key
bool set(const Key&, const T& newElmt, bool protect); bool set(const Key&, const T& newElmt, bool protect);

View File

@ -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 * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>

View File

@ -33,15 +33,16 @@ License
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size) Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
: :
tableSize_(size), HashTableName(),
table_(new hashedEntry*[tableSize_]),
nElmts_(0), nElmts_(0),
tableSize_(canonicalSize(size)),
table_(new hashedEntry*[tableSize_]),
endIter_(*this, NULL, 0), endIter_(*this, NULL, 0),
endConstIter_(*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); operator>>(is, *this);

View File

@ -31,6 +31,33 @@ License
#include "List.H" #include "List.H"
#include "IOstreams.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 * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct given initial table size // 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) Foam::StaticHashTable<T, Key, Hash>::StaticHashTable(const label size)
: :
StaticHashTableName(), StaticHashTableName(),
keys_(size), keys_(canonicalSize(size)),
objects_(size), objects_(keys_.size()),
nElmts_(0), nElmts_(0),
endIter_(*this, keys_.size(), 0), endIter_(*this, keys_.size(), 0),
endConstIter_(*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> template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
( (
const Xfer<StaticHashTable<T, Key, Hash> >& ht const Xfer< StaticHashTable<T, Key, Hash> >& ht
) )
: :
StaticHashTableName(), StaticHashTableName(),
@ -103,7 +130,7 @@ bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const
{ {
if (nElmts_) if (nElmts_)
{ {
label hashIdx = Hash()(key, keys_.size()); const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx]; const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx) forAll(localKeys, elemIdx)
@ -136,7 +163,7 @@ Foam::StaticHashTable<T, Key, Hash>::find
{ {
if (nElmts_) if (nElmts_)
{ {
label hashIdx = Hash()(key, keys_.size()); const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx]; const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx) forAll(localKeys, elemIdx)
@ -167,14 +194,17 @@ Foam::StaticHashTable<T, Key, Hash>::find
const Key& key const Key& key
) const ) const
{ {
label hashIdx = Hash()(key, keys_.size()); if (nElmts_)
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
{ {
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 # endif
return end(); return cend();
} }
@ -197,7 +227,7 @@ Foam::List<Key> Foam::StaticHashTable<T, Key, Hash>::toc() const
List<Key> tofc(nElmts_); List<Key> tofc(nElmts_);
label i = 0; label i = 0;
for (const_iterator iter = begin(); iter != end(); ++iter) for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{ {
tofc[i++] = iter.key(); tofc[i++] = iter.key();
} }
@ -214,7 +244,7 @@ bool Foam::StaticHashTable<T, Key, Hash>::set
const bool protect const bool protect
) )
{ {
label hashIdx = Hash()(key, keys_.size()); const label hashIdx = hashKeyIndex(key);
List<Key>& localKeys = keys_[hashIdx]; List<Key>& localKeys = keys_[hashIdx];
label existing = localKeys.size(); label existing = localKeys.size();
@ -375,8 +405,10 @@ Foam::label Foam::StaticHashTable<T, Key, Hash>::erase
template<class T, class Key, class Hash> 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()) if (newSize == keys_.size())
{ {
# ifdef FULLDEBUG # ifdef FULLDEBUG
@ -394,7 +426,7 @@ void Foam::StaticHashTable<T, Key, Hash>::resize(const label newSize)
{ {
FatalErrorIn FatalErrorIn
( (
"StaticHashTable<T, Key, Hash>::StaticHashTable(const label size)" "StaticHashTable<T, Key, Hash>::resize(const label)"
) << "Illegal size " << newSize << " for StaticHashTable." ) << "Illegal size " << newSize << " for StaticHashTable."
<< " Minimum size is 1" << abort(FatalError); << " 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); 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); 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); insert(iter.key(), *iter);
} }
@ -512,22 +544,22 @@ bool Foam::StaticHashTable<T, Key, Hash>::operator==
) const ) const
{ {
// Are all my elements in rhs? // 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()); const_iterator fnd = rhs.find(iter.key());
if (fnd == rhs.end() || fnd() != iter()) if (fnd == rhs.cend() || fnd() != iter())
{ {
return false; return false;
} }
} }
// Are all rhs elements in me? // 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()); const_iterator fnd = find(iter.key());
if (fnd == end() || fnd() != iter()) if (fnd == cend() || fnd() != iter())
{ {
return false; return false;
} }

View File

@ -99,6 +99,13 @@ class StaticHashTable
//- The current number of elements in table //- The current number of elements in table
label nElmts_; 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 //- Assign a new hashed entry to a possibly already existing key
bool set(const Key&, const T& newElmt, bool protect); bool set(const Key&, const T& newElmt, bool protect);
@ -150,7 +157,7 @@ public:
StaticHashTable(const StaticHashTable<T, Key, Hash>&); StaticHashTable(const StaticHashTable<T, Key, Hash>&);
//- Construct by transferring the parameter contents //- Construct by transferring the parameter contents
StaticHashTable(const Xfer<StaticHashTable<T, Key, Hash> >&); StaticHashTable(const Xfer< StaticHashTable<T, Key, Hash> >&);
// Destructor // Destructor
@ -218,7 +225,7 @@ public:
void transfer(StaticHashTable<T, Key, Hash>&); void transfer(StaticHashTable<T, Key, Hash>&);
//- Transfer contents to the Xfer container //- Transfer contents to the Xfer container
inline Xfer<StaticHashTable<T, Key, Hash> > xfer(); inline Xfer< StaticHashTable<T, Key, Hash> > xfer();
// Member Operators // Member Operators

View File

@ -29,6 +29,17 @@ License
// * * * * * * * * * * * * * Private Member Classes * * * * * * * * * * * * // // * * * * * * * * * * * * * 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 * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash> 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> 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() Foam::StaticHashTable<T, Key, Hash>::xfer()
{ {
return xferMove(*this); return xferMove(*this);

View File

@ -80,17 +80,12 @@ public:
// Rotating hash from http://burtleburtle.net/bob/hash/doobs.html // Rotating hash from http://burtleburtle.net/bob/hash/doobs.html
template<class HashT=Hash<T> > template<class HashT=Hash<T> >
class Hash class Hash
:
public Foam::Hash<FixedList<T, Size> >
{ {
public: public:
inline Hash(); Hash()
{}
label operator()(const FixedList<T, Size>&) const; label operator()(const FixedList<T, Size>&) const;
label operator()
(
const FixedList<T, Size>&,
const label tableSize
) const;
}; };
// Static Member Functions // Static Member Functions

View File

@ -403,11 +403,6 @@ inline bool Foam::FixedList<T, Size>::empty() const
#ifndef __CINT__ #ifndef __CINT__
template<class T, Foam::label Size>
template<class HashT>
inline Foam::FixedList<T, Size>::Hash<HashT>::Hash()
{}
// Rotating Hash // Rotating Hash
template<class T, Foam::label Size> template<class T, Foam::label Size>
@ -429,17 +424,6 @@ inline Foam::label Foam::FixedList<T, Size>::Hash<HashT>::operator()
return val; return val;
} }
template<class T, Foam::label Size> #endif // __CINT__
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
// ************************************************************************* // // ************************************************************************* //

View File

@ -38,7 +38,7 @@ SourceFiles
#include "HashTable.H" #include "HashTable.H"
#include "label.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 class dlLibraryTable
: :
public HashTable<fileName, void*, Hash<void*> > public HashTable<fileName, void*, Hash<void*> >

View File

@ -133,12 +133,12 @@ public:
}; };
//- Hash<edge> specialisation //- Hash specialization for hashing edges
// Simple commutative hash. // Simple commutative hash.
template<> template<>
inline label Hash<edge>::operator()(const edge& e) const 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<> template<>

View File

@ -164,7 +164,7 @@ public:
}; };
//- Hash<triFace> specialisation //- Hash specialization for hashing triFace
// Simple commutative hash. // Simple commutative hash.
template<> template<>
inline label Hash<triFace>::operator()(const triFace& t) const inline label Hash<triFace>::operator()(const triFace& t) const

View File

@ -27,7 +27,7 @@ Class
Description Description
Hash function class for primitives. All non-primitives used to hash 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 #define Hash_H
#include "label.H" #include "label.H"
#include "pTraits.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -42,7 +43,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class Hash Declaration Class Hash Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
template<class PrimitiveType> template<class PrimitiveType>
@ -59,10 +60,26 @@ public:
return label(p); return label(p);
} }
label operator()(const PrimitiveType& p, const label tableSize) const };
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Hash specialization for hashing pointer addresses
template<>
class Hash<void*>
{
public:
Hash()
{}
long operator()(const void* const& p) const
{ {
return mag(operator()(p)) % tableSize; return long(p);
} }
}; };

View File

@ -89,9 +89,10 @@ public:
class hash class hash
{ {
public: public:
inline hash(); hash()
{}
inline size_type operator()(const string&) const; inline size_type operator()(const string&) const;
inline size_type operator()(const string&, const size_type) const;
}; };

View File

@ -196,10 +196,6 @@ inline Foam::string Foam::string::operator()(const size_type n) const
} }
inline Foam::string::hash::hash()
{}
inline Foam::string::size_type Foam::string::hash::operator() inline Foam::string::size_type Foam::string::hash::operator()
( (
const string& key const string& key
@ -216,14 +212,4 @@ inline Foam::string::size_type Foam::string::hash::operator()
} }
inline Foam::string::size_type Foam::string::hash::operator()
(
const string& key,
const size_type tableSize
) const
{
return ::abs(operator()(key)) % tableSize;
}
// ************************************************************************* // // ************************************************************************* //