mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improvements to HashTable internals
- make single-parameter construct (label) explicit - consolidate iterators - slightly reduced overhead for some HashSet types - improved resizing behaviour - compact output for empty Ptr hashes
This commit is contained in:
@ -1,3 +0,0 @@
|
|||||||
Test-hashTable.C
|
|
||||||
|
|
||||||
EXE = $(FOAM_USER_APPBIN)/Test-hashTable
|
|
||||||
3
applications/test/HashTable1/Make/files
Normal file
3
applications/test/HashTable1/Make/files
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Test-HashTable1.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/Test-HashTable1
|
||||||
3
applications/test/HashTable4/Make/files
Normal file
3
applications/test/HashTable4/Make/files
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Test-HashTable4.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/Test-HashTable4
|
||||||
2
applications/test/HashTable4/Make/options
Normal file
2
applications/test/HashTable4/Make/options
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
|
||||||
|
/* EXE_LIBS = -lfiniteVolume */
|
||||||
312
applications/test/HashTable4/Test-HashTable4.C
Normal file
312
applications/test/HashTable4/Test-HashTable4.C
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -28,6 +28,13 @@ License
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class T, class Key, class Hash>
|
||||||
|
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable()
|
||||||
|
:
|
||||||
|
parent_type()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable(const label size)
|
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable(const label size)
|
||||||
:
|
:
|
||||||
@ -157,6 +164,7 @@ void Foam::HashPtrTable<T, Key, Hash>::operator=
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
|
||||||
|
|
||||||
#include "HashPtrTableIO.C"
|
#include "HashPtrTableIO.C"
|
||||||
|
|||||||
@ -91,8 +91,11 @@ public:
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct null with default table size
|
||||||
|
HashPtrTable();
|
||||||
|
|
||||||
//- Construct given initial table size
|
//- Construct given initial table size
|
||||||
HashPtrTable(const label size = 128);
|
explicit HashPtrTable(const label size);
|
||||||
|
|
||||||
//- Construct from Istream using given Istream constructor class
|
//- Construct from Istream using given Istream constructor class
|
||||||
template<class INew>
|
template<class INew>
|
||||||
@ -102,7 +105,7 @@ public:
|
|||||||
HashPtrTable(Istream& is);
|
HashPtrTable(Istream& is);
|
||||||
|
|
||||||
//- Construct from dictionary with default dictionary constructor class
|
//- Construct from dictionary with default dictionary constructor class
|
||||||
HashPtrTable(const dictionary& dict);
|
explicit HashPtrTable(const dictionary& dict);
|
||||||
|
|
||||||
//- Construct as copy
|
//- Construct as copy
|
||||||
HashPtrTable(const this_type& ht);
|
HashPtrTable(const this_type& ht);
|
||||||
@ -127,7 +130,7 @@ public:
|
|||||||
//- Erase an entry specified by the given key
|
//- Erase an entry specified by the given key
|
||||||
bool erase(const Key& key);
|
bool erase(const Key& key);
|
||||||
|
|
||||||
//- Clear all entries from table
|
//- Clear all entries from table and deleting any allocated pointers
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
//- Write
|
//- Write
|
||||||
|
|||||||
@ -41,7 +41,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
|||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
|
"HashPtrTable::read(Istream&, const INew&) : "
|
||||||
"reading first token"
|
"reading first token"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
|||||||
const label s = firstToken.labelToken();
|
const label s = firstToken.labelToken();
|
||||||
|
|
||||||
// Read beginning of contents
|
// Read beginning of contents
|
||||||
const char delimiter = is.readBeginList("HashPtrTable<T, Key, Hash>");
|
const char delimiter = is.readBeginList("HashPtrTable");
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
@ -69,8 +69,8 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
|||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"HashPtrTable<T, Key, Hash>::"
|
"HashPtrTable::read(Istream&, const INew&) : "
|
||||||
"read(Istream&, const INew&) : reading entry"
|
"reading entry"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
|||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
|
"HashPtrTable::read(Istream&, const INew&) : "
|
||||||
"reading entry"
|
"reading entry"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read
|
|||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
void Foam::HashPtrTable<T, Key, Hash>::write(Ostream& os) const
|
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();
|
const T* ptr = iter.object();
|
||||||
if (ptr)
|
if (ptr)
|
||||||
@ -209,29 +209,34 @@ Foam::Ostream& Foam::operator<<
|
|||||||
const HashPtrTable<T, Key, Hash>& tbl
|
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
|
if (sz)
|
||||||
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
|
|
||||||
|
|
||||||
// Write contents
|
|
||||||
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
|
||||||
{
|
{
|
||||||
const T* ptr = iter.object();
|
// Size and start list delimiter
|
||||||
|
os << nl << sz << nl << token::BEGIN_LIST << nl;
|
||||||
|
|
||||||
os << iter.key();
|
// Contents
|
||||||
if (ptr)
|
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);
|
os.check(FUNCTION_NAME);
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -79,7 +79,7 @@ inline Foam::label Foam::HashSet<Key, Hash>::assignMultiple
|
|||||||
template<class Key, class Hash>
|
template<class Key, class Hash>
|
||||||
Foam::HashSet<Key, Hash>::HashSet(const UList<Key>& lst)
|
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)
|
for (const auto& k : lst)
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ template<class Key, class Hash>
|
|||||||
template<unsigned Size>
|
template<unsigned Size>
|
||||||
Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
|
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)
|
for (const auto& k : lst)
|
||||||
{
|
{
|
||||||
@ -104,7 +104,7 @@ Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
|
|||||||
template<class Key, class Hash>
|
template<class Key, class Hash>
|
||||||
Foam::HashSet<Key, Hash>::HashSet(std::initializer_list<Key> lst)
|
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)
|
for (const auto& k : lst)
|
||||||
{
|
{
|
||||||
@ -120,7 +120,7 @@ Foam::HashSet<Key, Hash>::HashSet
|
|||||||
const HashTable<AnyType, Key, AnyHash>& tbl
|
const HashTable<AnyType, Key, AnyHash>& tbl
|
||||||
)
|
)
|
||||||
:
|
:
|
||||||
HashTable<nil, Key, Hash>(tbl.capacity())
|
parent_type(tbl.capacity())
|
||||||
{
|
{
|
||||||
using other_iter =
|
using other_iter =
|
||||||
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
|
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
|
||||||
@ -349,7 +349,7 @@ template<class Key, class Hash>
|
|||||||
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
||||||
Foam::HashSet<Key, Hash>::begin() const
|
Foam::HashSet<Key, Hash>::begin() const
|
||||||
{
|
{
|
||||||
return HashTableCore::iterator_begin<const_iterator>
|
return HashTableCore::iterator_cbegin<const_iterator>
|
||||||
(
|
(
|
||||||
static_cast<const parent_type&>(*this)
|
static_cast<const parent_type&>(*this)
|
||||||
);
|
);
|
||||||
@ -360,7 +360,7 @@ template<class Key, class Hash>
|
|||||||
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
||||||
Foam::HashSet<Key, Hash>::cbegin() const
|
Foam::HashSet<Key, Hash>::cbegin() const
|
||||||
{
|
{
|
||||||
return HashTableCore::iterator_begin<const_iterator>
|
return HashTableCore::iterator_cbegin<const_iterator>
|
||||||
(
|
(
|
||||||
static_cast<const parent_type&>(*this)
|
static_cast<const parent_type&>(*this)
|
||||||
);
|
);
|
||||||
@ -379,7 +379,7 @@ template<class Key, class Hash>
|
|||||||
inline const typename Foam::HashSet<Key, Hash>::const_iterator&
|
inline const typename Foam::HashSet<Key, Hash>::const_iterator&
|
||||||
Foam::HashSet<Key, Hash>::end() const
|
Foam::HashSet<Key, Hash>::end() const
|
||||||
{
|
{
|
||||||
return HashTableCore::iterator_end<const_iterator>();
|
return HashTableCore::iterator_cend<const_iterator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,24 @@ Class
|
|||||||
Foam::HashSet
|
Foam::HashSet
|
||||||
|
|
||||||
Description
|
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
|
Typedef
|
||||||
Foam::wordHashSet
|
Foam::wordHashSet
|
||||||
@ -45,7 +62,6 @@ Description
|
|||||||
#define HashSet_H
|
#define HashSet_H
|
||||||
|
|
||||||
#include "HashTable.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>
|
template<class Key=word, class Hash=string::hash>
|
||||||
class HashSet
|
class HashSet
|
||||||
:
|
:
|
||||||
public HashTable<nil, Key, Hash>
|
public HashTable<zero::null, Key, Hash>
|
||||||
{
|
{
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
@ -94,7 +110,7 @@ public:
|
|||||||
typedef HashSet<Key, Hash> this_type;
|
typedef HashSet<Key, Hash> this_type;
|
||||||
|
|
||||||
//- The template instance used for the parent HashTable
|
//- 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
|
//- An iterator, returning reference to the key
|
||||||
using iterator = typename parent_type::key_iterator;
|
using iterator = typename parent_type::key_iterator;
|
||||||
@ -105,13 +121,19 @@ public:
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct null with default (128) table size
|
||||||
|
HashSet()
|
||||||
|
:
|
||||||
|
parent_type()
|
||||||
|
{}
|
||||||
|
|
||||||
//- Construct given initial size
|
//- Construct given initial size
|
||||||
HashSet(const label size = 128)
|
explicit HashSet(const label size)
|
||||||
:
|
:
|
||||||
parent_type(size)
|
parent_type(size)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//- Construct from Istream
|
//- Construct from Istream with default table size
|
||||||
HashSet(Istream& is)
|
HashSet(Istream& is)
|
||||||
:
|
:
|
||||||
parent_type(is)
|
parent_type(is)
|
||||||
@ -140,13 +162,13 @@ public:
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
//- Construct by transferring the parameter contents
|
//- Construct by transferring the parameter contents
|
||||||
HashSet(const Xfer<HashSet<Key, Hash>>& hs)
|
HashSet(const Xfer<this_type>& hs)
|
||||||
:
|
:
|
||||||
parent_type(hs)
|
parent_type(hs)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//- Construct by transferring the parameter contents
|
//- Construct by transferring the parameter contents
|
||||||
HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs)
|
HashSet(const Xfer<parent_type>& hs)
|
||||||
:
|
:
|
||||||
parent_type(hs)
|
parent_type(hs)
|
||||||
{}
|
{}
|
||||||
@ -166,7 +188,7 @@ public:
|
|||||||
// not previously exist in the set.
|
// not previously exist in the set.
|
||||||
bool insert(const Key& key)
|
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
|
//- Insert keys from the list of Key
|
||||||
@ -182,26 +204,26 @@ public:
|
|||||||
// \return The number of new elements inserted
|
// \return The number of new elements inserted
|
||||||
label insert(std::initializer_list<Key> lst);
|
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)
|
bool set(const Key& key)
|
||||||
{
|
{
|
||||||
return insert(key);
|
return insert(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Same as insert (cannot overwrite nil content)
|
//- Same as insert (no value to overwrite)
|
||||||
label set(const UList<Key>& lst)
|
label set(const UList<Key>& lst)
|
||||||
{
|
{
|
||||||
return insert(lst);
|
return insert(lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Same as insert (cannot overwrite nil content)
|
//- Same as insert (no value to overwrite)
|
||||||
template<unsigned Size>
|
template<unsigned Size>
|
||||||
label set(const FixedList<Key, Size>& lst)
|
label set(const FixedList<Key, Size>& lst)
|
||||||
{
|
{
|
||||||
return insert(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)
|
label set(std::initializer_list<Key> lst)
|
||||||
{
|
{
|
||||||
return insert(lst);
|
return insert(lst);
|
||||||
@ -331,22 +353,22 @@ public:
|
|||||||
// Logical operations
|
// Logical operations
|
||||||
|
|
||||||
//- Combine entries from HashSets
|
//- Combine entries from HashSets
|
||||||
void operator|=(const HashSet<Key, Hash>& rhs);
|
void operator|=(const this_type& rhs);
|
||||||
|
|
||||||
//- Only retain entries found in both HashSets
|
//- 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)
|
//- 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
|
//- 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);
|
this->operator|=(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Remove entries listed in the given HashSet from this HashSet
|
//- 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
|
// IOstream Operator
|
||||||
|
|||||||
@ -61,21 +61,27 @@ Foam::label Foam::HashTable<T, Key, Hash>::eraseMultiple
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * 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>
|
template<class T, class Key, class Hash>
|
||||||
Foam::HashTable<T, Key, Hash>::HashTable(const label size)
|
Foam::HashTable<T, Key, Hash>::HashTable(const label size)
|
||||||
:
|
:
|
||||||
HashTableCore(),
|
HashTableCore(),
|
||||||
nElmts_(0),
|
size_(0),
|
||||||
tableSize_(HashTableCore::canonicalSize(size)),
|
capacity_(HashTableCore::canonicalSize(size)),
|
||||||
table_(nullptr)
|
table_(nullptr)
|
||||||
{
|
{
|
||||||
if (tableSize_)
|
if (capacity_)
|
||||||
{
|
{
|
||||||
table_ = new hashedEntry*[tableSize_];
|
table_ = new node_type*[capacity_];
|
||||||
|
for (label i=0; i < capacity_; ++i)
|
||||||
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
|
|
||||||
{
|
{
|
||||||
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>
|
template<class T, class Key, class Hash>
|
||||||
Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
|
Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
|
||||||
:
|
:
|
||||||
HashTable<T, Key, Hash>(ht.tableSize_)
|
HashTable<T, Key, Hash>(ht.capacity_)
|
||||||
{
|
{
|
||||||
for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
|
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>
|
template<class T, class Key, class Hash>
|
||||||
Foam::HashTable<T, Key, Hash>::HashTable(HashTable<T, Key, Hash>&& ht)
|
Foam::HashTable<T, Key, Hash>::HashTable(HashTable<T, Key, Hash>&& ht)
|
||||||
:
|
:
|
||||||
HashTableCore(),
|
HashTable<T, Key, Hash>(0)
|
||||||
nElmts_(0),
|
|
||||||
tableSize_(0),
|
|
||||||
table_(nullptr)
|
|
||||||
{
|
{
|
||||||
transfer(ht);
|
transfer(ht);
|
||||||
}
|
}
|
||||||
@ -111,10 +114,7 @@ Foam::HashTable<T, Key, Hash>::HashTable
|
|||||||
const Xfer<HashTable<T, Key, Hash>>& ht
|
const Xfer<HashTable<T, Key, Hash>>& ht
|
||||||
)
|
)
|
||||||
:
|
:
|
||||||
HashTableCore(),
|
HashTable<T, Key, Hash>(0)
|
||||||
nElmts_(0),
|
|
||||||
tableSize_(0),
|
|
||||||
table_(nullptr)
|
|
||||||
{
|
{
|
||||||
transfer(ht());
|
transfer(ht());
|
||||||
}
|
}
|
||||||
@ -150,110 +150,10 @@ Foam::HashTable<T, Key, Hash>::~HashTable()
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * 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>
|
template<class T, class Key, class Hash>
|
||||||
Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
|
Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
|
||||||
{
|
{
|
||||||
List<Key> keyLst(nElmts_);
|
List<Key> keyLst(size_);
|
||||||
label count = 0;
|
label count = 0;
|
||||||
|
|
||||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
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 bool invert
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
List<Key> keyLst(nElmts_);
|
List<Key> keyLst(size_);
|
||||||
label count = 0;
|
label count = 0;
|
||||||
|
|
||||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
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 bool invert
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
List<Key> keyLst(nElmts_);
|
List<Key> keyLst(size_);
|
||||||
label count = 0;
|
label count = 0;
|
||||||
|
|
||||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
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 bool invert
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
List<Key> keyLst(nElmts_);
|
List<Key> keyLst(size_);
|
||||||
label count = 0;
|
label count = 0;
|
||||||
|
|
||||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||||
@ -438,36 +338,36 @@ bool Foam::HashTable<T, Key, Hash>::set
|
|||||||
(
|
(
|
||||||
const Key& key,
|
const Key& key,
|
||||||
const T& obj,
|
const T& obj,
|
||||||
const bool protect
|
const bool overwrite
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!tableSize_)
|
if (!capacity_)
|
||||||
{
|
{
|
||||||
resize(2);
|
resize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
const label hashIdx = hashKeyIndex(key);
|
const label index = hashKeyIndex(key);
|
||||||
|
|
||||||
hashedEntry* existing = nullptr;
|
node_type* curr = nullptr;
|
||||||
hashedEntry* prev = 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;
|
break;
|
||||||
}
|
}
|
||||||
prev = ep;
|
prev = ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existing)
|
if (!curr)
|
||||||
{
|
{
|
||||||
// Not found, insert it at the head
|
// Not found, insert it at the head
|
||||||
table_[hashIdx] = new hashedEntry(key, obj, table_[hashIdx]);
|
table_[index] = new node_type(key, obj, table_[index]);
|
||||||
nElmts_++;
|
++size_;
|
||||||
|
|
||||||
if (double(nElmts_)/tableSize_ > 0.8 && tableSize_ < maxTableSize)
|
if (double(size_)/capacity_ > 0.8 && capacity_ < maxTableSize)
|
||||||
{
|
{
|
||||||
#ifdef FULLDEBUG
|
#ifdef FULLDEBUG
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -476,13 +376,35 @@ bool Foam::HashTable<T, Key, Hash>::set
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
resize(2*tableSize_);
|
resize(2*capacity_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (protect)
|
else if (overwrite)
|
||||||
{
|
{
|
||||||
// Found - but protected from overwriting
|
// Overwrite current entry (Perl convention).
|
||||||
// this corresponds to the STL 'insert' 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
|
#ifdef FULLDEBUG
|
||||||
if (debug)
|
if (debug)
|
||||||
{
|
{
|
||||||
@ -492,99 +414,22 @@ bool Foam::HashTable<T, Key, Hash>::set
|
|||||||
#endif
|
#endif
|
||||||
return false;
|
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;
|
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>
|
template<class T, class Key, class Hash>
|
||||||
bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
|
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
|
// The parameter should be (iterator&), but then the compiler doesn't find
|
||||||
// it correctly and tries to call as (iterator) instead.
|
// it correctly and tries to call as (iterator) instead.
|
||||||
//
|
|
||||||
// Adjust iterator after erase
|
iterator& it = const_cast<iterator&>(iter);
|
||||||
return const_cast<iterator&>(iter).erase();
|
|
||||||
|
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>
|
template<class T, class Key, class Hash>
|
||||||
Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
|
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
|
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();
|
const label nTotal = this->size();
|
||||||
label changed = 0;
|
label changed = 0;
|
||||||
|
|
||||||
using other_iter =
|
|
||||||
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
|
|
||||||
|
|
||||||
if (other.size() <= nTotal)
|
if (other.size() <= nTotal)
|
||||||
{
|
{
|
||||||
// The other is smaller/same-size, use its keys for removal
|
// The other is smaller/same-size, use its keys for removal
|
||||||
|
|
||||||
for
|
for
|
||||||
(
|
(
|
||||||
other_iter iter = other.begin();
|
auto iter = other.cbegin();
|
||||||
changed < nTotal && iter != other.end(); // terminate early
|
changed < nTotal && iter != other.cend(); // Terminate early
|
||||||
++iter
|
++iter
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -660,7 +502,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
|
|||||||
for
|
for
|
||||||
(
|
(
|
||||||
iterator iter = begin();
|
iterator iter = begin();
|
||||||
changed < nTotal && iter != end(); // terminate early
|
changed < nTotal && iter != end(); // Terminate early
|
||||||
++iter
|
++iter
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -711,9 +553,10 @@ Foam::label Foam::HashTable<T, Key, Hash>::retain
|
|||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
void Foam::HashTable<T, Key, Hash>::resize(const label sz)
|
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
|
#ifdef FULLDEBUG
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -724,46 +567,85 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (!newCapacity)
|
||||||
HashTable<T, Key, Hash>* tmpTable = new HashTable<T, Key, Hash>(newSize);
|
|
||||||
|
|
||||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
|
||||||
{
|
{
|
||||||
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_;
|
// Swap primary table entries: size_ is left untouched
|
||||||
tableSize_ = tmpTable->tableSize_;
|
|
||||||
tmpTable->tableSize_ = oldSize;
|
|
||||||
|
|
||||||
hashedEntry** oldTable = table_;
|
auto oldTable = table_;
|
||||||
table_ = tmpTable->table_;
|
capacity_ = newCapacity;
|
||||||
tmpTable->table_ = oldTable;
|
|
||||||
|
|
||||||
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>
|
template<class T, class Key, class Hash>
|
||||||
void Foam::HashTable<T, Key, Hash>::clear()
|
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])
|
node_type* next = ep->next_;
|
||||||
{
|
|
||||||
hashedEntry* ep = table_[hashIdx];
|
delete ep;
|
||||||
while (hashedEntry* next = ep->next_)
|
|
||||||
{
|
ep = next; // continue in the linked-list
|
||||||
delete ep;
|
--size_; // note any early completion
|
||||||
ep = next;
|
|
||||||
}
|
|
||||||
delete ep;
|
|
||||||
table_[hashIdx] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
nElmts_ = 0;
|
table_[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,30 +661,31 @@ void Foam::HashTable<T, Key, Hash>::clearStorage()
|
|||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
void Foam::HashTable<T, Key, Hash>::swap(HashTable<T, Key, Hash>& ht)
|
void Foam::HashTable<T, Key, Hash>::swap(HashTable<T, Key, Hash>& ht)
|
||||||
{
|
{
|
||||||
Foam::Swap(table_, ht.table_);
|
Foam::Swap(size_, ht.size_);
|
||||||
Foam::Swap(tableSize_, ht.tableSize_);
|
Foam::Swap(capacity_, ht.capacity_);
|
||||||
Foam::Swap(nElmts_, ht.nElmts_);
|
Foam::Swap(table_, ht.table_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
|
void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
|
||||||
{
|
{
|
||||||
// As per the Destructor
|
// As per destructor
|
||||||
if (table_)
|
if (table_)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
delete[] table_;
|
delete[] table_;
|
||||||
}
|
}
|
||||||
|
|
||||||
tableSize_ = ht.tableSize_;
|
size_ = ht.size_;
|
||||||
ht.tableSize_ = 0;
|
ht.size_ = 0;
|
||||||
|
|
||||||
|
capacity_ = ht.capacity_;
|
||||||
|
ht.capacity_ = 0;
|
||||||
|
|
||||||
table_ = ht.table_;
|
table_ = ht.table_;
|
||||||
ht.table_ = nullptr;
|
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()
|
// Could be zero-sized from a previous transfer()
|
||||||
if (!tableSize_)
|
if (!capacity_)
|
||||||
{
|
{
|
||||||
resize(rhs.tableSize_);
|
resize(rhs.capacity_);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -927,7 +810,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Could be zero-sized from a previous transfer()
|
// Could be zero-sized from a previous transfer()
|
||||||
if (!tableSize_)
|
if (!capacity_)
|
||||||
{
|
{
|
||||||
resize(2*lst.size());
|
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)
|
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())
|
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"
|
#include "HashTableIO.C"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|||||||
@ -25,14 +25,15 @@ Class
|
|||||||
Foam::HashTable
|
Foam::HashTable
|
||||||
|
|
||||||
Description
|
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
|
Internally the table uses closed addressing into a flat storage space
|
||||||
Hashing index collisions are handled via chaining using a singly-linked
|
with collisions handled by linked-list chaining.
|
||||||
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.
|
|
||||||
|
|
||||||
The end iterator of all hash-tables has a nullptr to the hash entry.
|
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
|
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.
|
a nullptr as its first data member.
|
||||||
The nullObject is such an item (with a nullptr 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
|
SourceFiles
|
||||||
HashTableI.H
|
HashTableI.H
|
||||||
|
HashTableIterI.H
|
||||||
HashTable.C
|
HashTable.C
|
||||||
HashTableIO.C
|
HashTableIO.C
|
||||||
|
HashTableIter.C
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
@ -52,6 +81,7 @@ SourceFiles
|
|||||||
#define HashTable_H
|
#define HashTable_H
|
||||||
|
|
||||||
#include "word.H"
|
#include "word.H"
|
||||||
|
#include "zero.H"
|
||||||
#include "Xfer.H"
|
#include "Xfer.H"
|
||||||
#include "Hash.H"
|
#include "Hash.H"
|
||||||
#include "HashTableCore.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>
|
template<class T, class Key=word, class Hash=string::hash>
|
||||||
@ -88,6 +118,140 @@ class HashTable
|
|||||||
:
|
:
|
||||||
public HashTableCore
|
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:
|
public:
|
||||||
|
|
||||||
//- The template instance used for this HashTable
|
//- The template instance used for this HashTable
|
||||||
@ -96,18 +260,25 @@ public:
|
|||||||
|
|
||||||
// STL type definitions
|
// STL type definitions
|
||||||
|
|
||||||
//- Type of keys that the HashTable uses.
|
//- The second template parameter, type of keys used.
|
||||||
typedef Key key_type;
|
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;
|
typedef T value_type;
|
||||||
|
|
||||||
|
//- The third template parameter, the hash index method.
|
||||||
|
typedef Hash hasher;
|
||||||
|
|
||||||
//- The type used for storing into value_type objects.
|
//- The type used for storing into value_type objects.
|
||||||
// This type is usually value_type&.
|
// This type is usually 'value_type*'.
|
||||||
typedef T* pointer;
|
typedef T* pointer;
|
||||||
|
|
||||||
//- The type used for storing into value_type objects.
|
//- The type used for storing into value_type objects.
|
||||||
// This type is usually value_type&.
|
// This type is usually 'value_type&'.
|
||||||
typedef T& reference;
|
typedef T& reference;
|
||||||
|
|
||||||
//- The type used for reading from constant value_type objects.
|
//- The type used for reading from constant value_type objects.
|
||||||
@ -129,65 +300,14 @@ public:
|
|||||||
//- Forward iterator with const access
|
//- Forward iterator with const access
|
||||||
class const_iterator;
|
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:
|
protected:
|
||||||
|
|
||||||
//- Internally used base for iterator and const_iterator
|
//- Internally used base for iterator and const_iterator
|
||||||
class iterator_base;
|
template<bool Const> class Iterator;
|
||||||
|
|
||||||
//- Friendship with the iterator_base is required.
|
//- Friendship with the base iterator is required.
|
||||||
friend class iterator_base;
|
friend class Iterator<true>;
|
||||||
|
friend class Iterator<false>;
|
||||||
|
|
||||||
|
|
||||||
// Protected Member Functions
|
// Protected Member Functions
|
||||||
@ -205,20 +325,23 @@ public:
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct given initial table size
|
//- Construct null with default (128) table size
|
||||||
HashTable(const label size = 128);
|
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);
|
HashTable(Istream& is, const label size = 128);
|
||||||
|
|
||||||
//- Construct as copy
|
//- Construct as copy
|
||||||
HashTable(const HashTable<T, Key, Hash>& ht);
|
HashTable(const this_type& ht);
|
||||||
|
|
||||||
//- Move construct
|
//- Move construct
|
||||||
HashTable(HashTable<T, Key, Hash>&& ht);
|
HashTable(this_type&& ht);
|
||||||
|
|
||||||
//- Construct by transferring the parameter contents
|
//- 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
|
//- Construct from an initializer list
|
||||||
HashTable(std::initializer_list<std::pair<Key, T>> lst);
|
HashTable(std::initializer_list<std::pair<Key, T>> lst);
|
||||||
@ -242,19 +365,19 @@ public:
|
|||||||
inline bool empty() const;
|
inline bool empty() const;
|
||||||
|
|
||||||
//- Return true if hashed entry is found in table
|
//- 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
|
//- Find and return an iterator set at the hashed entry
|
||||||
// If not found iterator = end()
|
// 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
|
//- Find and return an const_iterator set at the hashed entry
|
||||||
// If not found iterator = end()
|
// 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
|
//- Find and return an const_iterator set at the hashed entry
|
||||||
// If not found iterator = end()
|
// 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
|
//- Return hashed entry if it exists, or return the given default
|
||||||
inline const T& lookup(const Key& key, const T& deflt) const;
|
inline const T& lookup(const Key& key, const T& deflt) const;
|
||||||
@ -512,149 +635,157 @@ protected:
|
|||||||
// and prevent most external usage.
|
// and prevent most external usage.
|
||||||
// iterator and const_iterator have the same size, allowing
|
// iterator and const_iterator have the same size, allowing
|
||||||
// us to reinterpret_cast between them (if desired)
|
// us to reinterpret_cast between them (if desired)
|
||||||
class iterator_base
|
|
||||||
|
template<bool Const>
|
||||||
|
class Iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Public typedefs
|
// Typedefs
|
||||||
using table_type = this_type;
|
|
||||||
using key_type = this_type::key_type;
|
|
||||||
using iterator_category = std::forward_iterator_tag;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
using difference_type = this_type::difference_type;
|
using difference_type = this_type::difference_type;
|
||||||
|
|
||||||
private:
|
//- The HashTable container type
|
||||||
using entry_type = hashedEntry;
|
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.
|
//- The key type
|
||||||
// MUST be the first member for easy comparison between iterators
|
using key_type = this_type::key_type;
|
||||||
// and for reinterpret_cast from nullObject
|
|
||||||
entry_type* entryPtr_;
|
|
||||||
|
|
||||||
//- Pointer to the hash-table for which this is an iterator
|
//- The object type being addressed
|
||||||
// This allows use of the default bitwise copy/assignment
|
using mapped_type = typename std::conditional
|
||||||
table_type* hashTable_;
|
<
|
||||||
|
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:
|
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
|
// Protected Member Functions
|
||||||
|
|
||||||
//- Increment to the next position
|
//- Increment to the next position
|
||||||
inline void increment();
|
inline void increment();
|
||||||
|
|
||||||
//- The referenced object/value element
|
//- The object associated with the iterator
|
||||||
inline T& element() const;
|
inline mapped_type& object() const
|
||||||
|
{
|
||||||
|
return entry_->mapped();
|
||||||
|
}
|
||||||
|
|
||||||
//- Erase the entry at the current position
|
//- Permit an explicit cast to the other (const/non-const) searcher
|
||||||
bool erase();
|
inline explicit operator const Iterator<!Const>&() const
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<const Iterator<!Const>*>(this);
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//- 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:
|
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
|
//- Forward iterator with non-const access
|
||||||
class iterator
|
class iterator
|
||||||
:
|
:
|
||||||
public iterator_base
|
public Iterator<false>
|
||||||
{
|
{
|
||||||
friend class HashTable; // Uses iterator::erase() method
|
|
||||||
using entry_type = hashedEntry;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Typedefs
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = this_type::difference_type;
|
||||||
|
|
||||||
// Public typedefs
|
using key_type = this_type::key_type;
|
||||||
using table_type = this_type;
|
using mapped_type = this_type::mapped_type;
|
||||||
using value_type = this_type::value_type;
|
using value_type = this_type::value_type;
|
||||||
using pointer = this_type::pointer;
|
using pointer = this_type::pointer;
|
||||||
using reference = this_type::reference;
|
using reference = this_type::reference;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct null (end iterator)
|
//- Construct null (end iterator)
|
||||||
inline iterator();
|
inline iterator() {}
|
||||||
|
|
||||||
//- Construct from begin of hash-table
|
//- Copy construct from similar access type
|
||||||
inline explicit iterator(table_type* hashTbl);
|
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
|
// Member functions/operators
|
||||||
|
|
||||||
//- Return non-const access to referenced object
|
//- Non-const access to referenced object
|
||||||
inline reference object() const;
|
using Iterator<false>::object;
|
||||||
|
|
||||||
//- Return non-const access to referenced object
|
//- Non-const access to referenced object
|
||||||
inline reference operator*() const;
|
inline reference operator*() const { return this->object(); }
|
||||||
inline reference operator()() const;
|
inline reference operator()() const { return this->object(); }
|
||||||
|
|
||||||
inline iterator& operator++();
|
inline iterator& operator++();
|
||||||
inline iterator operator++(int);
|
inline iterator operator++(int);
|
||||||
@ -666,54 +797,111 @@ public:
|
|||||||
//- Forward iterator with const access
|
//- Forward iterator with const access
|
||||||
class const_iterator
|
class const_iterator
|
||||||
:
|
:
|
||||||
public iterator_base
|
public Iterator<true>
|
||||||
{
|
{
|
||||||
using entry_type = const hashedEntry;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Typedefs
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = this_type::difference_type;
|
||||||
|
|
||||||
// Public typedefs
|
using key_type = this_type::key_type;
|
||||||
using table_type = const this_type;
|
using mapped_type = const this_type::mapped_type;
|
||||||
using value_type = const this_type::value_type;
|
using value_type = const this_type::value_type;
|
||||||
using pointer = this_type::const_pointer;
|
using pointer = this_type::const_pointer;
|
||||||
using reference = this_type::const_reference;
|
using reference = this_type::const_reference;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct null (end iterator)
|
//- Construct null (end iterator)
|
||||||
inline const_iterator();
|
inline const_iterator() {}
|
||||||
|
|
||||||
//- Construct from begin of hash-table
|
//- Copy construct from similar access type
|
||||||
inline explicit const_iterator(table_type* hashTbl);
|
inline explicit const_iterator(const Iterator<true>& iter)
|
||||||
|
:
|
||||||
|
Iterator<true>(iter)
|
||||||
|
{}
|
||||||
|
|
||||||
//- Construct from hash table, element and hash index.
|
//- Copy construct from dissimilar access type
|
||||||
// Used by the hash-table find() method.
|
inline explicit const_iterator(const Iterator<false>& iter)
|
||||||
inline const_iterator
|
:
|
||||||
(
|
Iterator<true>
|
||||||
table_type* hashTbl,
|
(
|
||||||
entry_type* elmt,
|
static_cast<const Iterator<true>&>(iter)
|
||||||
const label hashIndex
|
)
|
||||||
);
|
{}
|
||||||
|
|
||||||
|
//- 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
|
// Member functions/operators
|
||||||
|
|
||||||
//- Return const access to referenced object
|
//- Const access to referenced object
|
||||||
inline reference object() const;
|
using Iterator<true>::object;
|
||||||
|
|
||||||
//- Return const access to referenced object
|
//- Const access to referenced object
|
||||||
inline reference operator*() const;
|
inline reference operator*() const { return this->object(); }
|
||||||
inline reference operator()() const;
|
inline reference operator()() const { return this->object(); }
|
||||||
|
|
||||||
inline const_iterator& operator++();
|
inline const_iterator& operator++();
|
||||||
inline const_iterator operator++(int);
|
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
|
//- 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
|
//- Forward iterator returning the key
|
||||||
using key_iterator = key_iterator_base<iterator>;
|
using key_iterator = key_iterator_base<iterator>;
|
||||||
|
|
||||||
@ -793,6 +981,7 @@ inline void Swap
|
|||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
#include "HashTableI.H"
|
#include "HashTableI.H"
|
||||||
|
#include "HashTableIterI.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,8 @@ defineTypeNameAndDebug(HashTableCore, 0);
|
|||||||
// Approximately labelMax/4
|
// Approximately labelMax/4
|
||||||
const Foam::label Foam::HashTableCore::maxTableSize(1L << (sizeof(label)*8-3));
|
const Foam::label Foam::HashTableCore::maxTableSize(1L << (sizeof(label)*8-3));
|
||||||
|
|
||||||
|
Foam::zero::null Foam::HashTableCore::zeroNullElement;
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
|
|||||||
return maxTableSize;
|
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.
|
// Use unsigned for these calculations.
|
||||||
//
|
//
|
||||||
// - The lower limit (8) is somewhat arbitrary, but if the hash table
|
// - 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;
|
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.
|
// Determine power-of-two. Brute-force is fast enough.
|
||||||
while (powerOfTwo < size)
|
while (powerOfTwo < size)
|
||||||
@ -75,10 +78,8 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
|
|||||||
|
|
||||||
return powerOfTwo;
|
return powerOfTwo;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return size;
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,7 @@ SourceFiles
|
|||||||
#include "uLabel.H"
|
#include "uLabel.H"
|
||||||
#include "className.H"
|
#include "className.H"
|
||||||
#include "nullObject.H"
|
#include "nullObject.H"
|
||||||
|
#include "zero.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -77,20 +78,16 @@ struct HashTableCore
|
|||||||
template<class IteratorType, class TableType>
|
template<class IteratorType, class TableType>
|
||||||
inline static IteratorType iterator_begin(TableType& table);
|
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
|
//- Factory method to create a const iterator begin
|
||||||
template<class IteratorType, class TableType>
|
template<class IteratorType, class TableType>
|
||||||
inline static IteratorType iterator_cbegin(const TableType& table);
|
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.
|
// Simply reinterprets a NullObject as a hash-table iterator.
|
||||||
template<class IteratorType>
|
template<class IteratorType>
|
||||||
inline static const IteratorType& iterator_end();
|
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.
|
// Simply reinterprets a NullObject as a hash-table iterator.
|
||||||
template<class IteratorType>
|
template<class IteratorType>
|
||||||
inline static const IteratorType& iterator_cend();
|
inline static const IteratorType& iterator_cend();
|
||||||
@ -116,6 +113,13 @@ struct HashTableCore
|
|||||||
inline const IteratorType& end() const;
|
inline const IteratorType& end() const;
|
||||||
inline const IteratorType& cend() const;
|
inline const IteratorType& cend() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//- A static zero::null for dereferencing as a dummy HashSet element
|
||||||
|
static zero::null zeroNullElement;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
template<class IteratorType, class TableType>
|
||||||
inline IteratorType Foam::HashTableCore::iterator_cbegin
|
inline IteratorType Foam::HashTableCore::iterator_cbegin
|
||||||
(
|
(
|
||||||
|
|||||||
@ -25,30 +25,14 @@ License
|
|||||||
|
|
||||||
#include "error.H"
|
#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 * * * * * * * * * * * * //
|
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
inline Foam::label
|
inline Foam::label
|
||||||
Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
|
Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
|
||||||
{
|
{
|
||||||
// size is power of two - this is the modulus
|
// capacity is always a power of two - this is the modulus
|
||||||
return Hash()(key) & (tableSize_ - 1);
|
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>
|
template<class T, class Key, class Hash>
|
||||||
inline Foam::label Foam::HashTable<T, Key, Hash>::capacity() const
|
inline Foam::label Foam::HashTable<T, Key, Hash>::capacity() const
|
||||||
{
|
{
|
||||||
return tableSize_;
|
return capacity_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
inline Foam::label Foam::HashTable<T, Key, Hash>::size() const
|
inline Foam::label Foam::HashTable<T, Key, Hash>::size() const
|
||||||
{
|
{
|
||||||
return nElmts_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
inline bool Foam::HashTable<T, Key, Hash>::empty() const
|
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
|
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
|
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 T& deflt
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
const_iterator iter = this->find(key);
|
const const_iterator iter(this->cfind(key));
|
||||||
return iter.found() ? iter.object() : deflt;
|
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>
|
template<class T, class Key, class Hash>
|
||||||
inline T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key)
|
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())
|
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>
|
template<class T, class Key, class Hash>
|
||||||
inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
|
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())
|
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>
|
template<class T, class Key, class Hash>
|
||||||
inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key)
|
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())
|
if (iter.found())
|
||||||
{
|
{
|
||||||
return iter.object();
|
return iter.object();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->insert(key, T());
|
this->insert(key, mapped_type());
|
||||||
return find(key).object();
|
return find(key).object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +214,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()
|
|||||||
const T& deflt
|
const T& deflt
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
iterator iter = this->find(key);
|
const iterator iter(this->find(key));
|
||||||
|
|
||||||
if (iter.found())
|
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 * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
|
|||||||
@ -33,17 +33,17 @@ template<class T, class Key, class Hash>
|
|||||||
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
|
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
|
||||||
:
|
:
|
||||||
HashTableCore(),
|
HashTableCore(),
|
||||||
nElmts_(0),
|
size_(0),
|
||||||
tableSize_(HashTableCore::canonicalSize(size)),
|
capacity_(HashTableCore::canonicalSize(size)),
|
||||||
table_(nullptr)
|
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;
|
label maxChain = 0;
|
||||||
unsigned avgChain = 0;
|
unsigned avgChain = 0;
|
||||||
|
|
||||||
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
|
for (label i=0; i < capacity_; ++i)
|
||||||
{
|
{
|
||||||
label count = 0;
|
label count = 0;
|
||||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
for (node_type* ep = table_[i]; ep; ep = ep->next_)
|
||||||
{
|
{
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::printInfo(Ostream& os) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
os << "HashTable<T,Key,Hash>"
|
os << "HashTable<T,Key,Hash>"
|
||||||
<< " elements:" << size() << " slots:" << used << "/" << tableSize_
|
<< " elements:" << size() << " slots:" << used << "/" << capacity_
|
||||||
<< " chaining(avg/max):" << (used ? (float(avgChain)/used) : 0)
|
<< " chaining(avg/max):" << (used ? (float(avgChain)/used) : 0)
|
||||||
<< "/" << maxChain << endl;
|
<< "/" << maxChain << endl;
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ Foam::Istream& Foam::operator>>
|
|||||||
{
|
{
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
// Anull list
|
// Anull existing table
|
||||||
L.clear();
|
L.clear();
|
||||||
|
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
@ -154,7 +154,7 @@ Foam::Istream& Foam::operator>>
|
|||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
"operator>>(Istream&, HashTable&) : "
|
||||||
"reading first token"
|
"reading first token"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -163,11 +163,11 @@ Foam::Istream& Foam::operator>>
|
|||||||
const label s = firstToken.labelToken();
|
const label s = firstToken.labelToken();
|
||||||
|
|
||||||
// Read beginning of contents
|
// Read beginning of contents
|
||||||
const char delimiter = is.readBeginList("HashTable<T, Key, Hash>");
|
const char delimiter = is.readBeginList("HashTable");
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
if (2*s > L.tableSize_)
|
if (2*s > L.capacity_)
|
||||||
{
|
{
|
||||||
L.resize(2*s);
|
L.resize(2*s);
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ Foam::Istream& Foam::operator>>
|
|||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
"operator>>(Istream&, HashTable&) : "
|
||||||
"reading entry"
|
"reading entry"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -224,15 +224,11 @@ Foam::Istream& Foam::operator>>
|
|||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
is >> key;
|
is >> key;
|
||||||
|
L.insert(key, pTraits<T>(is));
|
||||||
T element;
|
|
||||||
is >> element;
|
|
||||||
|
|
||||||
L.insert(key, element);
|
|
||||||
|
|
||||||
is.fatalCheck
|
is.fatalCheck
|
||||||
(
|
(
|
||||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
"operator>>(Istream&, HashTable&) : "
|
||||||
"reading entry"
|
"reading entry"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -262,19 +258,26 @@ Foam::Ostream& Foam::operator<<
|
|||||||
const HashTable<T, Key, Hash>& tbl
|
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
|
if (sz)
|
||||||
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
|
|
||||||
|
|
||||||
// Write contents
|
|
||||||
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
|
||||||
{
|
{
|
||||||
os << iter.key() << token::SPACE << iter.object() << nl;
|
// Size and start list delimiter
|
||||||
}
|
os << nl << sz << nl << token::BEGIN_LIST << nl;
|
||||||
|
|
||||||
// Write end delimiter
|
// Contents
|
||||||
os << token::END_LIST;
|
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);
|
os.check(FUNCTION_NAME);
|
||||||
return os;
|
return os;
|
||||||
|
|||||||
123
src/OpenFOAM/containers/HashTables/HashTable/HashTableIter.C
Normal file
123
src/OpenFOAM/containers/HashTables/HashTable/HashTableIter.C
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
263
src/OpenFOAM/containers/HashTables/HashTable/HashTableIterI.H
Normal file
263
src/OpenFOAM/containers/HashTables/HashTable/HashTableIterI.H
Normal 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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -27,6 +27,11 @@ Class
|
|||||||
Description
|
Description
|
||||||
A HashTable to objects of type \<T\> with a label key.
|
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
|
See also
|
||||||
PtrMap
|
PtrMap
|
||||||
|
|
||||||
@ -65,13 +70,19 @@ public:
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct given initial size
|
//- Construct null with default table size
|
||||||
Map(const label size = 128)
|
Map()
|
||||||
|
:
|
||||||
|
parent_type()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//- Construct with given table size
|
||||||
|
explicit Map(const label size)
|
||||||
:
|
:
|
||||||
parent_type(size)
|
parent_type(size)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//- Construct from Istream
|
//- Construct from Istream with default table size
|
||||||
Map(Istream& is)
|
Map(Istream& is)
|
||||||
:
|
:
|
||||||
parent_type(is)
|
parent_type(is)
|
||||||
@ -96,7 +107,7 @@ public:
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
//- Construct by transferring the parameter contents
|
//- Construct by transferring the parameter contents
|
||||||
Map(const Xfer<HashTable<T, label, Hash<label>>>& map)
|
Map(const Xfer<parent_type>& map)
|
||||||
:
|
:
|
||||||
parent_type(map)
|
parent_type(map)
|
||||||
{}
|
{}
|
||||||
|
|||||||
@ -62,8 +62,14 @@ public:
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct null with default table size
|
||||||
|
PtrMap()
|
||||||
|
:
|
||||||
|
parent_type()
|
||||||
|
{}
|
||||||
|
|
||||||
//- Construct given initial map size
|
//- Construct given initial map size
|
||||||
PtrMap(const label size = 128)
|
explicit PtrMap(const label size)
|
||||||
:
|
:
|
||||||
parent_type(size)
|
parent_type(size)
|
||||||
{}
|
{}
|
||||||
|
|||||||
Reference in New Issue
Block a user