Merge branch 'feature-hash-table' into 'develop'

Improvements to HashTable internals

See merge request Development/OpenFOAM-plus!158
This commit is contained in:
Andrew Heather
2017-11-03 17:40:33 +00:00
47 changed files with 1686 additions and 3048 deletions

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,6 +26,7 @@ Description
\*---------------------------------------------------------------------------*/
#include "hashedWordList.H"
#include "nil.H"
#include "HashSet.H"
#include "Map.H"
#include "labelPairHashes.H"
@ -69,6 +70,8 @@ int main(int argc, char *argv[])
Info<< "tableA keys: "; tableA.writeKeys(Info) << endl;
Info<< "tableB content: " << tableB << endl;
auto keyIterPair = tableA.keys();
for (const auto& i : keyIterPair)
{

View File

@ -1,3 +0,0 @@
Test-hashTable.C
EXE = $(FOAM_USER_APPBIN)/Test-hashTable

View File

@ -0,0 +1,3 @@
Test-HashTable1.C
EXE = $(FOAM_USER_APPBIN)/Test-HashTable1

View File

@ -30,7 +30,6 @@ Description
#include "HashTable.H"
#include "HashPtrTable.H"
#include "Map.H"
#include "StaticHashTable.H"
#include "cpuTime.H"
using namespace Foam;
@ -57,7 +56,6 @@ int main(int argc, char *argv[])
// ie, a
// Map<label> map(2 * nSize);
// HashTable<label, label, Hash<label>> map(2 * nSize);
// StaticHashTable<label, label, Hash<label>> map(2 * nSize);
HashTable<label, label, Hash<label>> map(2 * nSize);
Info<< "Constructed map of size: " << nSize;

View File

@ -0,0 +1,3 @@
Test-HashTable4.C
EXE = $(FOAM_USER_APPBIN)/Test-HashTable4

View File

@ -0,0 +1,2 @@
/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
/* EXE_LIBS = -lfiniteVolume */

View File

@ -0,0 +1,312 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Test HashTable resizing
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "HashSet.H"
#include "HashTable.H"
#include "Map.H"
#include "cpuTime.H"
#include "memInfo.H"
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
// #undef ORDERED
// #define ORDERED
using namespace Foam;
template<class T>
Ostream& printInfo(Ostream& os, const HashTable<T, T, Hash<T>>& ht)
{
os << " (size " << ht.size() << " capacity " << ht.capacity() << ") ";
return os;
}
template<class K, class V>
inline void insertElem
(
#ifdef ORDERED
std::set<K>& container,
#else
std::unordered_set<K, Hash<K>>& container,
#endif
K k,
V v
)
{
container.insert(k);
}
template<class K, class V>
inline void insertElem
(
#ifdef ORDERED
std::map<K, V>& container,
#else
std::unordered_map<K, V, Hash<K>>& container,
#endif
K k,
V v
)
{
container.insert(std::make_pair(k, v));
}
template<class K, class V>
inline void insertElem
(
HashSet<K, Hash<K>>& container,
K k,
V v
)
{
container.insert(k);
}
template<class K, class V>
inline void insertElem
(
HashTable<K, V, Hash<K>>& container,
K k,
V v
)
{
container.insert(k, v);
}
template<class Container>
inline void loopInsert(Container& container, const label n)
{
for (label i = 0; i < n; i++)
{
insertElem(container, i, i);
}
}
template<class Container>
inline unsigned long loopFind(const Container& container, const label n)
{
const auto endIter = container.end();
unsigned long sum = 0;
for (label i = 0; i < n; i++)
{
if (container.find(i) != endIter)
{
++sum;
}
}
return sum;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
const label nLoops = 200;
const label nFind = 10;
const label nElem = 1000000;
argList::noBanner();
argList::addBoolOption("std", "use std::unordered_map or std::set");
argList::addBoolOption("set", "test HashSet");
argList::addBoolOption("find", "test find");
argList args(argc, argv);
const bool optStd = args.optionFound("std");
const bool optSet = args.optionFound("set");
const bool optFnd = args.optionFound("find");
cpuTime timer;
memInfo mem;
Info<< "insert " << nElem << " (int) elements";
if (optFnd)
{
Info<< ", then find " << (nFind*nLoops) << " times\n";
}
else
{
Info<< " repeated " << nLoops << " times " << endl;
}
if (false)
{
// verify that resizing around (0) doesn't fail
HashTable<label, label, Hash<label>> map(32);
printInfo(Info, map) << endl;
map.insert(10, 1000);
map.resize(0);
printInfo(Info, map) << endl;
map.resize(10);
printInfo(Info, map) << endl;
map.clear();
printInfo(Info, map) << endl;
map.resize(0);
printInfo(Info, map) << endl;
return 0;
}
if (optStd)
{
if (optFnd)
{
#ifdef ORDERED
Info<< "using stl::set" << endl;
std::set<label> map;
#else
Info<< "using stl::unordered_set" << endl;
std::unordered_set<label, Hash<label>> map(32);
#endif
loopInsert(map, nElem);
(void)timer.cpuTimeIncrement();
unsigned long sum = 0;
for (label loopi = 0; loopi < nFind*nLoops; ++loopi)
{
sum += loopFind(map, nElem);
}
// check result (suppress compiler optimizations?)
if (sum == 0)
{
Info<<"sum=0\n";
}
}
else if (optSet)
{
#ifdef ORDERED
Info<< "using stl::set" << endl;
#else
Info<< "using stl::unordered_set" << endl;
#endif
for (label loopi = 0; loopi < nLoops; ++loopi)
{
#ifdef ORDERED
std::set<label> map;
#else
std::unordered_set<label, Hash<label>> map(32);
#endif
loopInsert(map, nElem);
}
}
else
{
#ifdef ORDERED
Info<< "using stl::map" << endl;
#else
Info<< "using stl::unordered_set" << endl;
#endif
for (label loopi = 0; loopi < nLoops; ++loopi)
{
#ifdef ORDERED
std::map<label, label> map;
#else
std::unordered_map<label, label, Hash<label>> map(32);
#endif
loopInsert(map, nElem);
}
}
}
else
{
if (optFnd)
{
Info<< "using HashSet" << endl;
HashSet<label, Hash<label>> map(32);
loopInsert(map, nElem);
(void)timer.cpuTimeIncrement();
unsigned long sum = 0;
for (label loopi = 0; loopi < nFind*nLoops; ++loopi)
{
sum += loopFind(map, nElem);
}
// check result (suppress compiler optimizations?)
if (sum == 0)
{
Info<<"sum=0\n";
}
}
else if (optSet)
{
Info<< "using HashSet" << endl;
for (label loopi = 0; loopi < nLoops; ++loopi)
{
HashSet<label, Hash<label>> map(32);
loopInsert(map, nElem);
}
}
else
{
Info<< "using HashTable" << endl;
for (label loopi = 0; loopi < nLoops; ++loopi)
{
HashTable<label, label, Hash<label>> map(32);
loopInsert(map, nElem);
}
}
}
Info<< timer.cpuTimeIncrement() << " s\n";
Info<< "mem info: " << mem.update() << endl;
return 0;
}
// ************************************************************************* //

View File

@ -31,14 +31,12 @@ Description
#include "boolList.H"
#include "PackedBoolList.H"
#include "HashSet.H"
#include "StaticHashTable.H"
#include "cpuTime.H"
#include <vector>
#include <unordered_set>
using namespace Foam;
#undef TEST_STATIC_HASH
#undef TEST_STD_BOOLLIST
#undef TEST_STD_UNORDERED_SET
@ -84,20 +82,6 @@ int main(int argc, char *argv[])
Info<< "populated labelHashSet in "
<< timer.cpuTimeIncrement() << " s\n\n";
#ifdef TEST_STATIC_HASH
// fullStaticHash is really slow
// give it lots of slots to help
StaticHashTable<nil, label, Hash<label>> emptyStaticHash;
StaticHashTable<nil, label, Hash<label>> fullStaticHash(100000);
for (label i = 0; i < n; i++)
{
fullStaticHash.insert(i, nil());
}
Info<< "populated StaticHashTable in "
<< timer.cpuTimeIncrement() << " s\n\n";
#endif
#ifdef TEST_STD_UNORDERED_SET
std::unordered_set<label, Foam::Hash<label>> emptyStdHash;
std::unordered_set<label, Foam::Hash<label>> fullStdHash;
@ -112,10 +96,6 @@ int main(int argc, char *argv[])
emptyHash.printInfo(Info);
fullHash.printInfo(Info);
#ifdef TEST_STATIC_HASH
emptyStaticHash.printInfo(Info);
fullStaticHash.printInfo(Info);
#endif
#ifdef TEST_STD_UNORDERED_SET
printInfo(emptyStdHash);
printInfo(fullStdHash);
@ -305,37 +285,6 @@ int main(int argc, char *argv[])
<< " sum " << sum << nl;
#ifdef TEST_STATIC_HASH
// Read empty StaticHashTable
sum = 0;
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
sum += emptyStaticHash.found(i);
}
}
std::cout
<< "Reading empty StaticHash:" << timer.cpuTimeIncrement()
<< " s" << nl
<< " sum " << sum << nl;
// Read full StaticHashTable
sum = 0;
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
sum += fullStaticHash.found(i);
}
}
std::cout
<< "Reading full StaticHash:" << timer.cpuTimeIncrement()
<< " s" << nl
<< " sum " << sum << nl;
#endif
#ifdef TEST_STD_UNORDERED_SET
// Read empty stl set
sum = 0;

View File

@ -1,3 +0,0 @@
Test-staticHashTable.C
EXE = $(FOAM_USER_APPBIN)/Test-staticHashTable

View File

@ -1,170 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "StaticHashTable.H"
#include "IOstreams.H"
#include "StringStream.H"
using namespace Foam;
// use define so we can easily test other implementations
#define HASHTABLE_CLASS StaticHashTable
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main()
{
HASHTABLE_CLASS<double> table1(13);
table1.insert("aaa", 1.0);
table1.insert("aba", 2.0);
table1.insert("aca", 3.0);
table1.insert("ada", 4.0);
table1.insert("aeq", 5.0);
table1.insert("aaw", 6.0);
table1.insert("abs", 7.0);
table1.insert("acr", 8.0);
table1.insert("adx", 9.0);
table1.insert("aec", 10.0);
table1.erase("aaw");
table1.erase("abs");
Info<< "\ntable1 toc: " << table1.toc() << endl;
table1.printInfo(Info)
<< "table1 [" << table1.size() << "] " << endl;
forAllIter(HASHTABLE_CLASS<double>, table1, iter)
{
Info<< iter.key() << " => " << iter() << nl;
}
table1.set("acr", 108);
table1.set("adx", 109);
table1.set("aec", 100);
table1("aaw") -= 1000;
table1("aeq") += 1000;
Info<< "\noverwrote some values table1: " << table1 << endl;
Info<< "\ntest find:" << endl;
Info<< table1.find("aaa")() << nl
<< table1.find("aba")() << nl
<< table1.find("aca")() << nl
<< table1.find("ada")() << nl
<< table1.find("aeq")() << nl
<< table1.find("acr")() << nl
<< table1.find("adx")() << nl
<< table1.find("aec")() << nl
<< table1["aaa"] << nl;
{
OStringStream os;
os << table1;
HASHTABLE_CLASS<double> readTable(IStringStream(os.str())(), 100);
Info<< "Istream constructor:" << readTable << endl;
}
HASHTABLE_CLASS<double> table2(table1);
HASHTABLE_CLASS<double> table3(table1.xfer());
Info<< "\ncopy table1 -> table2" << nl
<< "transfer table1 -> table3 via the xfer() method" << nl;
Info<< "\ntable1" << table1 << nl
<< "\ntable2" << table2 << nl
<< "\ntable3" << table3 << nl;
Info<< "\nerase table2 by iterator" << nl;
forAllIter(HASHTABLE_CLASS<double>, table2, iter)
{
Info<< "erasing " << iter.key() << " => " << iter() << " ... ";
table2.erase(iter);
Info<< "erased" << endl;
}
Info<< "\ntable1" << table1 << nl
<< "\ntable2" << table2 << nl
<< "\ntable3" << table3 << nl;
table3.resize(1);
Info<< "\nresize(1) table3" << nl;
table3.printInfo(Info)
<< table3 << nl;
table3.resize(10000);
Info<< "\nresize(10000) table3" << nl;
table3.printInfo(Info)
<< table3 << nl;
HASHTABLE_CLASS<double> table4;
table4 = table3;
Info<< "\ncopy table3 -> table4 " << table4 << nl;
Info<< "\nclear table4 ... ";
table4.clear();
Info<< "[" << table4.size() << "] " << table4 << nl;
table1 = table3;
Info<< "\ncopy table3 -> table1 (previously transferred)" << table1 << nl;
Info<< "test table1 == table3 : " << (table1 == table3) << nl;
table1.erase(table1.begin());
Info<< "removed an element - test table1 != table3 : "
<< (table1 != table3) << nl;
// insert a few things into table2
table2.set("ada", 14.0);
table2.set("aeq", 15.0);
table2.set("aaw", 16.0);
table2.set("abs", 17.0);
table2.set("adx", 20.0);
Info<< "\ntable1" << table1 << nl
<< "\ntable2" << table2 << nl;
label nErased = table1.erase(table2);
Info<< "\nerase table2 keys from table1 (removed "
<< nErased << " elements)" << nl
<< "\ntable1" << table1 << nl
<< "\ntable2" << table2 << nl;
Info<< "\ntable3" << table3
<< "\nclearStorage table3 ... ";
table3.clearStorage();
Info<< table3 << nl;
Info<< "\nDone\n";
return 0;
}
// ************************************************************************* //

View File

@ -61,6 +61,10 @@ int main(int argc, char *argv[])
nil x;
cout<<"nil:" << sizeof(x) << nl;
}
{
zero x;
cout<<"zero:" << sizeof(x) << nl;
}
{
bool x(0);
cout<<"bool:" << sizeof(x) << nl;
@ -93,6 +97,10 @@ int main(int argc, char *argv[])
cout<<"double:" << sizeof(double) << nl;
}
{
cout<<"string:" << sizeof(Foam::string) << nl;
}
Info << "---\nEnd\n" << endl;

View File

@ -65,7 +65,7 @@ export WM_COMPILER_TYPE=system
#- Compiler:
# WM_COMPILER = Gcc | Gcc4[8-9] | Gcc5[1-4] | Gcc6[1-3] | GccKNL
# | Clang | Clang3[8-9] | Clang40 | Icc | IccKNL | Cray
# | Clang | Clang3[8-9] | Gcc[45]0 | Icc | IccKNL | Cray
export WM_COMPILER=Gcc
unset WM_COMPILER_ARCH WM_COMPILER_LIB_ARCH

View File

@ -82,7 +82,10 @@ case ThirdParty:
set clang_version=llvm-3.9.1
breaksw
case Clang40:
set clang_version=llvm-4.0.0
set clang_version=llvm-4.0.1
breaksw
case Clang50:
set clang_version=llvm-5.0.0
breaksw
default:
/bin/cat << UNKNOWN_COMPILER

View File

@ -81,7 +81,10 @@ ThirdParty)
clang_version=llvm-3.9.1
;;
Clang40)
clang_version=llvm-4.0.0
clang_version=llvm-4.0.1
;;
Clang50)
clang_version=llvm-5.0.0
;;
*)
/bin/cat << UNKNOWN_COMPILER 1>&2

View File

@ -337,7 +337,6 @@ DebugSwitches
SpalartAllmarasIDDES 0;
SphereDrag 0;
StandardWallInteraction 0;
StaticHashTable 0;
StochasticDispersionRAS 0;
SuperBee 0;
SuperBeeV 0;

View File

@ -61,7 +61,7 @@ setenv WM_COMPILER_TYPE system
#- Compiler:
# WM_COMPILER = Gcc | Gcc4[8-9] | Gcc5[1-4] | Gcc6[1-3] | GccKNL
# | Clang | Clang3[8-9] | Clang40 | Icc | IccKNL | Cray
# | Clang | Clang3[8-9] | Gcc[45]0 | Icc | IccKNL | Cray
setenv WM_COMPILER Gcc
setenv WM_COMPILER_ARCH # defined but empty
unsetenv WM_COMPILER_LIB_ARCH

View File

@ -147,7 +147,6 @@ primitives/Barycentric/barycentric/barycentric.C
primitives/Barycentric2D/barycentric2D/barycentric2D.C
containers/HashTables/HashTable/HashTableCore.C
containers/HashTables/StaticHashTable/StaticHashTableCore.C
containers/Lists/SortableList/ParSortableListName.C
containers/Lists/PackedList/PackedListCore.C
containers/Lists/PackedList/PackedBoolList.C

View File

@ -28,6 +28,13 @@ License
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable()
:
parent_type()
{}
template<class T, class Key, class Hash>
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable(const label size)
:
@ -157,6 +164,7 @@ void Foam::HashPtrTable<T, Key, Hash>::operator=
}
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
#include "HashPtrTableIO.C"

View File

@ -91,8 +91,11 @@ public:
// Constructors
//- Construct null with default table size
HashPtrTable();
//- Construct given initial table size
HashPtrTable(const label size = 128);
explicit HashPtrTable(const label size);
//- Construct from Istream using given Istream constructor class
template<class INew>
@ -102,7 +105,7 @@ public:
HashPtrTable(Istream& is);
//- Construct from dictionary with default dictionary constructor class
HashPtrTable(const dictionary& dict);
explicit HashPtrTable(const dictionary& dict);
//- Construct as copy
HashPtrTable(const this_type& ht);
@ -127,7 +130,7 @@ public:
//- Erase an entry specified by the given key
bool erase(const Key& key);
//- Clear all entries from table
//- Clear all entries from table and deleting any allocated pointers
void clear();
//- Write

View File

@ -41,7 +41,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
is.fatalCheck
(
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
"HashPtrTable::read(Istream&, const INew&) : "
"reading first token"
);
@ -50,7 +50,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
const label s = firstToken.labelToken();
// Read beginning of contents
const char delimiter = is.readBeginList("HashPtrTable<T, Key, Hash>");
const char delimiter = is.readBeginList("HashPtrTable");
if (s)
{
@ -69,8 +69,8 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
is.fatalCheck
(
"HashPtrTable<T, Key, Hash>::"
"read(Istream&, const INew&) : reading entry"
"HashPtrTable::read(Istream&, const INew&) : "
"reading entry"
);
}
}
@ -114,7 +114,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
is.fatalCheck
(
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
"HashPtrTable::read(Istream&, const INew&) : "
"reading entry"
);
@ -155,7 +155,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read
template<class T, class Key, class Hash>
void Foam::HashPtrTable<T, Key, Hash>::write(Ostream& os) const
{
for (const_iterator iter = this->begin(); iter != this->end(); ++iter)
for (const_iterator iter = this->cbegin(); iter != this->cend(); ++iter)
{
const T* ptr = iter.object();
if (ptr)
@ -209,29 +209,34 @@ Foam::Ostream& Foam::operator<<
const HashPtrTable<T, Key, Hash>& tbl
)
{
using const_iterator = typename HashPtrTable<T, Key, Hash>::const_iterator;
const label sz = tbl.size();
// Write size and start delimiter
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
// Write contents
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
if (sz)
{
const T* ptr = iter.object();
// Size and start list delimiter
os << nl << sz << nl << token::BEGIN_LIST << nl;
os << iter.key();
if (ptr)
// Contents
for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
{
os << token::SPACE << *ptr;
const T* ptr = iter.object();
os << iter.key();
if (ptr)
{
os << token::SPACE << *ptr;
}
os << nl;
}
os << nl;
os << token::END_LIST; // End list delimiter
}
else
{
// Empty hash table
os << sz << token::BEGIN_LIST << token::END_LIST;
}
// Write end delimiter
os << token::END_LIST;
os.check(FUNCTION_NAME);
return os;
}

View File

@ -79,7 +79,7 @@ inline Foam::label Foam::HashSet<Key, Hash>::assignMultiple
template<class Key, class Hash>
Foam::HashSet<Key, Hash>::HashSet(const UList<Key>& lst)
:
HashTable<nil, Key, Hash>(2*lst.size())
parent_type(2*lst.size())
{
for (const auto& k : lst)
{
@ -92,7 +92,7 @@ template<class Key, class Hash>
template<unsigned Size>
Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
:
HashTable<nil, Key, Hash>(2*lst.size())
parent_type(2*lst.size())
{
for (const auto& k : lst)
{
@ -104,7 +104,7 @@ Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
template<class Key, class Hash>
Foam::HashSet<Key, Hash>::HashSet(std::initializer_list<Key> lst)
:
HashTable<nil, Key, Hash>(2*lst.size())
parent_type(2*lst.size())
{
for (const auto& k : lst)
{
@ -120,7 +120,7 @@ Foam::HashSet<Key, Hash>::HashSet
const HashTable<AnyType, Key, AnyHash>& tbl
)
:
HashTable<nil, Key, Hash>(tbl.capacity())
parent_type(tbl.capacity())
{
using other_iter =
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
@ -349,7 +349,7 @@ template<class Key, class Hash>
inline typename Foam::HashSet<Key, Hash>::const_iterator
Foam::HashSet<Key, Hash>::begin() const
{
return HashTableCore::iterator_begin<const_iterator>
return HashTableCore::iterator_cbegin<const_iterator>
(
static_cast<const parent_type&>(*this)
);
@ -360,7 +360,7 @@ template<class Key, class Hash>
inline typename Foam::HashSet<Key, Hash>::const_iterator
Foam::HashSet<Key, Hash>::cbegin() const
{
return HashTableCore::iterator_begin<const_iterator>
return HashTableCore::iterator_cbegin<const_iterator>
(
static_cast<const parent_type&>(*this)
);
@ -379,7 +379,7 @@ template<class Key, class Hash>
inline const typename Foam::HashSet<Key, Hash>::const_iterator&
Foam::HashSet<Key, Hash>::end() const
{
return HashTableCore::iterator_end<const_iterator>();
return HashTableCore::iterator_cend<const_iterator>();
}

View File

@ -25,7 +25,24 @@ Class
Foam::HashSet
Description
A HashTable with keys but without contents.
A HashTable with keys but without contents that is similar to
\c std::unordered_set.
The entries are considered \a unordered since their placement
depends on the method used to generate the hash key index, the
table capacity, insertion order etc. When the key order is
important, use the sortedToc() method to obtain a list of sorted
keys and use that for further access.
Note
The HashSet iterator dereferences to the key, so the following
range-for works as expected:
\code
HashSet<label> someLabels{10, 20, 30, 40, ...};
for (const label i : someLabels)
{
Info<< "val:" << i << nl;
}
\endcode
Typedef
Foam::wordHashSet
@ -45,7 +62,6 @@ Description
#define HashSet_H
#include "HashTable.H"
#include "nil.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -66,7 +82,7 @@ Ostream& operator<<(Ostream& os, const HashSet<Key, Hash>& tbl);
template<class Key=word, class Hash=string::hash>
class HashSet
:
public HashTable<nil, Key, Hash>
public HashTable<zero::null, Key, Hash>
{
// Private Member Functions
@ -94,7 +110,7 @@ public:
typedef HashSet<Key, Hash> this_type;
//- The template instance used for the parent HashTable
typedef HashTable<nil, Key, Hash> parent_type;
typedef HashTable<zero::null, Key, Hash> parent_type;
//- An iterator, returning reference to the key
using iterator = typename parent_type::key_iterator;
@ -105,13 +121,19 @@ public:
// Constructors
//- Construct null with default (128) table size
HashSet()
:
parent_type()
{}
//- Construct given initial size
HashSet(const label size = 128)
explicit HashSet(const label size)
:
parent_type(size)
{}
//- Construct from Istream
//- Construct from Istream with default table size
HashSet(Istream& is)
:
parent_type(is)
@ -140,13 +162,13 @@ public:
{}
//- Construct by transferring the parameter contents
HashSet(const Xfer<HashSet<Key, Hash>>& hs)
HashSet(const Xfer<this_type>& hs)
:
parent_type(hs)
{}
//- Construct by transferring the parameter contents
HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs)
HashSet(const Xfer<parent_type>& hs)
:
parent_type(hs)
{}
@ -166,7 +188,7 @@ public:
// not previously exist in the set.
bool insert(const Key& key)
{
return this->parent_type::insert(key, nil());
return this->parent_type::insert(key, zero::null());
}
//- Insert keys from the list of Key
@ -182,26 +204,26 @@ public:
// \return The number of new elements inserted
label insert(std::initializer_list<Key> lst);
//- Same as insert (cannot overwrite nil content)
//- Same as insert (no value to overwrite)
bool set(const Key& key)
{
return insert(key);
}
//- Same as insert (cannot overwrite nil content)
//- Same as insert (no value to overwrite)
label set(const UList<Key>& lst)
{
return insert(lst);
}
//- Same as insert (cannot overwrite nil content)
//- Same as insert (no value to overwrite)
template<unsigned Size>
label set(const FixedList<Key, Size>& lst)
{
return insert(lst);
}
//- Same as insert (cannot overwrite nil content)
//- Same as insert (no value to overwrite)
label set(std::initializer_list<Key> lst)
{
return insert(lst);
@ -331,22 +353,22 @@ public:
// Logical operations
//- Combine entries from HashSets
void operator|=(const HashSet<Key, Hash>& rhs);
void operator|=(const this_type& rhs);
//- Only retain entries found in both HashSets
inline void operator&=(const HashSet<Key, Hash>& rhs);
inline void operator&=(const this_type& rhs);
//- Only retain unique entries (xor)
void operator^=(const HashSet<Key, Hash>& rhs);
void operator^=(const this_type& rhs);
//- Add entries listed in the given HashSet to this HashSet
inline void operator+=(const HashSet<Key, Hash>& rhs)
inline void operator+=(const this_type& rhs)
{
this->operator|=(rhs);
}
//- Remove entries listed in the given HashSet from this HashSet
inline void operator-=(const HashSet<Key, Hash>& rhs);
inline void operator-=(const this_type& rhs);
// IOstream Operator

View File

@ -61,21 +61,27 @@ Foam::label Foam::HashTable<T, Key, Hash>::eraseMultiple
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable()
:
HashTable<T, Key, Hash>(128)
{}
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(const label size)
:
HashTableCore(),
nElmts_(0),
tableSize_(HashTableCore::canonicalSize(size)),
size_(0),
capacity_(HashTableCore::canonicalSize(size)),
table_(nullptr)
{
if (tableSize_)
if (capacity_)
{
table_ = new hashedEntry*[tableSize_];
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
table_ = new node_type*[capacity_];
for (label i=0; i < capacity_; ++i)
{
table_[hashIdx] = nullptr;
table_[i] = nullptr;
}
}
}
@ -84,7 +90,7 @@ Foam::HashTable<T, Key, Hash>::HashTable(const label size)
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
:
HashTable<T, Key, Hash>(ht.tableSize_)
HashTable<T, Key, Hash>(ht.capacity_)
{
for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
{
@ -96,10 +102,7 @@ Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(HashTable<T, Key, Hash>&& ht)
:
HashTableCore(),
nElmts_(0),
tableSize_(0),
table_(nullptr)
HashTable<T, Key, Hash>(0)
{
transfer(ht);
}
@ -111,10 +114,7 @@ Foam::HashTable<T, Key, Hash>::HashTable
const Xfer<HashTable<T, Key, Hash>>& ht
)
:
HashTableCore(),
nElmts_(0),
tableSize_(0),
table_(nullptr)
HashTable<T, Key, Hash>(0)
{
transfer(ht());
}
@ -150,110 +150,10 @@ Foam::HashTable<T, Key, Hash>::~HashTable()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
if (key == ep->key_)
{
return true;
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return false;
}
template<class T, class Key, class Hash>
typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::find
(
const Key& key
)
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
if (key == ep->key_)
{
return iterator(this, ep, hashIdx);
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return iterator();
}
template<class T, class Key, class Hash>
typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::find
(
const Key& key
) const
{
return this->cfind(key);
}
template<class T, class Key, class Hash>
typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::cfind
(
const Key& key
) const
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{
if (key == ep->key_)
{
return const_iterator(this, ep, hashIdx);
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return const_iterator();
}
template<class T, class Key, class Hash>
Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
{
List<Key> keyLst(nElmts_);
List<Key> keyLst(size_);
label count = 0;
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
@ -297,7 +197,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocKeys
const bool invert
) const
{
List<Key> keyLst(nElmts_);
List<Key> keyLst(size_);
label count = 0;
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
@ -323,7 +223,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocValues
const bool invert
) const
{
List<Key> keyLst(nElmts_);
List<Key> keyLst(size_);
label count = 0;
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
@ -349,7 +249,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocEntries
const bool invert
) const
{
List<Key> keyLst(nElmts_);
List<Key> keyLst(size_);
label count = 0;
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
@ -438,36 +338,36 @@ bool Foam::HashTable<T, Key, Hash>::set
(
const Key& key,
const T& obj,
const bool protect
const bool overwrite
)
{
if (!tableSize_)
if (!capacity_)
{
resize(2);
}
const label hashIdx = hashKeyIndex(key);
const label index = hashKeyIndex(key);
hashedEntry* existing = nullptr;
hashedEntry* prev = nullptr;
node_type* curr = nullptr;
node_type* prev = nullptr;
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
for (node_type* ep = table_[index]; ep; ep = ep->next_)
{
if (key == ep->key_)
if (key == ep->key())
{
existing = ep;
curr = ep;
break;
}
prev = ep;
}
if (!existing)
if (!curr)
{
// Not found, insert it at the head
table_[hashIdx] = new hashedEntry(key, obj, table_[hashIdx]);
nElmts_++;
table_[index] = new node_type(key, obj, table_[index]);
++size_;
if (double(nElmts_)/tableSize_ > 0.8 && tableSize_ < maxTableSize)
if (double(size_)/capacity_ > 0.8 && capacity_ < maxTableSize)
{
#ifdef FULLDEBUG
if (debug)
@ -476,13 +376,35 @@ bool Foam::HashTable<T, Key, Hash>::set
}
#endif
resize(2*tableSize_);
resize(2*capacity_);
}
}
else if (protect)
else if (overwrite)
{
// Found - but protected from overwriting
// this corresponds to the STL 'insert' convention
// Overwrite current entry (Perl convention).
node_type* ep = curr->next_; // next in the linked list
// In some cases the delete/new could be avoided in favour of move
// assignment, but cannot be certain that all objects support this
// or that it behaves the same as a copy construct.
delete curr;
ep = new node_type(key, obj, ep);
// Replace current element - within list or insert at the head
if (prev)
{
prev->next_ = ep;
}
else
{
table_[index] = ep;
}
}
else
{
// Do not overwrite existing entry (STL 'insert' convention)
#ifdef FULLDEBUG
if (debug)
{
@ -492,99 +414,22 @@ bool Foam::HashTable<T, Key, Hash>::set
#endif
return false;
}
else
{
// Found - overwrite existing entry
// this corresponds to the Perl convention
hashedEntry* ep = new hashedEntry(key, obj, existing->next_);
// Replace existing element - within list or insert at the head
if (prev)
{
prev->next_ = ep;
}
else
{
table_[hashIdx] = ep;
}
delete existing;
}
return true;
}
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::iterator_base::erase()
{
// Note: entryPtr_ is nullptr for end(), so this catches that too
if (entryPtr_)
{
// Search element before entryPtr_
entry_type* prev = nullptr;
for
(
entry_type* ep = hashTable_->table_[hashIndex_];
ep;
ep = ep->next_
)
{
if (ep == entryPtr_)
{
break;
}
prev = ep;
}
if (prev)
{
// Has an element before entryPtr - reposition to there
prev->next_ = entryPtr_->next_;
delete entryPtr_;
entryPtr_ = prev;
}
else
{
// entryPtr was first element on SLList
hashTable_->table_[hashIndex_] = entryPtr_->next_;
delete entryPtr_;
// Assign any non-nullptr value so it doesn't look like end()
entryPtr_ = reinterpret_cast<hashedEntry*>(this);
// Mark with special hashIndex value to signal it has been rewound.
// The next increment will bring it back to the present location.
//
// From the current position 'curPos', we wish to continue at
// prevPos='curPos-1', which we mark as markPos='-curPos-1'.
// The negative lets us notice it is special, the extra '-1'
// is needed to avoid ambiguity for position '0'.
// To retrieve prevPos, we would later use '-(markPos+1) - 1'
hashIndex_ = -hashIndex_ - 1;
}
hashTable_->nElmts_--;
return true;
}
else
{
return false;
}
}
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
{
// NOTE: We use (const iterator&) here, but manipulate its contents anyhow.
// NOTE: we use (const iterator&) here, but treat its contents as mutable.
//
// The parameter should be (iterator&), but then the compiler doesn't find
// it correctly and tries to call as (iterator) instead.
//
// Adjust iterator after erase
return const_cast<iterator&>(iter).erase();
iterator& it = const_cast<iterator&>(iter);
return iterator_erase(it.entry_, it.index_);
}
@ -599,7 +444,7 @@ bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
template<class T, class Key, class Hash>
Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
{
return eraseMultiple(keys.begin(), keys.end());
return eraseMultiple(keys.cbegin(), keys.cend());
}
@ -610,7 +455,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
const FixedList<Key, Size>& keys
)
{
return eraseMultiple(keys.begin(), keys.end());
return eraseMultiple(keys.cbegin(), keys.cend());
}
@ -634,17 +479,14 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
const label nTotal = this->size();
label changed = 0;
using other_iter =
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
if (other.size() <= nTotal)
{
// The other is smaller/same-size, use its keys for removal
for
(
other_iter iter = other.begin();
changed < nTotal && iter != other.end(); // terminate early
auto iter = other.cbegin();
changed < nTotal && iter != other.cend(); // Terminate early
++iter
)
{
@ -660,7 +502,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
for
(
iterator iter = begin();
changed < nTotal && iter != end(); // terminate early
changed < nTotal && iter != end(); // Terminate early
++iter
)
{
@ -711,9 +553,10 @@ Foam::label Foam::HashTable<T, Key, Hash>::retain
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::resize(const label sz)
{
const label newSize = HashTableCore::canonicalSize(sz);
const label newCapacity = HashTableCore::canonicalSize(sz);
const label oldCapacity = capacity_;
if (newSize == tableSize_)
if (newCapacity == oldCapacity)
{
#ifdef FULLDEBUG
if (debug)
@ -724,46 +567,85 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
return;
}
HashTable<T, Key, Hash>* tmpTable = new HashTable<T, Key, Hash>(newSize);
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
else if (!newCapacity)
{
tmpTable->insert(iter.key(), iter.object());
// Special treatment for resize(0)
if (size_)
{
WarningInFunction
<< "HashTable contains " << size_ << " cannot resize(0)"
<< endl;
}
else
{
if (table_)
{
delete[] table_;
capacity_ = 0;
}
table_ = nullptr;
}
return;
}
const label oldSize = tableSize_;
tableSize_ = tmpTable->tableSize_;
tmpTable->tableSize_ = oldSize;
// Swap primary table entries: size_ is left untouched
hashedEntry** oldTable = table_;
table_ = tmpTable->table_;
tmpTable->table_ = oldTable;
auto oldTable = table_;
capacity_ = newCapacity;
delete tmpTable;
table_ = new node_type*[capacity_];
for (label i=0; i < capacity_; ++i)
{
table_[i] = nullptr;
}
// Move to new table[] but with new chaining.
label nMove = size_; // Allow early completion
for (label i=0; nMove && i < oldCapacity; ++i)
{
for (node_type* ep = oldTable[i]; ep; /*nil*/)
{
node_type* next = ep->next_;
// Move to new location
{
const label newIdx = hashKeyIndex(ep->key());
ep->next_ = table_[newIdx]; // add to head
table_[newIdx] = ep;
}
ep = next; // continue in the linked-list
--nMove; // note any early completion
}
oldTable[i] = nullptr;
}
if (oldTable)
{
delete[] oldTable;
}
}
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::clear()
{
if (nElmts_)
for (label i=0; size_ && i<capacity_; ++i)
{
for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
for (node_type* ep = table_[i]; ep; /*nil*/)
{
if (table_[hashIdx])
{
hashedEntry* ep = table_[hashIdx];
while (hashedEntry* next = ep->next_)
{
delete ep;
ep = next;
}
delete ep;
table_[hashIdx] = nullptr;
}
node_type* next = ep->next_;
delete ep;
ep = next; // continue in the linked-list
--size_; // note any early completion
}
nElmts_ = 0;
table_[i] = nullptr;
}
}
@ -779,30 +661,31 @@ void Foam::HashTable<T, Key, Hash>::clearStorage()
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::swap(HashTable<T, Key, Hash>& ht)
{
Foam::Swap(table_, ht.table_);
Foam::Swap(tableSize_, ht.tableSize_);
Foam::Swap(nElmts_, ht.nElmts_);
Foam::Swap(size_, ht.size_);
Foam::Swap(capacity_, ht.capacity_);
Foam::Swap(table_, ht.table_);
}
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
{
// As per the Destructor
// As per destructor
if (table_)
{
clear();
delete[] table_;
}
tableSize_ = ht.tableSize_;
ht.tableSize_ = 0;
size_ = ht.size_;
ht.size_ = 0;
capacity_ = ht.capacity_;
ht.capacity_ = 0;
table_ = ht.table_;
ht.table_ = nullptr;
nElmts_ = ht.nElmts_;
ht.nElmts_ = 0;
}
@ -904,9 +787,9 @@ void Foam::HashTable<T, Key, Hash>::operator=
}
// Could be zero-sized from a previous transfer()
if (!tableSize_)
if (!capacity_)
{
resize(rhs.tableSize_);
resize(rhs.capacity_);
}
else
{
@ -927,7 +810,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
)
{
// Could be zero-sized from a previous transfer()
if (!tableSize_)
if (!capacity_)
{
resize(2*lst.size());
}
@ -975,7 +858,7 @@ bool Foam::HashTable<T, Key, Hash>::operator==
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{
const_iterator other = this->cfind(iter.key());
const const_iterator other(this->cfind(iter.key()));
if (!other.found() || other.object() != iter.object())
{
@ -997,8 +880,11 @@ bool Foam::HashTable<T, Key, Hash>::operator!=
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Iterators, Friend Operators
#include "HashTableIter.C"
#include "HashTableIO.C"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -25,14 +25,15 @@ Class
Foam::HashTable
Description
An STL-conforming hash table.
A HashTable similar to \c std::unordered_map.
The entries are considered \a unordered since their placement
depends on the method used to generate the hash key index, the
table capacity, insertion order etc. When the key order is
important, use the sortedToc() method to obtain a list of sorted
keys and use that for further access.
Note
Hashing index collisions are handled via chaining using a singly-linked
list with the colliding entry being added to the head of the linked
list. Thus copying the hash table (or indeed even resizing it) will
often result in a different hash order. Use a sorted table-of-contents
when the hash order is important.
Internally the table uses closed addressing into a flat storage space
with collisions handled by linked-list chaining.
The end iterator of all hash-tables has a nullptr to the hash entry.
Thus avoid separate allocation for each table and use a single one with
@ -41,10 +42,38 @@ Note
a nullptr as its first data member.
The nullObject is such an item (with a nullptr data member).
Note
For historical reasons, dereferencing the table iterator
(eg, \a *iter) returns a reference to the stored object value
value rather than the stored key/object value like std::unordered_map
does.
The HashTable iterator:
\code
forAllConstIters(table, iter)
{
Info<< "val:" << *iter << nl
<< "key:" << iter.key() << nl;
<< "val:" << iter.object() << nl;
}
\endcode
whereas for the \c std::unordered_map iterator:
\code
forAllConstIters(stdmap, iter)
{
Info<< "key/val:" << *iter << nl
<< "key:" << iter->first << nl
<< "val:" << iter->second << nl;
}
\endcode
This difference is most evident when using range-for syntax.
SourceFiles
HashTableI.H
HashTableIterI.H
HashTable.C
HashTableIO.C
HashTableIter.C
\*---------------------------------------------------------------------------*/
@ -52,6 +81,7 @@ SourceFiles
#define HashTable_H
#include "word.H"
#include "zero.H"
#include "Xfer.H"
#include "Hash.H"
#include "HashTableCore.H"
@ -80,7 +110,7 @@ Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl);
/*---------------------------------------------------------------------------*\
Class HashTable Declaration
Class HashTable Declaration
\*---------------------------------------------------------------------------*/
template<class T, class Key=word, class Hash=string::hash>
@ -88,6 +118,140 @@ class HashTable
:
public HashTableCore
{
// Private types for table entries
//- Structure with a (K,V) tuple and a linked-list for collisions
// Could store key/object as std::pair, but no particular advantage
// unless the iterator dereference type changes.
struct pair_entry
{
//- Type of key
typedef Key key_type;
//- Object content type
typedef T mapped_type;
//- The lookup key
key_type key_;
//- The data object
mapped_type obj_;
//- Addressing (next in collision list)
pair_entry* next_;
//- Construct from key, object, next pointer
pair_entry(const Key& key, const T& obj, pair_entry* next)
:
key_(key),
obj_(obj),
next_(next)
{}
//- The key
const key_type& key() const
{
return key_;
}
//- The mapped object
const mapped_type& mapped() const
{
return obj_;
}
mapped_type& mapped()
{
return obj_;
}
private:
//- Disallow default bitwise copy construct / assignment
pair_entry(const pair_entry&) = delete;
void operator=(const pair_entry&) = delete;
};
//- Structure with a single (K) value and a linked-list for collisions
struct unary_entry
{
//- Type of key
typedef Key key_type;
//- Object content type
typedef zero::null mapped_type;
//- Content storage type to the entry
typedef key_type value_type;
//- The lookup key == content
key_type key_;
//- Addressing (next in collision list)
unary_entry* next_;
//- Construct from key, (ununsed) object, next pointer
unary_entry(const Key& key, const T&, unary_entry* next)
:
key_(key),
next_(next)
{}
//- The key
const key_type& key() const
{
return key_;
}
//- Dummy mapped object
const mapped_type& mapped() const
{
return zeroNullElement;
}
mapped_type& mapped()
{
return zeroNullElement;
}
private:
//- Disallow default bitwise copy construct / assignment
unary_entry(const unary_entry&) = delete;
void operator=(const unary_entry&) = delete;
};
//- Hashed node with a linked-list for collisions
typedef typename std::conditional
<
std::is_same<zero::null, typename std::remove_cv<T>::type>::value,
unary_entry,
pair_entry
>::type node_type;
// Private Data
//- The number of nodes currently stored in table
label size_;
//- Number of nodes allocated in table
label capacity_;
//- The table of primary nodes
node_type** table_;
// Private Member Functions
//- Return the hash index of the Key within the current table size.
// No checks for zero-sized tables.
inline label hashKeyIndex(const Key& key) const;
//- Assign a new hash-entry to a possibly already existing key.
// \return True if the new entry was set.
bool set(const Key& key, const T& obj, const bool overwrite);
public:
//- The template instance used for this HashTable
@ -96,18 +260,25 @@ public:
// STL type definitions
//- Type of keys that the HashTable uses.
//- The second template parameter, type of keys used.
typedef Key key_type;
//- Type of values that the HashTable contains.
//- The first template parameter, type of objects contained.
typedef T mapped_type;
//- Same as mapped_type for OpenFOAM HashTables
// Note that this is different than the std::map definition.
typedef T value_type;
//- The third template parameter, the hash index method.
typedef Hash hasher;
//- The type used for storing into value_type objects.
// This type is usually value_type&.
// This type is usually 'value_type*'.
typedef T* pointer;
//- The type used for storing into value_type objects.
// This type is usually value_type&.
// This type is usually 'value_type&'.
typedef T& reference;
//- The type used for reading from constant value_type objects.
@ -129,65 +300,14 @@ public:
//- Forward iterator with const access
class const_iterator;
private:
// Private data type for table entries
//- Structure to hold a hashed entry, with a linked-list for collisions
struct hashedEntry
{
//- The lookup key
Key key_;
//- The data object
T obj_;
//- Pointer to next hashedEntry in sub-list
hashedEntry* next_;
//- Construct from key, object, next pointer
inline hashedEntry(const Key& key, const T& obj, hashedEntry* next);
private:
//- Disallow default bitwise copy construct
hashedEntry(const hashedEntry&) = delete;
//- Disallow default bitwise assignment
void operator=(const hashedEntry&) = delete;
};
// 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
label tableSize_;
//- The table of primary entries
hashedEntry** table_;
// Private Member Functions
//- Return the hash index of the Key within the current table size.
// No checks for zero-sized tables.
inline label hashKeyIndex(const Key& key) const;
//- Assign a new hash-entry to a possibly already existing key.
// \return True if the new entry was set.
bool set(const Key& key, const T& obj, const bool protect);
protected:
//- Internally used base for iterator and const_iterator
class iterator_base;
template<bool Const> class Iterator;
//- Friendship with the iterator_base is required.
friend class iterator_base;
//- Friendship with the base iterator is required.
friend class Iterator<true>;
friend class Iterator<false>;
// Protected Member Functions
@ -205,20 +325,23 @@ public:
// Constructors
//- Construct given initial table size
HashTable(const label size = 128);
//- Construct null with default (128) table size
HashTable();
//- Construct from Istream
//- Construct given initial table size
explicit HashTable(const label size);
//- Construct from Istream with default table size
HashTable(Istream& is, const label size = 128);
//- Construct as copy
HashTable(const HashTable<T, Key, Hash>& ht);
HashTable(const this_type& ht);
//- Move construct
HashTable(HashTable<T, Key, Hash>&& ht);
HashTable(this_type&& ht);
//- Construct by transferring the parameter contents
HashTable(const Xfer<HashTable<T, Key, Hash>>& ht);
HashTable(const Xfer<this_type>& ht);
//- Construct from an initializer list
HashTable(std::initializer_list<std::pair<Key, T>> lst);
@ -242,19 +365,19 @@ public:
inline bool empty() const;
//- Return true if hashed entry is found in table
bool found(const Key& key) const;
inline bool found(const Key& key) const;
//- Find and return an iterator set at the hashed entry
// If not found iterator = end()
iterator find(const Key& key);
inline iterator find(const Key& key);
//- Find and return an const_iterator set at the hashed entry
// If not found iterator = end()
const_iterator find(const Key& key) const;
inline const_iterator find(const Key& key) const;
//- Find and return an const_iterator set at the hashed entry
// If not found iterator = end()
const_iterator cfind(const Key& key) const;
inline const_iterator cfind(const Key& key) const;
//- Return hashed entry if it exists, or return the given default
inline const T& lookup(const Key& key, const T& deflt) const;
@ -512,149 +635,157 @@ protected:
// and prevent most external usage.
// iterator and const_iterator have the same size, allowing
// us to reinterpret_cast between them (if desired)
class iterator_base
template<bool Const>
class Iterator
{
public:
// Public typedefs
using table_type = this_type;
using key_type = this_type::key_type;
// Typedefs
using iterator_category = std::forward_iterator_tag;
using difference_type = this_type::difference_type;
using difference_type = this_type::difference_type;
private:
using entry_type = hashedEntry;
//- The HashTable container type
using table_type = typename std::conditional
<
Const,
const this_type,
this_type
>::type;
// Private Data
//- The node-type being addressed
using node_type = typename std::conditional
<
Const,
const this_type::node_type,
this_type::node_type
>::type;
//- Currently selected entry.
// MUST be the first member for easy comparison between iterators
// and for reinterpret_cast from nullObject
entry_type* entryPtr_;
//- The key type
using key_type = this_type::key_type;
//- Pointer to the hash-table for which this is an iterator
// This allows use of the default bitwise copy/assignment
table_type* hashTable_;
//- The object type being addressed
using mapped_type = typename std::conditional
<
Const,
const this_type::mapped_type,
this_type::mapped_type
>::type;
// Member Functions
//- True if iterator points to an entry
// This can be used directly instead of comparing to end()
inline bool found() const;
//- The key associated with the iterator
inline const Key& key() const;
// Member Operators
//- Compare hash-entry element pointers.
// Independent of const/non-const access
inline bool operator==(const Iterator<true>& iter) const;
inline bool operator!=(const Iterator<true>& iter) const;
inline bool operator==(const Iterator<false>& iter) const;
inline bool operator!=(const Iterator<false>& iter) const;
//- Current hash index within the hash-table data.
// A signed value, since erase() uses a negative value to signal
// the erasure state.
label hashIndex_;
protected:
friend class HashTable; // For begin/find constructors
// Protected Data
//- The selected entry.
// MUST be the first member for easy comparison between iterators
// and for reinterpret_cast from nullObject
node_type* entry_;
//- The hash-table container being iterated on.
// Using a pointer allows default bitwise copy/assignment
table_type* container_;
//- Index within the hash-table data.
// A signed value, since iterator_erase() needs a negative value
// to mark the position.
label index_;
// Protected Constructors
//- Construct null (end iterator)
inline Iterator();
//- Construct from begin of hash-table
inline Iterator(bool, table_type* tbl);
//- Construct by finding key in hash table
inline Iterator(table_type* tbl, const Key& key);
// Protected Member Functions
//- Increment to the next position
inline void increment();
//- The referenced object/value element
inline T& element() const;
//- The object associated with the iterator
inline mapped_type& object() const
{
return entry_->mapped();
}
//- Erase the entry at the current position
bool erase();
public:
// Constructors
//- Construct null (end iterator)
inline iterator_base();
//- Construct from begin of hash-table
inline explicit iterator_base(const table_type* hashTbl);
//- Construct from hash table, element and hash index
inline iterator_base
(
const table_type* hashTbl,
const entry_type* elmt,
const label hashIndex
);
// Member functions/operators
//- True if iterator points to an entry
// This can be used directly instead of comparing to end()
inline bool found() const;
//- Return the Key corresponding to the iterator
inline const Key& key() const;
//- Compare hash-entry element pointers
inline bool operator==(const iterator_base& iter) const;
inline bool operator!=(const iterator_base& iter) const;
//- Permit an explicit cast to the other (const/non-const) searcher
inline explicit operator const Iterator<!Const>&() const
{
return *reinterpret_cast<const Iterator<!Const>*>(this);
}
};
//- Low-level entry erasure using iterator internals.
// This invalidates the iterator until the next ++ operation.
// \return True if the corresponding entry existed and was removed
bool iterator_erase(node_type*& entry, label& index);
public:
//- An iterator wrapper for returning a reference to the key
template<class WrappedIterator>
class key_iterator_base
:
public WrappedIterator
{
public:
using value_type = this_type::key_type;
using pointer = const Key*;
using reference = const Key&;
//- Implicit conversion
inline key_iterator_base(const WrappedIterator& iter);
//- Return the key
inline reference operator*() const;
inline reference operator()() const;
inline key_iterator_base& operator++();
inline key_iterator_base operator++(int);
};
// STL iterator
//- Forward iterator with non-const access
class iterator
:
public iterator_base
public Iterator<false>
{
friend class HashTable; // Uses iterator::erase() method
using entry_type = hashedEntry;
public:
// Typedefs
using iterator_category = std::forward_iterator_tag;
using difference_type = this_type::difference_type;
// Public typedefs
using table_type = this_type;
using value_type = this_type::value_type;
using pointer = this_type::pointer;
using reference = this_type::reference;
using key_type = this_type::key_type;
using mapped_type = this_type::mapped_type;
using value_type = this_type::value_type;
using pointer = this_type::pointer;
using reference = this_type::reference;
// Constructors
//- Construct null (end iterator)
inline iterator();
inline iterator() {}
//- Construct from begin of hash-table
inline explicit iterator(table_type* hashTbl);
//- Copy construct from similar access type
inline explicit iterator(const Iterator<false>& iter)
:
Iterator<false>(iter)
{}
//- Construct from hash table, element and hash index
// Used by the hash-table find() method.
inline iterator
(
table_type* hashTbl,
entry_type* elmt,
const label hashIndex
);
// Member functions/operators
//- Return non-const access to referenced object
inline reference object() const;
//- Non-const access to referenced object
using Iterator<false>::object;
//- Return non-const access to referenced object
inline reference operator*() const;
inline reference operator()() const;
//- Non-const access to referenced object
inline reference operator*() const { return this->object(); }
inline reference operator()() const { return this->object(); }
inline iterator& operator++();
inline iterator operator++(int);
@ -666,54 +797,111 @@ public:
//- Forward iterator with const access
class const_iterator
:
public iterator_base
public Iterator<true>
{
using entry_type = const hashedEntry;
public:
// Typedefs
using iterator_category = std::forward_iterator_tag;
using difference_type = this_type::difference_type;
// Public typedefs
using table_type = const this_type;
using value_type = const this_type::value_type;
using pointer = this_type::const_pointer;
using reference = this_type::const_reference;
using key_type = this_type::key_type;
using mapped_type = const this_type::mapped_type;
using value_type = const this_type::value_type;
using pointer = this_type::const_pointer;
using reference = this_type::const_reference;
// Constructors
//- Construct null (end iterator)
inline const_iterator();
inline const_iterator() {}
//- Construct from begin of hash-table
inline explicit const_iterator(table_type* hashTbl);
//- Copy construct from similar access type
inline explicit const_iterator(const Iterator<true>& iter)
:
Iterator<true>(iter)
{}
//- Construct from hash table, element and hash index.
// Used by the hash-table find() method.
inline const_iterator
(
table_type* hashTbl,
entry_type* elmt,
const label hashIndex
);
//- Copy construct from dissimilar access type
inline explicit const_iterator(const Iterator<false>& iter)
:
Iterator<true>
(
static_cast<const Iterator<true>&>(iter)
)
{}
//- Implicit conversion from dissimilar access type
inline const_iterator(const iterator& iter)
:
const_iterator(reinterpret_cast<const const_iterator&>(iter))
{}
//- Copy construct from iterator
inline const_iterator(const iterator& iter);
// Member functions/operators
//- Return const access to referenced object
inline reference object() const;
//- Const access to referenced object
using Iterator<true>::object;
//- Return const access to referenced object
inline reference operator*() const;
inline reference operator()() const;
//- Const access to referenced object
inline reference operator*() const { return this->object(); }
inline reference operator()() const { return this->object(); }
inline const_iterator& operator++();
inline const_iterator operator++(int);
// Assignment
const_iterator& operator=(const const_iterator&) = default;
// Allow assign from iterator to const_iterator
const_iterator& operator=(const iterator& iter)
{
return this->operator=
(
reinterpret_cast<const const_iterator&>(iter)
);
}
};
//- Iterating over keys only
//- An iterator wrapper for returning a reference to the key
template<class Iter>
class key_iterator_base
:
public Iter
{
public:
using value_type = this_type::key_type;
using pointer = const Key*;
using reference = const Key&;
//- Implicit conversion
inline key_iterator_base(const Iter& iter)
:
Iter(iter)
{}
//- Return the key
inline reference operator*() const { return this->key(); }
inline reference operator()() const { return this->key(); }
inline key_iterator_base& operator++()
{
this->increment();
return *this;
}
inline key_iterator_base operator++(int)
{
key_iterator_base iter(*this);
this->increment();
return iter;
}
};
//- Forward iterator returning the key
using key_iterator = key_iterator_base<iterator>;
@ -793,6 +981,7 @@ inline void Swap
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "HashTableI.H"
#include "HashTableIterI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -36,6 +36,8 @@ defineTypeNameAndDebug(HashTableCore, 0);
// Approximately labelMax/4
const Foam::label Foam::HashTableCore::maxTableSize(1L << (sizeof(label)*8-3));
Foam::zero::null Foam::HashTableCore::zeroNullElement;
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
@ -50,7 +52,7 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
return maxTableSize;
}
// Enforce power of two - makes for a very fast modulus.
// Enforce power of two for fast modulus in hash index calculations.
// Use unsigned for these calculations.
//
// - The lower limit (8) is somewhat arbitrary, but if the hash table
@ -65,7 +67,8 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
{
return powerOfTwo;
}
else if (size & (size-1)) // <- Modulus of i^2
if (size & (size-1)) // <- Modulus of i^2
{
// Determine power-of-two. Brute-force is fast enough.
while (powerOfTwo < size)
@ -75,10 +78,8 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
return powerOfTwo;
}
else
{
return size;
}
return size;
}

View File

@ -40,6 +40,7 @@ SourceFiles
#include "uLabel.H"
#include "className.H"
#include "nullObject.H"
#include "zero.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -77,20 +78,16 @@ struct HashTableCore
template<class IteratorType, class TableType>
inline static IteratorType iterator_begin(TableType& table);
//- Factory method to create a const iterator begin
template<class IteratorType, class TableType>
inline static IteratorType iterator_begin(const TableType& table);
//- Factory method to create a const iterator begin
template<class IteratorType, class TableType>
inline static IteratorType iterator_cbegin(const TableType& table);
//- Factory method to create a non-const iterator end
//- Factory method to return an iterator end
// Simply reinterprets a NullObject as a hash-table iterator.
template<class IteratorType>
inline static const IteratorType& iterator_end();
//- Factory method to create a const iterator cend
//- Factory method to return an iterator cend
// Simply reinterprets a NullObject as a hash-table iterator.
template<class IteratorType>
inline static const IteratorType& iterator_cend();
@ -116,6 +113,13 @@ struct HashTableCore
inline const IteratorType& end() const;
inline const IteratorType& cend() const;
};
protected:
//- A static zero::null for dereferencing as a dummy HashSet element
static zero::null zeroNullElement;
};

View File

@ -35,16 +35,6 @@ inline IteratorType Foam::HashTableCore::iterator_begin
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::iterator_begin
(
const TableType& table
)
{
return IteratorType(table.begin());
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::iterator_cbegin
(

View File

@ -25,30 +25,14 @@ License
#include "error.H"
// * * * * * * * * * * * * * Private Member Classes * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::hashedEntry::hashedEntry
(
const Key& key,
const T& obj,
hashedEntry* next
)
:
key_(key),
obj_(obj),
next_(next)
{}
// * * * * * * * * * * * * 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);
// capacity is always a power of two - this is the modulus
return Hash()(key) & (capacity_ - 1);
}
@ -57,21 +41,76 @@ Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
template<class T, class Key, class Hash>
inline Foam::label Foam::HashTable<T, Key, Hash>::capacity() const
{
return tableSize_;
return capacity_;
}
template<class T, class Key, class Hash>
inline Foam::label Foam::HashTable<T, Key, Hash>::size() const
{
return nElmts_;
return size_;
}
template<class T, class Key, class Hash>
inline bool Foam::HashTable<T, Key, Hash>::empty() const
{
return !nElmts_;
return !size_;
}
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
{
if (size_)
{
return Iterator<true>(this, key).found();
}
return false;
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::find
(
const Key& key
)
{
if (size_)
{
return iterator(Iterator<false>(this, key));
}
return iterator();
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::find
(
const Key& key
) const
{
return this->cfind(key);
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::cfind
(
const Key& key
) const
{
if (size_)
{
return const_iterator(Iterator<true>(this, key));
}
return const_iterator();
}
@ -82,7 +121,7 @@ inline bool Foam::HashTable<T, Key, Hash>::insert
const T& obj
)
{
return this->set(key, obj, true);
return this->set(key, obj, false); // No overwrite
}
@ -93,7 +132,7 @@ inline bool Foam::HashTable<T, Key, Hash>::set
const T& obj
)
{
return this->set(key, obj, false);
return this->set(key, obj, true); // Overwrite
}
@ -112,7 +151,7 @@ inline const T& Foam::HashTable<T, Key, Hash>::lookup
const T& deflt
) const
{
const_iterator iter = this->find(key);
const const_iterator iter(this->cfind(key));
return iter.found() ? iter.object() : deflt;
}
@ -122,7 +161,7 @@ inline const T& Foam::HashTable<T, Key, Hash>::lookup
template<class T, class Key, class Hash>
inline T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key)
{
iterator iter = this->find(key);
const iterator iter(this->find(key));
if (!iter.found())
{
@ -139,7 +178,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key)
template<class T, class Key, class Hash>
inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
{
const_iterator iter = this->find(key);
const const_iterator iter(this->cfind(key));
if (!iter.found())
{
@ -156,14 +195,14 @@ inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
template<class T, class Key, class Hash>
inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key)
{
iterator iter = this->find(key);
const iterator iter(this->find(key));
if (iter.found())
{
return iter.object();
}
this->insert(key, T());
this->insert(key, mapped_type());
return find(key).object();
}
@ -175,7 +214,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()
const T& deflt
)
{
iterator iter = this->find(key);
const iterator iter(this->find(key));
if (iter.found())
{
@ -198,412 +237,6 @@ inline const T& Foam::HashTable<T, Key, Hash>::operator()
}
// * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base()
:
entryPtr_(nullptr),
hashTable_(nullptr),
hashIndex_(0)
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
(
const table_type* hashTbl,
const entry_type* elmt,
const label hashIndex
)
:
entryPtr_(const_cast<entry_type*>(elmt)),
hashTable_(const_cast<table_type*>(hashTbl)),
hashIndex_(hashIndex)
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
(
const table_type* hashTbl
)
:
entryPtr_(nullptr),
hashTable_(const_cast<table_type*>(hashTbl)),
hashIndex_(0)
{
if (hashTable_ && hashTable_->nElmts_)
{
// find first non-nullptr table entry
while
(
!(entryPtr_ = hashTable_->table_[hashIndex_])
&& ++hashIndex_ < hashTable_->tableSize_
)
{}
if (hashIndex_ >= hashTable_->tableSize_)
{
// make into an end iterator
entryPtr_ = nullptr;
hashIndex_ = 0;
}
}
}
template<class T, class Key, class Hash>
inline void
Foam::HashTable<T, Key, Hash>::iterator_base::increment()
{
// A negative index is a special value from erase
if (hashIndex_ < 0)
{
// the markPos='-curPos-1', but we wish to continue at 'curPos-1'
// thus use '-(markPos+1) -1'
hashIndex_ = -(hashIndex_+1) - 1;
}
else if (entryPtr_)
{
if (entryPtr_->next_)
{
// Move to next element on the SLList
entryPtr_ = entryPtr_->next_;
return;
}
}
// else
// {
// // if we reach here (entryPtr_ is nullptr) it is already at the end()
// // we should probably stop
// }
// Step to the next table entry
while
(
++hashIndex_ < hashTable_->tableSize_
&& !(entryPtr_ = hashTable_->table_[hashIndex_])
)
{}
if (hashIndex_ >= hashTable_->tableSize_)
{
// make into an end iterator
entryPtr_ = nullptr;
hashIndex_ = 0;
}
}
template<class T, class Key, class Hash>
inline bool
Foam::HashTable<T, Key, Hash>::iterator_base::found() const
{
return entryPtr_;
}
template<class T, class Key, class Hash>
inline const Key& Foam::HashTable<T, Key, Hash>::iterator_base::key() const
{
return entryPtr_->key_;
}
template<class T, class Key, class Hash>
inline T& Foam::HashTable<T, Key, Hash>::iterator_base::element() const
{
return entryPtr_->obj_;
}
template<class T, class Key, class Hash>
inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator==
(
const iterator_base& iter
) const
{
return entryPtr_ == iter.entryPtr_;
}
template<class T, class Key, class Hash>
inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator!=
(
const iterator_base& iter
) const
{
return entryPtr_ != iter.entryPtr_;
}
// * * * * * * * * * * * * * * key iterator base * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::key_iterator_base
(
const WrappedIterator& iter
)
:
WrappedIterator(iter)
{}
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline const Key&
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::operator*() const
{
return this->key();
}
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline const Key&
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::operator()() const
{
return this->key();
}
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>&
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::operator++()
{
this->increment();
return *this;
}
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::operator++(int)
{
key_iterator_base old = *this;
this->increment();
return old;
}
// * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator::iterator()
:
iterator_base()
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator::iterator
(
table_type* hashTbl
)
:
iterator_base(hashTbl)
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator::iterator
(
table_type* hashTbl,
entry_type* elmt,
const label hashIndex
)
:
iterator_base(hashTbl, elmt, hashIndex)
{}
template<class T, class Key, class Hash>
inline T&
Foam::HashTable<T, Key, Hash>::iterator::object() const
{
return this->element();
}
template<class T, class Key, class Hash>
inline T&
Foam::HashTable<T, Key, Hash>::iterator::operator*() const
{
return this->object();
}
template<class T, class Key, class Hash>
inline T&
Foam::HashTable<T, Key, Hash>::iterator::operator()() const
{
return this->object();
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator&
Foam::HashTable<T, Key, Hash>::iterator::operator++()
{
this->increment();
return *this;
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::iterator::operator++(int)
{
iterator old = *this;
this->increment();
return old;
}
// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator()
:
iterator_base()
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
(
const HashTable<T, Key, Hash>::iterator& iter
)
:
iterator_base(iter)
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
(
table_type* hashTbl
)
:
iterator_base(hashTbl)
{}
template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
(
table_type* hashTbl,
entry_type* elmt,
const label hashIndex
)
:
iterator_base(hashTbl, elmt, hashIndex)
{}
template<class T, class Key, class Hash>
inline const T&
Foam::HashTable<T, Key, Hash>::const_iterator::object() const
{
return this->element();
}
template<class T, class Key, class Hash>
inline const T&
Foam::HashTable<T, Key, Hash>::const_iterator::operator*() const
{
return this->object();
}
template<class T, class Key, class Hash>
inline const T&
Foam::HashTable<T, Key, Hash>::const_iterator::operator()() const
{
return this->object();
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::const_iterator::operator++()
{
this->increment();
return *this;
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::const_iterator::operator++(int)
{
const_iterator old = *this;
this->increment();
return old;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::begin()
{
return iterator(this);
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::begin() const
{
return const_iterator(this);
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::cbegin() const
{
return const_iterator(this);
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::iterator&
Foam::HashTable<T, Key, Hash>::end()
{
return iterator_end<iterator>();
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::end() const
{
return iterator_end<const_iterator>();
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::cend() const
{
return iterator_cend<const_iterator>();
}
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>

View File

@ -33,17 +33,17 @@ template<class T, class Key, class Hash>
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
:
HashTableCore(),
nElmts_(0),
tableSize_(HashTableCore::canonicalSize(size)),
size_(0),
capacity_(HashTableCore::canonicalSize(size)),
table_(nullptr)
{
if (tableSize_)
if (capacity_)
{
table_ = new hashedEntry*[tableSize_];
table_ = new node_type*[capacity_];
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
for (label i=0; i < capacity_; ++i)
{
table_[hashIdx] = nullptr;
table_[i] = nullptr;
}
}
@ -60,10 +60,10 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::printInfo(Ostream& os) const
label maxChain = 0;
unsigned avgChain = 0;
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
for (label i=0; i < capacity_; ++i)
{
label count = 0;
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
for (node_type* ep = table_[i]; ep; ep = ep->next_)
{
++count;
}
@ -81,7 +81,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::printInfo(Ostream& os) const
}
os << "HashTable<T,Key,Hash>"
<< " elements:" << size() << " slots:" << used << "/" << tableSize_
<< " elements:" << size() << " slots:" << used << "/" << capacity_
<< " chaining(avg/max):" << (used ? (float(avgChain)/used) : 0)
<< "/" << maxChain << endl;
@ -145,7 +145,7 @@ Foam::Istream& Foam::operator>>
{
is.fatalCheck(FUNCTION_NAME);
// Anull list
// Anull existing table
L.clear();
is.fatalCheck(FUNCTION_NAME);
@ -154,7 +154,7 @@ Foam::Istream& Foam::operator>>
is.fatalCheck
(
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
"operator>>(Istream&, HashTable&) : "
"reading first token"
);
@ -163,11 +163,11 @@ Foam::Istream& Foam::operator>>
const label s = firstToken.labelToken();
// Read beginning of contents
const char delimiter = is.readBeginList("HashTable<T, Key, Hash>");
const char delimiter = is.readBeginList("HashTable");
if (s)
{
if (2*s > L.tableSize_)
if (2*s > L.capacity_)
{
L.resize(2*s);
}
@ -182,7 +182,7 @@ Foam::Istream& Foam::operator>>
is.fatalCheck
(
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
"operator>>(Istream&, HashTable&) : "
"reading entry"
);
}
@ -224,15 +224,11 @@ Foam::Istream& Foam::operator>>
Key key;
is >> key;
T element;
is >> element;
L.insert(key, element);
L.insert(key, pTraits<T>(is));
is.fatalCheck
(
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
"operator>>(Istream&, HashTable&) : "
"reading entry"
);
@ -262,19 +258,26 @@ Foam::Ostream& Foam::operator<<
const HashTable<T, Key, Hash>& tbl
)
{
using const_iterator = typename HashTable<T, Key, Hash>::const_iterator;
const label sz = tbl.size();
// Write size and start delimiter
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
// Write contents
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
if (sz)
{
os << iter.key() << token::SPACE << iter.object() << nl;
}
// Size and start list delimiter
os << nl << sz << nl << token::BEGIN_LIST << nl;
// Write end delimiter
os << token::END_LIST;
// Contents
for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
{
os << iter.key() << token::SPACE << iter.object() << nl;
}
os << token::END_LIST; // End list delimiter
}
else
{
// Empty hash table
os << sz << token::BEGIN_LIST << token::END_LIST;
}
os.check(FUNCTION_NAME);
return os;

View File

@ -0,0 +1,123 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
template<bool Const>
Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
(
table_type* tbl,
const Key& key
)
:
entry_(nullptr),
container_(tbl),
index_(0)
{
if (tbl->size())
{
const label index = container_->hashKeyIndex(key);
for (node_type* ep = container_->table_[index]; ep; ep = ep->next_)
{
if (key == ep->key())
{
entry_ = ep;
index_ = index;
break;
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
//
// Any changes here may need changes in the iterator increment() method
//
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::iterator_erase
(
node_type*& entry,
label& index
)
{
// Safeguard against the following:
// - empty table
// - nullptr entry
// - end iterator (which is also a nullptr)
// - negative index from a previous erase. See comment below.
if (!size_ || !entry || index < 0)
{
return false;
}
// Decrease count
size_--;
// The previous element in the singly linked list
node_type* prev = nullptr;
for (node_type* ep = table_[index]; ep; ep = ep->next_)
{
if (ep == entry)
{
break;
}
prev = ep;
}
if (prev)
{
// Had previous element in linked list - reposition to there
prev->next_ = entry->next_;
delete entry;
entry = prev;
return true;
}
// Was first element on linked list
table_[index] = entry->next_;
delete entry;
// Assign any non-nullptr value so it doesn't look like end()
entry = reinterpret_cast<node_type*>(this);
// Mark the present index to continue and bring it back to the present
// location with the next index.
//
// Save: (-index-1), which has no ambiguity for index 0.
// Retrieve: (-(index+1))
index = (-index - 1);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,263 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
template<bool Const>
inline Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator()
:
entry_(nullptr),
container_(nullptr),
index_(0)
{}
template<class T, class Key, class Hash>
template<bool Const>
inline Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
(
bool, // Future use and to avoid implicit construct
table_type* tbl
)
:
entry_(nullptr),
container_(tbl),
index_(0)
{
if (container_ && container_->size_)
{
// Locate the first non-nullptr table entry
while
(
!(entry_ = container_->table_[index_])
&& ++index_ < container_->capacity_
)
{}
if (index_ >= container_->capacity_)
{
// Nothing found - make it an end iterator
entry_ = nullptr;
index_ = 0;
}
}
}
//
// Any changes here may need changes in iterator_erase() method too
//
template<class T, class Key, class Hash>
template<bool Const>
inline void
Foam::HashTable<T, Key, Hash>::Iterator<Const>::increment()
{
if (index_ < 0)
{
// Negative index is a special value from erase
//
// Saved as (-index-1), retrieved as (-(index-1)) but to with an
// extra (-1) to compensate for the ++ in the following while loop
index_ = -(index_+1) - 1;
}
else if (index_ < container_->capacity_ && entry_ && entry_->next_)
{
// Move to next element on the linked-list
entry_ = entry_->next_;
return;
}
// Move to the next non-nullptr table entry
while
(
++index_ < container_->capacity_
&& !(entry_ = container_->table_[index_])
)
{}
if (index_ >= container_->capacity_)
{
// Nothing found - make it an end iterator
entry_ = nullptr;
index_ = 0;
}
}
template<class T, class Key, class Hash>
template<bool Const>
inline bool
Foam::HashTable<T, Key, Hash>::Iterator<Const>::found() const
{
return entry_;
}
template<class T, class Key, class Hash>
template<bool Const>
inline const Key& Foam::HashTable<T, Key, Hash>::Iterator<Const>::key() const
{
return entry_->key();
}
template<class T, class Key, class Hash>
template<bool Const>
inline bool Foam::HashTable<T, Key, Hash>::Iterator<Const>::operator==
(
const Iterator<true>& iter
) const
{
return entry_ == iter.entry_;
}
template<class T, class Key, class Hash>
template<bool Const>
inline bool Foam::HashTable<T, Key, Hash>::Iterator<Const>::operator!=
(
const Iterator<true>& iter
) const
{
return entry_ != iter.entry_;
}
template<class T, class Key, class Hash>
template<bool Const>
inline bool Foam::HashTable<T, Key, Hash>::Iterator<Const>::operator==
(
const Iterator<false>& iter
) const
{
return entry_ == iter.entry_;
}
template<class T, class Key, class Hash>
template<bool Const>
inline bool Foam::HashTable<T, Key, Hash>::Iterator<Const>::operator!=
(
const Iterator<false>& iter
) const
{
return entry_ != iter.entry_;
}
// * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator&
Foam::HashTable<T, Key, Hash>::iterator::operator++()
{
this->increment();
return *this;
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::iterator::operator++(int)
{
iterator iter(*this);
this->increment();
return iter;
}
// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::const_iterator::operator++()
{
this->increment();
return *this;
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::const_iterator::operator++(int)
{
const_iterator iter(*this);
this->increment();
return iter;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::iterator
Foam::HashTable<T, Key, Hash>::begin()
{
return iterator(Iterator<false>(true, this));
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::begin() const
{
return const_iterator(Iterator<true>(true, this));
}
template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::cbegin() const
{
return const_iterator(Iterator<true>(true, this));
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::iterator&
Foam::HashTable<T, Key, Hash>::end()
{
return iterator_end<iterator>();
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::end() const
{
return iterator_cend<const_iterator>();
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::cend() const
{
return iterator_cend<const_iterator>();
}
// ************************************************************************* //

View File

@ -27,6 +27,11 @@ Class
Description
A HashTable to objects of type \<T\> with a label key.
Note
The Map contents are unordered.
When the key order is important, use the sortedToc() method to obtain
a list of sorted keys and use that for further access.
See also
PtrMap
@ -65,13 +70,19 @@ public:
// Constructors
//- Construct given initial size
Map(const label size = 128)
//- Construct null with default table size
Map()
:
parent_type()
{}
//- Construct with given table size
explicit Map(const label size)
:
parent_type(size)
{}
//- Construct from Istream
//- Construct from Istream with default table size
Map(Istream& is)
:
parent_type(is)
@ -96,7 +107,7 @@ public:
{}
//- Construct by transferring the parameter contents
Map(const Xfer<HashTable<T, label, Hash<label>>>& map)
Map(const Xfer<parent_type>& map)
:
parent_type(map)
{}

View File

@ -62,8 +62,14 @@ public:
// Constructors
//- Construct null with default table size
PtrMap()
:
parent_type()
{}
//- Construct given initial map size
PtrMap(const label size = 128)
explicit PtrMap(const label size)
:
parent_type(size)
{}

View File

@ -1,530 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef StaticHashTable_C
#define StaticHashTable_C
#include "StaticHashTable.H"
#include "List.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable(const label size)
:
StaticHashTableCore(),
keys_(StaticHashTableCore::canonicalSize(size)),
objects_(keys_.size()),
nElmts_(0),
endIter_(*this, keys_.size(), 0),
endConstIter_(*this, keys_.size(), 0)
{
if (size < 1)
{
FatalErrorInFunction
<< "Illegal size " << size << " for StaticHashTable."
<< " Minimum size is 1" << abort(FatalError);
}
}
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
(
const StaticHashTable<T, Key, Hash>& ht
)
:
StaticHashTableCore(),
keys_(ht.keys_),
objects_(ht.objects_),
nElmts_(ht.nElmts_),
endIter_(*this, keys_.size(), 0),
endConstIter_(*this, keys_.size(), 0)
{}
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
(
const Xfer<StaticHashTable<T, Key, Hash>>& ht
)
:
StaticHashTableCore(),
keys_(0),
objects_(0),
nElmts_(0),
endIter_(*this, 0, 0),
endConstIter_(*this, 0, 0)
{
transfer(ht());
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::~StaticHashTable()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
{
if (key == localKeys[elemIdx])
{
return true;
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return false;
}
template<class T, class Key, class Hash>
typename Foam::StaticHashTable<T, Key, Hash>::iterator
Foam::StaticHashTable<T, Key, Hash>::find
(
const Key& key
)
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
{
if (key == localKeys[elemIdx])
{
return iterator(*this, hashIdx, elemIdx);
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return end();
}
template<class T, class Key, class Hash>
typename Foam::StaticHashTable<T, Key, Hash>::const_iterator
Foam::StaticHashTable<T, Key, Hash>::find
(
const Key& key
) const
{
return this->cfind(key);
}
template<class T, class Key, class Hash>
typename Foam::StaticHashTable<T, Key, Hash>::const_iterator
Foam::StaticHashTable<T, Key, Hash>::cfind
(
const Key& key
) const
{
if (nElmts_)
{
const label hashIdx = hashKeyIndex(key);
const List<Key>& localKeys = keys_[hashIdx];
forAll(localKeys, elemIdx)
{
if (key == localKeys[elemIdx])
{
return const_iterator(*this, hashIdx, elemIdx);
}
}
}
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "Entry " << key << " not found in hash table\n";
}
#endif
return cend();
}
template<class T, class Key, class Hash>
Foam::List<Key> Foam::StaticHashTable<T, Key, Hash>::toc() const
{
List<Key> keys(nElmts_);
label keyI = 0;
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{
keys[keyI++] = iter.key();
}
return keys;
}
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::set
(
const Key& key,
const T& obj,
const bool protect
)
{
const label hashIdx = hashKeyIndex(key);
List<Key>& localKeys = keys_[hashIdx];
label existing = localKeys.size();
forAll(localKeys, elemIdx)
{
if (key == localKeys[elemIdx])
{
existing = elemIdx;
break;
}
}
if (existing == localKeys.size())
{
// Not found, append
List<T>& localObjects = objects_[hashIdx];
localKeys.setSize(existing+1);
localObjects.setSize(existing+1);
localKeys[existing] = key;
localObjects[existing] = obj;
nElmts_++;
}
else if (protect)
{
// Found - but protected from overwriting
// this corresponds to the STL 'insert' convention
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction
<< "Cannot insert " << key << " already in hash table\n";
}
#endif
return false;
}
else
{
// Found - overwrite existing entry
// this corresponds to the Perl convention
objects_[hashIdx][existing] = obj;
}
return true;
}
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::erase(const iterator& cit)
{
if (cit != end())
{
List<Key>& localKeys = keys_[cit.hashIndex_];
List<T>& localObjects = objects_[cit.hashIndex_];
// Copy down
for (label i = cit.elemIndex_+1; i < localKeys.size(); i++)
{
localKeys[i-1] = localKeys[i];
localObjects[i-1] = localObjects[i];
}
localKeys.setSize(localKeys.size()-1);
localObjects.setSize(localObjects.size()-1);
// Adjust iterator after erase
iterator& it = const_cast<iterator&>(cit);
it.elemIndex_--;
if (it.elemIndex_ < 0)
{
// No previous element in the local list
// Mark with as special value (see notes in HashTable)
it.hashIndex_ = -it.hashIndex_ - 1;
it.elemIndex_ = 0;
}
nElmts_--;
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "hashedEntry removed.\n";
}
#endif
return true;
}
else
{
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction
<< "Cannot remove hashedEntry from hash table\n";
}
#endif
return false;
}
}
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::erase(const Key& key)
{
iterator it = find(key);
if (it != end())
{
return erase(it);
}
else
{
return false;
}
}
template<class T, class Key, class Hash>
Foam::label Foam::StaticHashTable<T, Key, Hash>::erase
(
const StaticHashTable<T, Key, Hash>& rhs
)
{
label count = 0;
// Remove rhs elements from this table
// NOTE: could optimize depending on which hash is smaller
for (iterator iter = this->begin(); iter != this->end(); ++iter)
{
if (rhs.found(iter.key()) && erase(iter))
{
count++;
}
}
return count;
}
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::resize(const label sz)
{
label newSize = StaticHashTableCore::canonicalSize(sz);
if (newSize == keys_.size())
{
#ifdef FULLDEBUG
if (debug)
{
InfoInFunction << "New table size == old table size\n";
}
#endif
return;
}
if (newSize < 1)
{
FatalErrorInFunction
<< "Illegal size " << newSize << " for StaticHashTable."
<< " Minimum size is 1" << abort(FatalError);
}
StaticHashTable<T, Key, Hash> newTable(newSize);
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{
newTable.insert(iter.key(), *iter);
}
transfer(newTable);
// Adapt end() iterators
endIter_.hashIndex_ = keys_.size();
endConstIter_.hashIndex_ = keys_.size();
}
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::clear()
{
forAll(keys_, hashIdx)
{
keys_[hashIdx].clear();
objects_[hashIdx].clear();
}
nElmts_ = 0;
}
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::clearStorage()
{
clear();
resize(1);
}
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::transfer
(
StaticHashTable<T, Key, Hash>& ht
)
{
// Remove existing elements
clear();
// Copy data from ht
keys_.transfer(ht.keys_);
objects_.transfer(ht.objects_);
nElmts_ = ht.nElmts_;
ht.nElmts_ = 0;
// Adapt end() iterators
endIter_.hashIndex_ = keys_.size();
endConstIter_.hashIndex_ = keys_.size();
ht.endIter_.hashIndex_ = 0;
ht.endConstIter_.hashIndex_ = 0;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
void Foam::StaticHashTable<T, Key, Hash>::operator=
(
const StaticHashTable<T, Key, Hash>& rhs
)
{
// Check for assignment to self
if (this == &rhs)
{
FatalErrorInFunction
<< "attempted assignment to self"
<< abort(FatalError);
}
// keys could be empty from a previous transfer()
if (keys_.empty())
{
keys_.setSize(rhs.keys_.size());
objects_.setSize(keys_.size());
// Adapt end() iterators
endIter_.hashIndex_ = keys_.size();
endConstIter_.hashIndex_ = keys_.size();
}
else
{
clear();
// keys_.size() does not change so neither does end() iterator.
}
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{
insert(iter.key(), *iter);
}
}
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::operator==
(
const StaticHashTable<T, Key, Hash>& rhs
) const
{
// Sizes (number of keys) must match
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{
const_iterator fnd = find(iter.key());
if (fnd == cend() || fnd() != iter())
{
return false;
}
}
return true;
}
template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::operator!=
(
const StaticHashTable<T, Key, Hash>& rhs
) const
{
return !(operator==(rhs));
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
#include "StaticHashTableIO.C"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,415 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::StaticHashTable
Description
STL conforming hash table.
Note
Uses straight lists as underlying type.
Is slower to insert than the standard HashTable, but should be more
memory efficient and faster to access.
SourceFiles
StaticHashTableI.H
StaticHashTable.C
StaticHashTableIO.C
\*---------------------------------------------------------------------------*/
#ifndef StaticHashTable_H
#define StaticHashTable_H
#include "label.H"
#include "uLabel.H"
#include "word.H"
#include "Xfer.H"
#include "className.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class T> class List;
template<class T, class Key, class Hash> class StaticHashTable;
template<class T, class Key, class Hash> Istream& operator>>
(
Istream&,
StaticHashTable<T, Key, Hash>&
);
template<class T, class Key, class Hash> Ostream& operator<<
(
Ostream&,
const StaticHashTable<T, Key, Hash>&
);
/*---------------------------------------------------------------------------*\
Class StaticHashTableCore Declaration
\*---------------------------------------------------------------------------*/
//- Template-invariant bits for StaticHashTable
struct StaticHashTableCore
{
//- Return a canonical (power-of-two) of the requested size.
static label canonicalSize(const label requested_size);
//- Construct null
StaticHashTableCore()
{}
//- Define template name and debug
ClassName("StaticHashTable");
//- A zero-sized end iterator
struct iteratorEnd
{
//- Construct null
iteratorEnd()
{}
};
};
/*---------------------------------------------------------------------------*\
Class StaticHashTable Declaration
\*---------------------------------------------------------------------------*/
template<class T, class Key=word, class Hash=string::hash>
class StaticHashTable
:
public StaticHashTableCore
{
// Private data type for table entries
//- The lookup keys, ordered per hash value
List<List<Key>> keys_;
//- For each key the corresponding object.
List<List<T>> objects_;
//- The current number of elements in table
label nElmts_;
//- Return the hash index of the Key within the current table size.
// No checks for zero-sized tables.
inline label hashKeyIndex(const Key& key) const;
//- Assign a new hashed entry to a possibly already existing key
bool set(const Key& key, const T& obj, bool protect);
public:
// Forward declaration of STL iterators
template<class TRef, class TableRef>
class Iterator;
typedef Iterator
<
T&,
StaticHashTable<T, Key, Hash>&
> iterator;
typedef Iterator
<
const T&,
const StaticHashTable<T, Key, Hash>&
> const_iterator;
// Declare friendship with the iterators
friend class Iterator
<
T&,
StaticHashTable<T, Key, Hash>&
>;
friend class Iterator
<
const T&,
const StaticHashTable<T, Key, Hash>&
>;
// Constructors
//- Construct given initial table size
StaticHashTable(const label size = 128);
//- Construct from Istream
StaticHashTable(Istream&, const label size = 128);
//- Construct as copy
StaticHashTable(const StaticHashTable<T, Key, Hash>&);
//- Construct by transferring the parameter contents
StaticHashTable(const Xfer<StaticHashTable<T, Key, Hash>>&);
//- Destructor
~StaticHashTable();
// Member Functions
// Access
//- Return number of elements in table.
inline label size() const;
//- Return true if the hash table is empty
inline bool empty() const;
//- Return true if hashed entry is found in table
bool found(const Key& key) const;
//- Find and return an iterator set at the hashed entry
// If not found iterator = end()
iterator find(const Key& key);
//- Find and return an const_iterator set at the hashed entry
// If not found iterator = end()
const_iterator find(const Key& key) const;
//- Find and return an const_iterator set at the hashed entry
// If not found iterator = end()
const_iterator cfind(const Key& key) const;
//- Return the table of contents
List<Key> toc() const;
//- Print information
Ostream& printInfo(Ostream&) const;
// Edit
//- Insert a new hashed entry
bool insert(const Key& key, const T& newElmt);
//- Assign a new hashed entry, overwriting existing entries
inline bool set(const Key&, const T& newElmt);
//- Erase an hashed entry specified by given iterator
bool erase(const iterator& it);
//- Erase an hashed entry specified by given key if in table
bool erase(const Key& key);
//- Resize the hash table for efficiency
void resize(const label newSize);
//- Remove entries in the given hash table from this hash table
// Return the number of elements removed
label erase(const StaticHashTable<T, Key, Hash>&);
//- Clear all entries from table
void clear();
//- Clear the table entries and the table itself.
// Equivalent to clear() followed by resize(1)
void clearStorage();
//- Transfer the contents of the argument table into this table
// and annul the argument table.
void transfer(StaticHashTable<T, Key, Hash>&);
//- Transfer contents to the Xfer container
inline Xfer<StaticHashTable<T, Key, Hash>> xfer();
// Member Operators
//- Find and return an hashed entry
inline T& operator[](const Key&);
//- Find and return an hashed entry
inline const T& operator[](const Key&) const;
//- Find and return an hashed entry, create it null if not present.
inline T& operator()(const Key&);
//- Assignment
void operator=(const StaticHashTable<T, Key, Hash>&);
//- Equality. Two hash tables are equal if all contents of first are
// also in second and vice versa.
bool operator==(const StaticHashTable<T, Key, Hash>&) const;
//- The opposite of the equality operation.
bool operator!=(const StaticHashTable<T, Key, Hash>&) const;
// STL type definitions
//- Type of values the StaticHashTable contains.
typedef T value_type;
//- Type that can be used for storing into StaticHashTable::value_type
// objects. This type is usually List::value_type&.
typedef T& reference;
//- Type that can be used for storing into constant
// StaticHashTable::value_type objects. This type is usually const
// StaticHashTable::value_type&.
typedef const T& const_reference;
//- The type that can represent the size of a StaticHashTable.
typedef label size_type;
// STL iterator
//- An STL iterator
template<class TRef, class TableRef>
class Iterator
{
friend class StaticHashTable;
template<class TRef2, class TableRef2>
friend class Iterator;
// Private data
//- Reference to the StaticHashTable this is an iterator for
TableRef hashTable_;
//- Current hash index
label hashIndex_;
//- Index of current element at hashIndex
label elemIndex_;
public:
// Constructors
//- Construct from hash table, hash index and element index
inline Iterator
(
TableRef,
label hashIndex_,
label elemIndex_
);
//- Construct from the non-const iterator
inline Iterator(const iterator&);
// Member operators
inline void operator=(const iterator&);
inline bool operator==(const iterator&) const;
inline bool operator==(const const_iterator&) const;
inline bool operator!=(const iterator&) const;
inline bool operator!=(const const_iterator&) const;
inline TRef operator*();
inline TRef operator()();
inline Iterator& operator++();
inline Iterator operator++(int);
inline const Key& key() const;
};
//- Iterator set to the beginning of the StaticHashTable
inline iterator begin();
//- Iterator set to beyond the end of the StaticHashTable
inline const iterator& end();
//- const_iterator set to the beginning of the StaticHashTable
inline const_iterator cbegin() const;
//- const_iterator set to beyond the end of the StaticHashTable
inline const const_iterator& cend() const;
//- const_iterator set to the beginning of the StaticHashTable
inline const_iterator begin() const;
//- const_iterator set to beyond the end of the StaticHashTable
inline const const_iterator& end() const;
// IOstream Operator
friend Istream& operator>> <T, Key, Hash>
(
Istream&,
StaticHashTable<T, Key, Hash>&
);
friend Ostream& operator<< <T, Key, Hash>
(
Ostream&,
const StaticHashTable<T, Key, Hash>&
);
private:
//- Iterator returned by end()
iterator endIter_;
//- const_iterator returned by end()
const_iterator endConstIter_;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "StaticHashTableI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifndef NoStaticHashTableC
#ifdef NoRepository
#include "StaticHashTable.C"
#endif
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,86 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "StaticHashTable.H"
#include "uLabel.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(StaticHashTableCore, 0);
}
// Approximately labelMax/4
static const Foam::label maxTableSize(1L << (sizeof(Foam::label)*8-3));
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::label Foam::StaticHashTableCore::canonicalSize(const label requested_size)
{
if (requested_size < 1)
{
return 0;
}
else if (requested_size >= maxTableSize)
{
return maxTableSize;
}
// Enforce power of two - makes for a very fast modulus.
// Use unsigned for these calculations.
//
// - The lower limit (8) is somewhat arbitrary, but if the hash table
// is too small, there will be many direct table collisions.
// - The upper limit (approx. labelMax/4) must be a power of two,
// need not be extremely large for hashing.
uLabel powerOfTwo = 8u; // lower-limit
const uLabel size = requested_size;
if (size <= powerOfTwo)
{
return powerOfTwo;
}
else if (size & (size-1)) // <- Modulus of i^2
{
// Determine power-of-two. Brute-force is fast enough.
while (powerOfTwo < size)
{
powerOfTwo <<= 1;
}
return powerOfTwo;
}
else
{
return size;
}
}
// ************************************************************************* //

View File

@ -1,399 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "error.H"
#include "IOstreams.H"
// * * * * * * * * * * * * 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>
inline Foam::label Foam::StaticHashTable<T, Key, Hash>::size() const
{
return nElmts_;
}
template<class T, class Key, class Hash>
inline bool Foam::StaticHashTable<T, Key, Hash>::empty() const
{
return !nElmts_;
}
template<class T, class Key, class Hash>
inline bool Foam::StaticHashTable<T, Key, Hash>::insert
(
const Key& key,
const T& obj
)
{
return set(key, obj, true);
}
template<class T, class Key, class Hash>
inline bool Foam::StaticHashTable<T, Key, Hash>::set
(
const Key& key,
const T& obj
)
{
return set(key, obj, false);
}
template<class T, class Key, class Hash>
inline Foam::Xfer<Foam::StaticHashTable<T, Key, Hash>>
Foam::StaticHashTable<T, Key, Hash>::xfer()
{
return xferMove(*this);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline T& Foam::StaticHashTable<T, Key, Hash>::operator[](const Key& key)
{
iterator iter = find(key);
if (iter == end())
{
FatalErrorInFunction
<< toc()
<< exit(FatalError);
}
return *iter;
}
template<class T, class Key, class Hash>
inline const T& Foam::StaticHashTable<T, Key, Hash>::operator[]
(
const Key& key
) const
{
const_iterator iter = find(key);
if (iter == cend())
{
FatalErrorInFunction
<< toc()
<< exit(FatalError);
}
return *iter;
}
template<class T, class Key, class Hash>
inline T& Foam::StaticHashTable<T, Key, Hash>::operator()(const Key& key)
{
iterator iter = find(key);
if (iter == end())
{
insert(key, T());
return *find(key);
}
else
{
return *iter;
}
}
// * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::Iterator
(
TableRef hashTbl,
label hashIndex,
label elemIndex
)
:
hashTable_(hashTbl),
hashIndex_(hashIndex),
elemIndex_(elemIndex)
{}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::Iterator
(
const iterator& iter
)
:
hashTable_(iter.hashTable_),
hashIndex_(iter.hashIndex_),
elemIndex_(iter.elemIndex_)
{}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline void
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator=
(
const iterator& iter
)
{
this->hashIndex_ = iter.hashIndex_;
this->elemIndex_ = iter.elemIndex_;
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline bool
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator==
(
const iterator& iter
) const
{
return hashIndex_ == iter.hashIndex_ && elemIndex_ == iter.elemIndex_;
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline bool
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator==
(
const const_iterator& iter
) const
{
return hashIndex_ == iter.hashIndex_ && elemIndex_ == iter.elemIndex_;
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline bool
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator!=
(
const iterator& iter
) const
{
return !operator==(iter);
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline bool
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator!=
(
const const_iterator& iter
) const
{
return !operator==(iter);
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline TRef
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator*()
{
return hashTable_.objects_[hashIndex_][elemIndex_];
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline TRef
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::operator()()
{
return operator*();
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline
typename Foam::StaticHashTable<T, Key, Hash>::template Iterator
<
TRef,
TableRef
>&
Foam::StaticHashTable<T, Key, Hash>::Iterator
<
TRef,
TableRef
>::operator++()
{
// A negative index is a special value from erase
// (see notes in HashTable)
if (hashIndex_ < 0)
{
hashIndex_ = -(hashIndex_+1) - 1;
}
else
{
// Try the next element on the local list
elemIndex_++;
if (elemIndex_ < hashTable_.objects_[hashIndex_].size())
{
return *this;
}
}
// Step to the next table entry
elemIndex_ = 0;
while
(
++hashIndex_ < hashTable_.objects_.size()
&& !hashTable_.objects_[hashIndex_].size()
)
{}
if (hashIndex_ >= hashTable_.objects_.size())
{
// make end iterator
hashIndex_ = hashTable_.keys_.size();
}
return *this;
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline
typename Foam::StaticHashTable<T, Key, Hash>::template Iterator
<
TRef,
TableRef
>
Foam::StaticHashTable<T, Key, Hash>::Iterator
<
TRef,
TableRef
>::operator++
(
int
)
{
iterator tmp = *this;
++*this;
return tmp;
}
template<class T, class Key, class Hash>
template<class TRef, class TableRef>
inline const Key&
Foam::StaticHashTable<T, Key, Hash>::Iterator<TRef, TableRef>::key() const
{
return hashTable_.keys_[hashIndex_][elemIndex_];
}
template<class T, class Key, class Hash>
inline typename Foam::StaticHashTable<T, Key, Hash>::iterator
Foam::StaticHashTable<T, Key, Hash>::begin()
{
// Find first non-empty entry
forAll(keys_, hashIdx)
{
if (keys_[hashIdx].size())
{
return iterator(*this, hashIdx, 0);
}
}
return StaticHashTable<T, Key, Hash>::endIter_;
}
template<class T, class Key, class Hash>
inline const typename Foam::StaticHashTable<T, Key, Hash>::iterator&
Foam::StaticHashTable<T, Key, Hash>::end()
{
return StaticHashTable<T, Key, Hash>::endIter_;
}
template<class T, class Key, class Hash>
inline typename Foam::StaticHashTable<T, Key, Hash>::const_iterator
Foam::StaticHashTable<T, Key, Hash>::cbegin() const
{
// Find first non-empty entry
forAll(keys_, hashIdx)
{
if (keys_[hashIdx].size())
{
return const_iterator(*this, hashIdx, 0);
}
}
return StaticHashTable<T, Key, Hash>::endConstIter_;
}
template<class T, class Key, class Hash>
inline const typename Foam::StaticHashTable<T, Key, Hash>::const_iterator&
Foam::StaticHashTable<T, Key, Hash>::cend() const
{
return StaticHashTable<T, Key, Hash>::endConstIter_;
}
template<class T, class Key, class Hash>
inline typename Foam::StaticHashTable<T, Key, Hash>::const_iterator
Foam::StaticHashTable<T, Key, Hash>::begin() const
{
return this->cbegin();
}
template<class T, class Key, class Hash>
inline const typename Foam::StaticHashTable<T, Key, Hash>::const_iterator&
Foam::StaticHashTable<T, Key, Hash>::end() const
{
return StaticHashTable<T, Key, Hash>::endConstIter_;
}
// ************************************************************************* //

View File

@ -1,237 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "StaticHashTable.H"
#include "Istream.H"
#include "Ostream.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::StaticHashTable<T, Key, Hash>::StaticHashTable
(
Istream& is,
const label size
)
:
StaticHashTableCore(),
keys_(StaticHashTableCore::canonicalSize(size)),
objects_(StaticHashTableCore::canonicalSize(size)),
nElmts_(0),
endIter_(*this, keys_.size(), 0),
endConstIter_(*this, keys_.size(), 0)
{
if (size < 1)
{
FatalErrorInFunction
<< "Illegal size " << size << " for StaticHashTable."
<< " Minimum size is 1" << abort(FatalError);
}
operator>>(is, *this);
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::Ostream&
Foam::StaticHashTable<T, Key, Hash>::printInfo(Ostream& os) const
{
label used = 0;
label maxChain = 0;
unsigned avgChain = 0;
// Find first non-empty entry
forAll(keys_, hashIdx)
{
const label count = keys_[hashIdx].size();
if (count)
{
++used;
avgChain += count;
if (maxChain < count)
{
maxChain = count;
}
}
}
os << "StaticHashTable<T,Key,Hash>"
<< " elements:" << size() << " slots:" << used << "/" << keys_.size()
<< " chaining(avg/max):" << (used ? float(avgChain/used) : 0)
<< "/" << maxChain << endl;
return os;
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::Istream& Foam::operator>>(Istream& is, StaticHashTable<T, Key, Hash>& L)
{
is.fatalCheck(FUNCTION_NAME);
// Anull list
L.clear();
is.fatalCheck(FUNCTION_NAME);
token firstToken(is);
is.fatalCheck
(
"operator>>(Istream&, StaticHashTable<T, Key, Hash>&) : "
"reading first token"
);
if (firstToken.isLabel())
{
label s = firstToken.labelToken();
// Read beginning of contents
char delimiter = is.readBeginList("StaticHashTable<T, Key, Hash>");
if (s)
{
if (2*s > L.keys_.size())
{
L.resize(2*s);
}
if (delimiter == token::BEGIN_LIST)
{
for (label i=0; i<s; i++)
{
Key key;
is >> key;
L.insert(key, pTraits<T>(is));
is.fatalCheck
(
"operator>>(Istream&, StaticHashTable<T, Key, Hash>&)"
" : reading entry"
);
}
}
else
{
FatalIOErrorInFunction
(
is
) << "incorrect first token, '(', found " << firstToken.info()
<< exit(FatalIOError);
}
}
// Read end of contents
is.readEndList("StaticHashTable");
}
else if (firstToken.isPunctuation())
{
if (firstToken.pToken() != token::BEGIN_LIST)
{
FatalIOErrorInFunction
(
is
) << "incorrect first token, '(', found " << firstToken.info()
<< exit(FatalIOError);
}
token lastToken(is);
while
(
!(
lastToken.isPunctuation()
&& lastToken.pToken() == token::END_LIST
)
)
{
is.putBack(lastToken);
Key key;
is >> key;
T element;
is >> element;
L.insert(key, element);
is.fatalCheck
(
"operator>>(Istream&, StaticHashTable<T, Key, Hash>&) : "
"reading entry"
);
is >> lastToken;
}
}
else
{
FatalIOErrorInFunction
(
is
) << "incorrect first token, expected <int> or '(', found "
<< firstToken.info()
<< exit(FatalIOError);
}
is.fatalCheck(FUNCTION_NAME);
return is;
}
template<class T, class Key, class Hash>
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const StaticHashTable<T, Key, Hash>& L)
{
// Write size and start delimiter
os << nl << L.size() << nl << token::BEGIN_LIST << nl;
// Write contents
for
(
typename StaticHashTable<T, Key, Hash>::const_iterator iter = L.begin();
iter != L.end();
++iter
)
{
os << iter.key() << token::SPACE << iter() << nl;
}
// Write end delimiter
os << token::END_LIST;
os.check(FUNCTION_NAME);
return os;
}
// ************************************************************************* //

View File

@ -1,97 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::nil
Description
A zero-sized class without any storage. Used, for example, in HashSet.
Note
A zero-sized class actually does still require at least 1 byte storage.
\*---------------------------------------------------------------------------*/
#ifndef nil_H
#define nil_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class Istream;
class Ostream;
// Forward declaration of friend functions and operators
class nil;
Istream& operator>>(Istream&, nil&);
Ostream& operator<<(Ostream&, const nil&);
/*---------------------------------------------------------------------------*\
Class nil Declaration
\*---------------------------------------------------------------------------*/
class nil
{
public:
// Constructors
//- Construct null
nil()
{}
//- Construct from Istream
nil(Istream&)
{}
// IOstream Operators
friend Istream& operator>>(Istream& is, nil&)
{
return is;
}
friend Ostream& operator<<(Ostream& os, const nil&)
{
return os;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -22,12 +22,13 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::nullObject
Foam::NullObject
Description
Singleton null-object class and instance.
It occupies enough space to reinterpret its content as a class with
a null pointer for its content.
Its contents occupy just enough space to also be reinterpreted
as another class with a null pointer or zero long for its first
member.
SourceFiles
nullObjectI.H
@ -43,8 +44,14 @@ SourceFiles
namespace Foam
{
// Forward declarations
class Istream;
class Ostream;
class NullObject;
/*---------------------------------------------------------------------------*\
Class nullObject Declaration
Class NullObject Declaration
\*---------------------------------------------------------------------------*/
class NullObject
@ -55,12 +62,12 @@ class NullObject
{
void* ptr;
unsigned long val;
} null;
} content;
//- Private constructor
//- Private constructor for singleton only
NullObject()
:
null{nullptr}
content{nullptr}
{}
//- Disallow default bitwise copy construct
@ -70,23 +77,44 @@ class NullObject
void operator=(const NullObject&) = delete;
public:
//- The unique null object
static const NullObject nullObject;
//- A nullptr pointer content
inline const void* pointer() const
{
return null.ptr;
}
// Static Data
//- A zero value content
inline unsigned long value() const
{
return null.val;
}
//- A unique null object
static const NullObject nullObject;
// Member Functions
//- A nullptr pointer content
inline const void* pointer() const
{
return content.ptr;
}
//- Zero valued integer content
inline unsigned long value() const
{
return content.val;
}
};
// IOstream Operators
//- Read from Istream consumes no content.
inline Istream& operator>>(Istream& is, NullObject&)
{
return is;
}
//- Write to Ostream emits no content.
inline Ostream& operator<<(Ostream& os, const NullObject&)
{
return os;
}
//- Pointer to the unique nullObject
extern const NullObject* nullObjectPtr;

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,9 +25,8 @@ Class
Foam::one
Description
A class representing the concept of 1 (scalar(1.0)) used to avoid
unnecessary manipulations for objects which are known to be one at
compile-time.
A class representing the concept of 1 (or 1.0) used to avoid unnecessary
manipulations for objects that are known to be one at compile-time.
SourceFiles
oneI.H
@ -44,6 +43,11 @@ SourceFiles
namespace Foam
{
// Forward declaration of classes, friend functions and operators
class Istream;
class Ostream;
class one;
/*---------------------------------------------------------------------------*\
Class one Declaration
\*---------------------------------------------------------------------------*/
@ -51,15 +55,22 @@ namespace Foam
class one
{
public:
typedef one value_type;
// Forward declaration
class null;
// Constructors
//- Construct null
//- Null constructible
one()
{}
//- Construct null from Istream. Consumes no content.
explicit one(Istream&)
{}
// Member operators
@ -83,6 +94,43 @@ public:
};
/*---------------------------------------------------------------------------*\
Class one::null Declaration
\*---------------------------------------------------------------------------*/
//- A one class with a null output adapter.
class one::null
:
public one
{
public:
typedef null value_type;
//- Null constructible
null()
{}
//- Construct null from Istream without consuming any content.
explicit null(Istream&)
{}
};
// IOstream Operators
//- Read from Istream consumes no content.
inline Istream& operator>>(Istream& is, one&)
{
return is;
}
//- Write to Ostream emits no content.
inline Ostream& operator<<(Ostream& os, const one::null&)
{
return os;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -39,13 +39,11 @@ Description
namespace Foam
{
typedef wordRes wordReListMatcher;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
#endif
// ************************************************************************* //

View File

@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------*\
Compatibility include
Typedef
Foam::nil
Description
The older name for Foam::zero::null.
\*---------------------------------------------------------------------------*/
#ifndef nil_H
#define nil_H
#include "zero.H"
namespace Foam
{
typedef zero::null nil;
}
#endif
// ************************************************************************* //

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -43,6 +43,12 @@ SourceFiles
namespace Foam
{
// Forward declarations
class Istream;
class Ostream;
class zero;
/*---------------------------------------------------------------------------*\
Class zero Declaration
\*---------------------------------------------------------------------------*/
@ -50,15 +56,22 @@ namespace Foam
class zero
{
public:
typedef zero value_type;
// Forward declaration
class null;
// Constructors
//- Construct null
//- Null constructible
zero()
{}
//- Construct null from Istream. Consumes no content.
explicit zero(Istream&)
{}
// Member operators
@ -85,9 +98,47 @@ public:
{
return 0;
}
};
/*---------------------------------------------------------------------------*\
Class zero::null Declaration
\*---------------------------------------------------------------------------*/
//- A zero class with a null output adapter.
class zero::null
:
public zero
{
public:
typedef null value_type;
//- Null constructible
null()
{}
//- Construct null from Istream without consuming any content.
explicit null(Istream&)
{}
};
// IOstream Operators
//- Read from Istream consumes no content.
inline Istream& operator>>(Istream& is, zero&)
{
return is;
}
//- Write to Ostream emits no content.
inline Ostream& operator<<(Ostream& os, const zero::null&)
{
return os;
}
// Global zero
static const zero Zero;