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 * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable()
|
||||
:
|
||||
parent_type()
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashPtrTable<T, Key, Hash>::HashPtrTable(const label size)
|
||||
:
|
||||
@ -157,6 +164,7 @@ void Foam::HashPtrTable<T, Key, Hash>::operator=
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
|
||||
|
||||
#include "HashPtrTableIO.C"
|
||||
|
||||
@ -91,8 +91,11 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null with default table size
|
||||
HashPtrTable();
|
||||
|
||||
//- Construct given initial table size
|
||||
HashPtrTable(const label size = 128);
|
||||
explicit HashPtrTable(const label size);
|
||||
|
||||
//- Construct from Istream using given Istream constructor class
|
||||
template<class INew>
|
||||
@ -102,7 +105,7 @@ public:
|
||||
HashPtrTable(Istream& is);
|
||||
|
||||
//- Construct from dictionary with default dictionary constructor class
|
||||
HashPtrTable(const dictionary& dict);
|
||||
explicit HashPtrTable(const dictionary& dict);
|
||||
|
||||
//- Construct as copy
|
||||
HashPtrTable(const this_type& ht);
|
||||
@ -127,7 +130,7 @@ public:
|
||||
//- Erase an entry specified by the given key
|
||||
bool erase(const Key& key);
|
||||
|
||||
//- Clear all entries from table
|
||||
//- Clear all entries from table and deleting any allocated pointers
|
||||
void clear();
|
||||
|
||||
//- Write
|
||||
|
||||
@ -41,7 +41,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
|
||||
"HashPtrTable::read(Istream&, const INew&) : "
|
||||
"reading first token"
|
||||
);
|
||||
|
||||
@ -50,7 +50,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
||||
const label s = firstToken.labelToken();
|
||||
|
||||
// Read beginning of contents
|
||||
const char delimiter = is.readBeginList("HashPtrTable<T, Key, Hash>");
|
||||
const char delimiter = is.readBeginList("HashPtrTable");
|
||||
|
||||
if (s)
|
||||
{
|
||||
@ -69,8 +69,8 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"HashPtrTable<T, Key, Hash>::"
|
||||
"read(Istream&, const INew&) : reading entry"
|
||||
"HashPtrTable::read(Istream&, const INew&) : "
|
||||
"reading entry"
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -114,7 +114,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read(Istream& is, const INew& inewt)
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"HashPtrTable<T, Key, Hash>::read(Istream&, const INew&) : "
|
||||
"HashPtrTable::read(Istream&, const INew&) : "
|
||||
"reading entry"
|
||||
);
|
||||
|
||||
@ -155,7 +155,7 @@ void Foam::HashPtrTable<T, Key, Hash>::read
|
||||
template<class T, class Key, class Hash>
|
||||
void Foam::HashPtrTable<T, Key, Hash>::write(Ostream& os) const
|
||||
{
|
||||
for (const_iterator iter = this->begin(); iter != this->end(); ++iter)
|
||||
for (const_iterator iter = this->cbegin(); iter != this->cend(); ++iter)
|
||||
{
|
||||
const T* ptr = iter.object();
|
||||
if (ptr)
|
||||
@ -209,29 +209,34 @@ Foam::Ostream& Foam::operator<<
|
||||
const HashPtrTable<T, Key, Hash>& tbl
|
||||
)
|
||||
{
|
||||
using const_iterator = typename HashPtrTable<T, Key, Hash>::const_iterator;
|
||||
const label sz = tbl.size();
|
||||
|
||||
// Write size and start delimiter
|
||||
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
// Write contents
|
||||
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
||||
if (sz)
|
||||
{
|
||||
const T* ptr = iter.object();
|
||||
// Size and start list delimiter
|
||||
os << nl << sz << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
os << iter.key();
|
||||
if (ptr)
|
||||
// Contents
|
||||
for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
||||
{
|
||||
os << token::SPACE << *ptr;
|
||||
const T* ptr = iter.object();
|
||||
|
||||
os << iter.key();
|
||||
if (ptr)
|
||||
{
|
||||
os << token::SPACE << *ptr;
|
||||
}
|
||||
os << nl;
|
||||
}
|
||||
os << nl;
|
||||
os << token::END_LIST; // End list delimiter
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty hash table
|
||||
os << sz << token::BEGIN_LIST << token::END_LIST;
|
||||
}
|
||||
|
||||
// Write end delimiter
|
||||
os << token::END_LIST;
|
||||
|
||||
os.check(FUNCTION_NAME);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ inline Foam::label Foam::HashSet<Key, Hash>::assignMultiple
|
||||
template<class Key, class Hash>
|
||||
Foam::HashSet<Key, Hash>::HashSet(const UList<Key>& lst)
|
||||
:
|
||||
HashTable<nil, Key, Hash>(2*lst.size())
|
||||
parent_type(2*lst.size())
|
||||
{
|
||||
for (const auto& k : lst)
|
||||
{
|
||||
@ -92,7 +92,7 @@ template<class Key, class Hash>
|
||||
template<unsigned Size>
|
||||
Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
|
||||
:
|
||||
HashTable<nil, Key, Hash>(2*lst.size())
|
||||
parent_type(2*lst.size())
|
||||
{
|
||||
for (const auto& k : lst)
|
||||
{
|
||||
@ -104,7 +104,7 @@ Foam::HashSet<Key, Hash>::HashSet(const FixedList<Key, Size>& lst)
|
||||
template<class Key, class Hash>
|
||||
Foam::HashSet<Key, Hash>::HashSet(std::initializer_list<Key> lst)
|
||||
:
|
||||
HashTable<nil, Key, Hash>(2*lst.size())
|
||||
parent_type(2*lst.size())
|
||||
{
|
||||
for (const auto& k : lst)
|
||||
{
|
||||
@ -120,7 +120,7 @@ Foam::HashSet<Key, Hash>::HashSet
|
||||
const HashTable<AnyType, Key, AnyHash>& tbl
|
||||
)
|
||||
:
|
||||
HashTable<nil, Key, Hash>(tbl.capacity())
|
||||
parent_type(tbl.capacity())
|
||||
{
|
||||
using other_iter =
|
||||
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
|
||||
@ -349,7 +349,7 @@ template<class Key, class Hash>
|
||||
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
||||
Foam::HashSet<Key, Hash>::begin() const
|
||||
{
|
||||
return HashTableCore::iterator_begin<const_iterator>
|
||||
return HashTableCore::iterator_cbegin<const_iterator>
|
||||
(
|
||||
static_cast<const parent_type&>(*this)
|
||||
);
|
||||
@ -360,7 +360,7 @@ template<class Key, class Hash>
|
||||
inline typename Foam::HashSet<Key, Hash>::const_iterator
|
||||
Foam::HashSet<Key, Hash>::cbegin() const
|
||||
{
|
||||
return HashTableCore::iterator_begin<const_iterator>
|
||||
return HashTableCore::iterator_cbegin<const_iterator>
|
||||
(
|
||||
static_cast<const parent_type&>(*this)
|
||||
);
|
||||
@ -379,7 +379,7 @@ template<class Key, class Hash>
|
||||
inline const typename Foam::HashSet<Key, Hash>::const_iterator&
|
||||
Foam::HashSet<Key, Hash>::end() const
|
||||
{
|
||||
return HashTableCore::iterator_end<const_iterator>();
|
||||
return HashTableCore::iterator_cend<const_iterator>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,24 @@ Class
|
||||
Foam::HashSet
|
||||
|
||||
Description
|
||||
A HashTable with keys but without contents.
|
||||
A HashTable with keys but without contents that is similar to
|
||||
\c std::unordered_set.
|
||||
The entries are considered \a unordered since their placement
|
||||
depends on the method used to generate the hash key index, the
|
||||
table capacity, insertion order etc. When the key order is
|
||||
important, use the sortedToc() method to obtain a list of sorted
|
||||
keys and use that for further access.
|
||||
|
||||
Note
|
||||
The HashSet iterator dereferences to the key, so the following
|
||||
range-for works as expected:
|
||||
\code
|
||||
HashSet<label> someLabels{10, 20, 30, 40, ...};
|
||||
for (const label i : someLabels)
|
||||
{
|
||||
Info<< "val:" << i << nl;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Typedef
|
||||
Foam::wordHashSet
|
||||
@ -45,7 +62,6 @@ Description
|
||||
#define HashSet_H
|
||||
|
||||
#include "HashTable.H"
|
||||
#include "nil.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -66,7 +82,7 @@ Ostream& operator<<(Ostream& os, const HashSet<Key, Hash>& tbl);
|
||||
template<class Key=word, class Hash=string::hash>
|
||||
class HashSet
|
||||
:
|
||||
public HashTable<nil, Key, Hash>
|
||||
public HashTable<zero::null, Key, Hash>
|
||||
{
|
||||
// Private Member Functions
|
||||
|
||||
@ -94,7 +110,7 @@ public:
|
||||
typedef HashSet<Key, Hash> this_type;
|
||||
|
||||
//- The template instance used for the parent HashTable
|
||||
typedef HashTable<nil, Key, Hash> parent_type;
|
||||
typedef HashTable<zero::null, Key, Hash> parent_type;
|
||||
|
||||
//- An iterator, returning reference to the key
|
||||
using iterator = typename parent_type::key_iterator;
|
||||
@ -105,13 +121,19 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null with default (128) table size
|
||||
HashSet()
|
||||
:
|
||||
parent_type()
|
||||
{}
|
||||
|
||||
//- Construct given initial size
|
||||
HashSet(const label size = 128)
|
||||
explicit HashSet(const label size)
|
||||
:
|
||||
parent_type(size)
|
||||
{}
|
||||
|
||||
//- Construct from Istream
|
||||
//- Construct from Istream with default table size
|
||||
HashSet(Istream& is)
|
||||
:
|
||||
parent_type(is)
|
||||
@ -140,13 +162,13 @@ public:
|
||||
{}
|
||||
|
||||
//- Construct by transferring the parameter contents
|
||||
HashSet(const Xfer<HashSet<Key, Hash>>& hs)
|
||||
HashSet(const Xfer<this_type>& hs)
|
||||
:
|
||||
parent_type(hs)
|
||||
{}
|
||||
|
||||
//- Construct by transferring the parameter contents
|
||||
HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs)
|
||||
HashSet(const Xfer<parent_type>& hs)
|
||||
:
|
||||
parent_type(hs)
|
||||
{}
|
||||
@ -166,7 +188,7 @@ public:
|
||||
// not previously exist in the set.
|
||||
bool insert(const Key& key)
|
||||
{
|
||||
return this->parent_type::insert(key, nil());
|
||||
return this->parent_type::insert(key, zero::null());
|
||||
}
|
||||
|
||||
//- Insert keys from the list of Key
|
||||
@ -182,26 +204,26 @@ public:
|
||||
// \return The number of new elements inserted
|
||||
label insert(std::initializer_list<Key> lst);
|
||||
|
||||
//- Same as insert (cannot overwrite nil content)
|
||||
//- Same as insert (no value to overwrite)
|
||||
bool set(const Key& key)
|
||||
{
|
||||
return insert(key);
|
||||
}
|
||||
|
||||
//- Same as insert (cannot overwrite nil content)
|
||||
//- Same as insert (no value to overwrite)
|
||||
label set(const UList<Key>& lst)
|
||||
{
|
||||
return insert(lst);
|
||||
}
|
||||
|
||||
//- Same as insert (cannot overwrite nil content)
|
||||
//- Same as insert (no value to overwrite)
|
||||
template<unsigned Size>
|
||||
label set(const FixedList<Key, Size>& lst)
|
||||
{
|
||||
return insert(lst);
|
||||
}
|
||||
|
||||
//- Same as insert (cannot overwrite nil content)
|
||||
//- Same as insert (no value to overwrite)
|
||||
label set(std::initializer_list<Key> lst)
|
||||
{
|
||||
return insert(lst);
|
||||
@ -331,22 +353,22 @@ public:
|
||||
// Logical operations
|
||||
|
||||
//- Combine entries from HashSets
|
||||
void operator|=(const HashSet<Key, Hash>& rhs);
|
||||
void operator|=(const this_type& rhs);
|
||||
|
||||
//- Only retain entries found in both HashSets
|
||||
inline void operator&=(const HashSet<Key, Hash>& rhs);
|
||||
inline void operator&=(const this_type& rhs);
|
||||
|
||||
//- Only retain unique entries (xor)
|
||||
void operator^=(const HashSet<Key, Hash>& rhs);
|
||||
void operator^=(const this_type& rhs);
|
||||
|
||||
//- Add entries listed in the given HashSet to this HashSet
|
||||
inline void operator+=(const HashSet<Key, Hash>& rhs)
|
||||
inline void operator+=(const this_type& rhs)
|
||||
{
|
||||
this->operator|=(rhs);
|
||||
}
|
||||
|
||||
//- Remove entries listed in the given HashSet from this HashSet
|
||||
inline void operator-=(const HashSet<Key, Hash>& rhs);
|
||||
inline void operator-=(const this_type& rhs);
|
||||
|
||||
|
||||
// IOstream Operator
|
||||
|
||||
@ -61,21 +61,27 @@ Foam::label Foam::HashTable<T, Key, Hash>::eraseMultiple
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashTable<T, Key, Hash>::HashTable()
|
||||
:
|
||||
HashTable<T, Key, Hash>(128)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashTable<T, Key, Hash>::HashTable(const label size)
|
||||
:
|
||||
HashTableCore(),
|
||||
nElmts_(0),
|
||||
tableSize_(HashTableCore::canonicalSize(size)),
|
||||
size_(0),
|
||||
capacity_(HashTableCore::canonicalSize(size)),
|
||||
table_(nullptr)
|
||||
{
|
||||
if (tableSize_)
|
||||
if (capacity_)
|
||||
{
|
||||
table_ = new hashedEntry*[tableSize_];
|
||||
|
||||
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
|
||||
table_ = new node_type*[capacity_];
|
||||
for (label i=0; i < capacity_; ++i)
|
||||
{
|
||||
table_[hashIdx] = nullptr;
|
||||
table_[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,7 +90,7 @@ Foam::HashTable<T, Key, Hash>::HashTable(const label size)
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
|
||||
:
|
||||
HashTable<T, Key, Hash>(ht.tableSize_)
|
||||
HashTable<T, Key, Hash>(ht.capacity_)
|
||||
{
|
||||
for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
|
||||
{
|
||||
@ -96,10 +102,7 @@ Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::HashTable<T, Key, Hash>::HashTable(HashTable<T, Key, Hash>&& ht)
|
||||
:
|
||||
HashTableCore(),
|
||||
nElmts_(0),
|
||||
tableSize_(0),
|
||||
table_(nullptr)
|
||||
HashTable<T, Key, Hash>(0)
|
||||
{
|
||||
transfer(ht);
|
||||
}
|
||||
@ -111,10 +114,7 @@ Foam::HashTable<T, Key, Hash>::HashTable
|
||||
const Xfer<HashTable<T, Key, Hash>>& ht
|
||||
)
|
||||
:
|
||||
HashTableCore(),
|
||||
nElmts_(0),
|
||||
tableSize_(0),
|
||||
table_(nullptr)
|
||||
HashTable<T, Key, Hash>(0)
|
||||
{
|
||||
transfer(ht());
|
||||
}
|
||||
@ -150,110 +150,10 @@ Foam::HashTable<T, Key, Hash>::~HashTable()
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
|
||||
{
|
||||
if (nElmts_)
|
||||
{
|
||||
const label hashIdx = hashKeyIndex(key);
|
||||
|
||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||
{
|
||||
if (key == ep->key_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
{
|
||||
InfoInFunction << "Entry " << key << " not found in hash table\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
typename Foam::HashTable<T, Key, Hash>::iterator
|
||||
Foam::HashTable<T, Key, Hash>::find
|
||||
(
|
||||
const Key& key
|
||||
)
|
||||
{
|
||||
if (nElmts_)
|
||||
{
|
||||
const label hashIdx = hashKeyIndex(key);
|
||||
|
||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||
{
|
||||
if (key == ep->key_)
|
||||
{
|
||||
return iterator(this, ep, hashIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
{
|
||||
InfoInFunction << "Entry " << key << " not found in hash table\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
return iterator();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::find
|
||||
(
|
||||
const Key& key
|
||||
) const
|
||||
{
|
||||
return this->cfind(key);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::cfind
|
||||
(
|
||||
const Key& key
|
||||
) const
|
||||
{
|
||||
if (nElmts_)
|
||||
{
|
||||
const label hashIdx = hashKeyIndex(key);
|
||||
|
||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||
{
|
||||
if (key == ep->key_)
|
||||
{
|
||||
return const_iterator(this, ep, hashIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
{
|
||||
InfoInFunction << "Entry " << key << " not found in hash table\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
|
||||
{
|
||||
List<Key> keyLst(nElmts_);
|
||||
List<Key> keyLst(size_);
|
||||
label count = 0;
|
||||
|
||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||
@ -297,7 +197,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocKeys
|
||||
const bool invert
|
||||
) const
|
||||
{
|
||||
List<Key> keyLst(nElmts_);
|
||||
List<Key> keyLst(size_);
|
||||
label count = 0;
|
||||
|
||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||
@ -323,7 +223,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocValues
|
||||
const bool invert
|
||||
) const
|
||||
{
|
||||
List<Key> keyLst(nElmts_);
|
||||
List<Key> keyLst(size_);
|
||||
label count = 0;
|
||||
|
||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||
@ -349,7 +249,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocEntries
|
||||
const bool invert
|
||||
) const
|
||||
{
|
||||
List<Key> keyLst(nElmts_);
|
||||
List<Key> keyLst(size_);
|
||||
label count = 0;
|
||||
|
||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||
@ -438,36 +338,36 @@ bool Foam::HashTable<T, Key, Hash>::set
|
||||
(
|
||||
const Key& key,
|
||||
const T& obj,
|
||||
const bool protect
|
||||
const bool overwrite
|
||||
)
|
||||
{
|
||||
if (!tableSize_)
|
||||
if (!capacity_)
|
||||
{
|
||||
resize(2);
|
||||
}
|
||||
|
||||
const label hashIdx = hashKeyIndex(key);
|
||||
const label index = hashKeyIndex(key);
|
||||
|
||||
hashedEntry* existing = nullptr;
|
||||
hashedEntry* prev = nullptr;
|
||||
node_type* curr = nullptr;
|
||||
node_type* prev = nullptr;
|
||||
|
||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||
for (node_type* ep = table_[index]; ep; ep = ep->next_)
|
||||
{
|
||||
if (key == ep->key_)
|
||||
if (key == ep->key())
|
||||
{
|
||||
existing = ep;
|
||||
curr = ep;
|
||||
break;
|
||||
}
|
||||
prev = ep;
|
||||
}
|
||||
|
||||
if (!existing)
|
||||
if (!curr)
|
||||
{
|
||||
// Not found, insert it at the head
|
||||
table_[hashIdx] = new hashedEntry(key, obj, table_[hashIdx]);
|
||||
nElmts_++;
|
||||
table_[index] = new node_type(key, obj, table_[index]);
|
||||
++size_;
|
||||
|
||||
if (double(nElmts_)/tableSize_ > 0.8 && tableSize_ < maxTableSize)
|
||||
if (double(size_)/capacity_ > 0.8 && capacity_ < maxTableSize)
|
||||
{
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
@ -476,13 +376,35 @@ bool Foam::HashTable<T, Key, Hash>::set
|
||||
}
|
||||
#endif
|
||||
|
||||
resize(2*tableSize_);
|
||||
resize(2*capacity_);
|
||||
}
|
||||
}
|
||||
else if (protect)
|
||||
else if (overwrite)
|
||||
{
|
||||
// Found - but protected from overwriting
|
||||
// this corresponds to the STL 'insert' convention
|
||||
// Overwrite current entry (Perl convention).
|
||||
|
||||
node_type* ep = curr->next_; // next in the linked list
|
||||
|
||||
// In some cases the delete/new could be avoided in favour of move
|
||||
// assignment, but cannot be certain that all objects support this
|
||||
// or that it behaves the same as a copy construct.
|
||||
|
||||
delete curr;
|
||||
ep = new node_type(key, obj, ep);
|
||||
|
||||
// Replace current element - within list or insert at the head
|
||||
if (prev)
|
||||
{
|
||||
prev->next_ = ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
table_[index] = ep;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not overwrite existing entry (STL 'insert' convention)
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
{
|
||||
@ -492,99 +414,22 @@ bool Foam::HashTable<T, Key, Hash>::set
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found - overwrite existing entry
|
||||
// this corresponds to the Perl convention
|
||||
hashedEntry* ep = new hashedEntry(key, obj, existing->next_);
|
||||
|
||||
// Replace existing element - within list or insert at the head
|
||||
if (prev)
|
||||
{
|
||||
prev->next_ = ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
table_[hashIdx] = ep;
|
||||
}
|
||||
|
||||
delete existing;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
bool Foam::HashTable<T, Key, Hash>::iterator_base::erase()
|
||||
{
|
||||
// Note: entryPtr_ is nullptr for end(), so this catches that too
|
||||
if (entryPtr_)
|
||||
{
|
||||
// Search element before entryPtr_
|
||||
entry_type* prev = nullptr;
|
||||
|
||||
for
|
||||
(
|
||||
entry_type* ep = hashTable_->table_[hashIndex_];
|
||||
ep;
|
||||
ep = ep->next_
|
||||
)
|
||||
{
|
||||
if (ep == entryPtr_)
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev = ep;
|
||||
}
|
||||
|
||||
if (prev)
|
||||
{
|
||||
// Has an element before entryPtr - reposition to there
|
||||
prev->next_ = entryPtr_->next_;
|
||||
delete entryPtr_;
|
||||
entryPtr_ = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
// entryPtr was first element on SLList
|
||||
hashTable_->table_[hashIndex_] = entryPtr_->next_;
|
||||
delete entryPtr_;
|
||||
|
||||
// Assign any non-nullptr value so it doesn't look like end()
|
||||
entryPtr_ = reinterpret_cast<hashedEntry*>(this);
|
||||
|
||||
// Mark with special hashIndex value to signal it has been rewound.
|
||||
// The next increment will bring it back to the present location.
|
||||
//
|
||||
// From the current position 'curPos', we wish to continue at
|
||||
// prevPos='curPos-1', which we mark as markPos='-curPos-1'.
|
||||
// The negative lets us notice it is special, the extra '-1'
|
||||
// is needed to avoid ambiguity for position '0'.
|
||||
// To retrieve prevPos, we would later use '-(markPos+1) - 1'
|
||||
hashIndex_ = -hashIndex_ - 1;
|
||||
}
|
||||
|
||||
hashTable_->nElmts_--;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
|
||||
{
|
||||
// NOTE: We use (const iterator&) here, but manipulate its contents anyhow.
|
||||
// NOTE: we use (const iterator&) here, but treat its contents as mutable.
|
||||
//
|
||||
// The parameter should be (iterator&), but then the compiler doesn't find
|
||||
// it correctly and tries to call as (iterator) instead.
|
||||
//
|
||||
// Adjust iterator after erase
|
||||
return const_cast<iterator&>(iter).erase();
|
||||
|
||||
iterator& it = const_cast<iterator&>(iter);
|
||||
|
||||
return iterator_erase(it.entry_, it.index_);
|
||||
}
|
||||
|
||||
|
||||
@ -599,7 +444,7 @@ bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
|
||||
template<class T, class Key, class Hash>
|
||||
Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
|
||||
{
|
||||
return eraseMultiple(keys.begin(), keys.end());
|
||||
return eraseMultiple(keys.cbegin(), keys.cend());
|
||||
}
|
||||
|
||||
|
||||
@ -610,7 +455,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
|
||||
const FixedList<Key, Size>& keys
|
||||
)
|
||||
{
|
||||
return eraseMultiple(keys.begin(), keys.end());
|
||||
return eraseMultiple(keys.cbegin(), keys.cend());
|
||||
}
|
||||
|
||||
|
||||
@ -634,17 +479,14 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
|
||||
const label nTotal = this->size();
|
||||
label changed = 0;
|
||||
|
||||
using other_iter =
|
||||
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
|
||||
|
||||
if (other.size() <= nTotal)
|
||||
{
|
||||
// The other is smaller/same-size, use its keys for removal
|
||||
|
||||
for
|
||||
(
|
||||
other_iter iter = other.begin();
|
||||
changed < nTotal && iter != other.end(); // terminate early
|
||||
auto iter = other.cbegin();
|
||||
changed < nTotal && iter != other.cend(); // Terminate early
|
||||
++iter
|
||||
)
|
||||
{
|
||||
@ -660,7 +502,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
|
||||
for
|
||||
(
|
||||
iterator iter = begin();
|
||||
changed < nTotal && iter != end(); // terminate early
|
||||
changed < nTotal && iter != end(); // Terminate early
|
||||
++iter
|
||||
)
|
||||
{
|
||||
@ -711,9 +553,10 @@ Foam::label Foam::HashTable<T, Key, Hash>::retain
|
||||
template<class T, class Key, class Hash>
|
||||
void Foam::HashTable<T, Key, Hash>::resize(const label sz)
|
||||
{
|
||||
const label newSize = HashTableCore::canonicalSize(sz);
|
||||
const label newCapacity = HashTableCore::canonicalSize(sz);
|
||||
const label oldCapacity = capacity_;
|
||||
|
||||
if (newSize == tableSize_)
|
||||
if (newCapacity == oldCapacity)
|
||||
{
|
||||
#ifdef FULLDEBUG
|
||||
if (debug)
|
||||
@ -724,46 +567,85 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HashTable<T, Key, Hash>* tmpTable = new HashTable<T, Key, Hash>(newSize);
|
||||
|
||||
for (const_iterator iter = cbegin(); iter != cend(); ++iter)
|
||||
else if (!newCapacity)
|
||||
{
|
||||
tmpTable->insert(iter.key(), iter.object());
|
||||
// Special treatment for resize(0)
|
||||
if (size_)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "HashTable contains " << size_ << " cannot resize(0)"
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (table_)
|
||||
{
|
||||
delete[] table_;
|
||||
capacity_ = 0;
|
||||
}
|
||||
|
||||
table_ = nullptr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const label oldSize = tableSize_;
|
||||
tableSize_ = tmpTable->tableSize_;
|
||||
tmpTable->tableSize_ = oldSize;
|
||||
// Swap primary table entries: size_ is left untouched
|
||||
|
||||
hashedEntry** oldTable = table_;
|
||||
table_ = tmpTable->table_;
|
||||
tmpTable->table_ = oldTable;
|
||||
auto oldTable = table_;
|
||||
capacity_ = newCapacity;
|
||||
|
||||
delete tmpTable;
|
||||
table_ = new node_type*[capacity_];
|
||||
for (label i=0; i < capacity_; ++i)
|
||||
{
|
||||
table_[i] = nullptr;
|
||||
}
|
||||
|
||||
// Move to new table[] but with new chaining.
|
||||
|
||||
label nMove = size_; // Allow early completion
|
||||
for (label i=0; nMove && i < oldCapacity; ++i)
|
||||
{
|
||||
for (node_type* ep = oldTable[i]; ep; /*nil*/)
|
||||
{
|
||||
node_type* next = ep->next_;
|
||||
|
||||
// Move to new location
|
||||
{
|
||||
const label newIdx = hashKeyIndex(ep->key());
|
||||
|
||||
ep->next_ = table_[newIdx]; // add to head
|
||||
table_[newIdx] = ep;
|
||||
}
|
||||
|
||||
ep = next; // continue in the linked-list
|
||||
--nMove; // note any early completion
|
||||
}
|
||||
oldTable[i] = nullptr;
|
||||
}
|
||||
|
||||
if (oldTable)
|
||||
{
|
||||
delete[] oldTable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
void Foam::HashTable<T, Key, Hash>::clear()
|
||||
{
|
||||
if (nElmts_)
|
||||
for (label i=0; size_ && i<capacity_; ++i)
|
||||
{
|
||||
for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
|
||||
for (node_type* ep = table_[i]; ep; /*nil*/)
|
||||
{
|
||||
if (table_[hashIdx])
|
||||
{
|
||||
hashedEntry* ep = table_[hashIdx];
|
||||
while (hashedEntry* next = ep->next_)
|
||||
{
|
||||
delete ep;
|
||||
ep = next;
|
||||
}
|
||||
delete ep;
|
||||
table_[hashIdx] = nullptr;
|
||||
}
|
||||
node_type* next = ep->next_;
|
||||
|
||||
delete ep;
|
||||
|
||||
ep = next; // continue in the linked-list
|
||||
--size_; // note any early completion
|
||||
}
|
||||
nElmts_ = 0;
|
||||
table_[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -779,30 +661,31 @@ void Foam::HashTable<T, Key, Hash>::clearStorage()
|
||||
template<class T, class Key, class Hash>
|
||||
void Foam::HashTable<T, Key, Hash>::swap(HashTable<T, Key, Hash>& ht)
|
||||
{
|
||||
Foam::Swap(table_, ht.table_);
|
||||
Foam::Swap(tableSize_, ht.tableSize_);
|
||||
Foam::Swap(nElmts_, ht.nElmts_);
|
||||
Foam::Swap(size_, ht.size_);
|
||||
Foam::Swap(capacity_, ht.capacity_);
|
||||
Foam::Swap(table_, ht.table_);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
|
||||
{
|
||||
// As per the Destructor
|
||||
// As per destructor
|
||||
if (table_)
|
||||
{
|
||||
clear();
|
||||
delete[] table_;
|
||||
}
|
||||
|
||||
tableSize_ = ht.tableSize_;
|
||||
ht.tableSize_ = 0;
|
||||
size_ = ht.size_;
|
||||
ht.size_ = 0;
|
||||
|
||||
capacity_ = ht.capacity_;
|
||||
ht.capacity_ = 0;
|
||||
|
||||
table_ = ht.table_;
|
||||
ht.table_ = nullptr;
|
||||
|
||||
nElmts_ = ht.nElmts_;
|
||||
ht.nElmts_ = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -904,9 +787,9 @@ void Foam::HashTable<T, Key, Hash>::operator=
|
||||
}
|
||||
|
||||
// Could be zero-sized from a previous transfer()
|
||||
if (!tableSize_)
|
||||
if (!capacity_)
|
||||
{
|
||||
resize(rhs.tableSize_);
|
||||
resize(rhs.capacity_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -927,7 +810,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
|
||||
)
|
||||
{
|
||||
// Could be zero-sized from a previous transfer()
|
||||
if (!tableSize_)
|
||||
if (!capacity_)
|
||||
{
|
||||
resize(2*lst.size());
|
||||
}
|
||||
@ -975,7 +858,7 @@ bool Foam::HashTable<T, Key, Hash>::operator==
|
||||
|
||||
for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
|
||||
{
|
||||
const_iterator other = this->cfind(iter.key());
|
||||
const const_iterator other(this->cfind(iter.key()));
|
||||
|
||||
if (!other.found() || other.object() != iter.object())
|
||||
{
|
||||
@ -997,8 +880,11 @@ bool Foam::HashTable<T, Key, Hash>::operator!=
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Iterators, Friend Operators
|
||||
|
||||
#include "HashTableIter.C"
|
||||
#include "HashTableIO.C"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -25,14 +25,15 @@ Class
|
||||
Foam::HashTable
|
||||
|
||||
Description
|
||||
An STL-conforming hash table.
|
||||
A HashTable similar to \c std::unordered_map.
|
||||
The entries are considered \a unordered since their placement
|
||||
depends on the method used to generate the hash key index, the
|
||||
table capacity, insertion order etc. When the key order is
|
||||
important, use the sortedToc() method to obtain a list of sorted
|
||||
keys and use that for further access.
|
||||
|
||||
Note
|
||||
Hashing index collisions are handled via chaining using a singly-linked
|
||||
list with the colliding entry being added to the head of the linked
|
||||
list. Thus copying the hash table (or indeed even resizing it) will
|
||||
often result in a different hash order. Use a sorted table-of-contents
|
||||
when the hash order is important.
|
||||
Internally the table uses closed addressing into a flat storage space
|
||||
with collisions handled by linked-list chaining.
|
||||
|
||||
The end iterator of all hash-tables has a nullptr to the hash entry.
|
||||
Thus avoid separate allocation for each table and use a single one with
|
||||
@ -41,10 +42,38 @@ Note
|
||||
a nullptr as its first data member.
|
||||
The nullObject is such an item (with a nullptr data member).
|
||||
|
||||
Note
|
||||
For historical reasons, dereferencing the table iterator
|
||||
(eg, \a *iter) returns a reference to the stored object value
|
||||
value rather than the stored key/object value like std::unordered_map
|
||||
does.
|
||||
|
||||
The HashTable iterator:
|
||||
\code
|
||||
forAllConstIters(table, iter)
|
||||
{
|
||||
Info<< "val:" << *iter << nl
|
||||
<< "key:" << iter.key() << nl;
|
||||
<< "val:" << iter.object() << nl;
|
||||
}
|
||||
\endcode
|
||||
whereas for the \c std::unordered_map iterator:
|
||||
\code
|
||||
forAllConstIters(stdmap, iter)
|
||||
{
|
||||
Info<< "key/val:" << *iter << nl
|
||||
<< "key:" << iter->first << nl
|
||||
<< "val:" << iter->second << nl;
|
||||
}
|
||||
\endcode
|
||||
This difference is most evident when using range-for syntax.
|
||||
|
||||
SourceFiles
|
||||
HashTableI.H
|
||||
HashTableIterI.H
|
||||
HashTable.C
|
||||
HashTableIO.C
|
||||
HashTableIter.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -52,6 +81,7 @@ SourceFiles
|
||||
#define HashTable_H
|
||||
|
||||
#include "word.H"
|
||||
#include "zero.H"
|
||||
#include "Xfer.H"
|
||||
#include "Hash.H"
|
||||
#include "HashTableCore.H"
|
||||
@ -80,7 +110,7 @@ Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class HashTable Declaration
|
||||
Class HashTable Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
template<class T, class Key=word, class Hash=string::hash>
|
||||
@ -88,6 +118,140 @@ class HashTable
|
||||
:
|
||||
public HashTableCore
|
||||
{
|
||||
// Private types for table entries
|
||||
|
||||
//- Structure with a (K,V) tuple and a linked-list for collisions
|
||||
// Could store key/object as std::pair, but no particular advantage
|
||||
// unless the iterator dereference type changes.
|
||||
struct pair_entry
|
||||
{
|
||||
//- Type of key
|
||||
typedef Key key_type;
|
||||
|
||||
//- Object content type
|
||||
typedef T mapped_type;
|
||||
|
||||
//- The lookup key
|
||||
key_type key_;
|
||||
|
||||
//- The data object
|
||||
mapped_type obj_;
|
||||
|
||||
//- Addressing (next in collision list)
|
||||
pair_entry* next_;
|
||||
|
||||
//- Construct from key, object, next pointer
|
||||
pair_entry(const Key& key, const T& obj, pair_entry* next)
|
||||
:
|
||||
key_(key),
|
||||
obj_(obj),
|
||||
next_(next)
|
||||
{}
|
||||
|
||||
//- The key
|
||||
const key_type& key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
//- The mapped object
|
||||
const mapped_type& mapped() const
|
||||
{
|
||||
return obj_;
|
||||
}
|
||||
mapped_type& mapped()
|
||||
{
|
||||
return obj_;
|
||||
}
|
||||
|
||||
private:
|
||||
//- Disallow default bitwise copy construct / assignment
|
||||
pair_entry(const pair_entry&) = delete;
|
||||
void operator=(const pair_entry&) = delete;
|
||||
};
|
||||
|
||||
|
||||
//- Structure with a single (K) value and a linked-list for collisions
|
||||
struct unary_entry
|
||||
{
|
||||
//- Type of key
|
||||
typedef Key key_type;
|
||||
|
||||
//- Object content type
|
||||
typedef zero::null mapped_type;
|
||||
|
||||
//- Content storage type to the entry
|
||||
typedef key_type value_type;
|
||||
|
||||
//- The lookup key == content
|
||||
key_type key_;
|
||||
|
||||
//- Addressing (next in collision list)
|
||||
unary_entry* next_;
|
||||
|
||||
//- Construct from key, (ununsed) object, next pointer
|
||||
unary_entry(const Key& key, const T&, unary_entry* next)
|
||||
:
|
||||
key_(key),
|
||||
next_(next)
|
||||
{}
|
||||
|
||||
//- The key
|
||||
const key_type& key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
//- Dummy mapped object
|
||||
const mapped_type& mapped() const
|
||||
{
|
||||
return zeroNullElement;
|
||||
}
|
||||
mapped_type& mapped()
|
||||
{
|
||||
return zeroNullElement;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//- Disallow default bitwise copy construct / assignment
|
||||
unary_entry(const unary_entry&) = delete;
|
||||
void operator=(const unary_entry&) = delete;
|
||||
};
|
||||
|
||||
|
||||
//- Hashed node with a linked-list for collisions
|
||||
typedef typename std::conditional
|
||||
<
|
||||
std::is_same<zero::null, typename std::remove_cv<T>::type>::value,
|
||||
unary_entry,
|
||||
pair_entry
|
||||
>::type node_type;
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- The number of nodes currently stored in table
|
||||
label size_;
|
||||
|
||||
//- Number of nodes allocated in table
|
||||
label capacity_;
|
||||
|
||||
//- The table of primary nodes
|
||||
node_type** table_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Return the hash index of the Key within the current table size.
|
||||
// No checks for zero-sized tables.
|
||||
inline label hashKeyIndex(const Key& key) const;
|
||||
|
||||
//- Assign a new hash-entry to a possibly already existing key.
|
||||
// \return True if the new entry was set.
|
||||
bool set(const Key& key, const T& obj, const bool overwrite);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- The template instance used for this HashTable
|
||||
@ -96,18 +260,25 @@ public:
|
||||
|
||||
// STL type definitions
|
||||
|
||||
//- Type of keys that the HashTable uses.
|
||||
//- The second template parameter, type of keys used.
|
||||
typedef Key key_type;
|
||||
|
||||
//- Type of values that the HashTable contains.
|
||||
//- The first template parameter, type of objects contained.
|
||||
typedef T mapped_type;
|
||||
|
||||
//- Same as mapped_type for OpenFOAM HashTables
|
||||
// Note that this is different than the std::map definition.
|
||||
typedef T value_type;
|
||||
|
||||
//- The third template parameter, the hash index method.
|
||||
typedef Hash hasher;
|
||||
|
||||
//- The type used for storing into value_type objects.
|
||||
// This type is usually value_type&.
|
||||
// This type is usually 'value_type*'.
|
||||
typedef T* pointer;
|
||||
|
||||
//- The type used for storing into value_type objects.
|
||||
// This type is usually value_type&.
|
||||
// This type is usually 'value_type&'.
|
||||
typedef T& reference;
|
||||
|
||||
//- The type used for reading from constant value_type objects.
|
||||
@ -129,65 +300,14 @@ public:
|
||||
//- Forward iterator with const access
|
||||
class const_iterator;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Private data type for table entries
|
||||
|
||||
//- Structure to hold a hashed entry, with a linked-list for collisions
|
||||
struct hashedEntry
|
||||
{
|
||||
//- The lookup key
|
||||
Key key_;
|
||||
|
||||
//- The data object
|
||||
T obj_;
|
||||
|
||||
//- Pointer to next hashedEntry in sub-list
|
||||
hashedEntry* next_;
|
||||
|
||||
//- Construct from key, object, next pointer
|
||||
inline hashedEntry(const Key& key, const T& obj, hashedEntry* next);
|
||||
|
||||
private:
|
||||
//- Disallow default bitwise copy construct
|
||||
hashedEntry(const hashedEntry&) = delete;
|
||||
|
||||
//- Disallow default bitwise assignment
|
||||
void operator=(const hashedEntry&) = delete;
|
||||
};
|
||||
|
||||
|
||||
// Private data: size of table, the table and current number of elements
|
||||
|
||||
//- The current number of elements in table
|
||||
label nElmts_;
|
||||
|
||||
//- Number of primary entries allocated in table
|
||||
label tableSize_;
|
||||
|
||||
//- The table of primary entries
|
||||
hashedEntry** table_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Return the hash index of the Key within the current table size.
|
||||
// No checks for zero-sized tables.
|
||||
inline label hashKeyIndex(const Key& key) const;
|
||||
|
||||
//- Assign a new hash-entry to a possibly already existing key.
|
||||
// \return True if the new entry was set.
|
||||
bool set(const Key& key, const T& obj, const bool protect);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
//- Internally used base for iterator and const_iterator
|
||||
class iterator_base;
|
||||
template<bool Const> class Iterator;
|
||||
|
||||
//- Friendship with the iterator_base is required.
|
||||
friend class iterator_base;
|
||||
//- Friendship with the base iterator is required.
|
||||
friend class Iterator<true>;
|
||||
friend class Iterator<false>;
|
||||
|
||||
|
||||
// Protected Member Functions
|
||||
@ -205,20 +325,23 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct given initial table size
|
||||
HashTable(const label size = 128);
|
||||
//- Construct null with default (128) table size
|
||||
HashTable();
|
||||
|
||||
//- Construct from Istream
|
||||
//- Construct given initial table size
|
||||
explicit HashTable(const label size);
|
||||
|
||||
//- Construct from Istream with default table size
|
||||
HashTable(Istream& is, const label size = 128);
|
||||
|
||||
//- Construct as copy
|
||||
HashTable(const HashTable<T, Key, Hash>& ht);
|
||||
HashTable(const this_type& ht);
|
||||
|
||||
//- Move construct
|
||||
HashTable(HashTable<T, Key, Hash>&& ht);
|
||||
HashTable(this_type&& ht);
|
||||
|
||||
//- Construct by transferring the parameter contents
|
||||
HashTable(const Xfer<HashTable<T, Key, Hash>>& ht);
|
||||
HashTable(const Xfer<this_type>& ht);
|
||||
|
||||
//- Construct from an initializer list
|
||||
HashTable(std::initializer_list<std::pair<Key, T>> lst);
|
||||
@ -242,19 +365,19 @@ public:
|
||||
inline bool empty() const;
|
||||
|
||||
//- Return true if hashed entry is found in table
|
||||
bool found(const Key& key) const;
|
||||
inline bool found(const Key& key) const;
|
||||
|
||||
//- Find and return an iterator set at the hashed entry
|
||||
// If not found iterator = end()
|
||||
iterator find(const Key& key);
|
||||
inline iterator find(const Key& key);
|
||||
|
||||
//- Find and return an const_iterator set at the hashed entry
|
||||
// If not found iterator = end()
|
||||
const_iterator find(const Key& key) const;
|
||||
inline const_iterator find(const Key& key) const;
|
||||
|
||||
//- Find and return an const_iterator set at the hashed entry
|
||||
// If not found iterator = end()
|
||||
const_iterator cfind(const Key& key) const;
|
||||
inline const_iterator cfind(const Key& key) const;
|
||||
|
||||
//- Return hashed entry if it exists, or return the given default
|
||||
inline const T& lookup(const Key& key, const T& deflt) const;
|
||||
@ -512,149 +635,157 @@ protected:
|
||||
// and prevent most external usage.
|
||||
// iterator and const_iterator have the same size, allowing
|
||||
// us to reinterpret_cast between them (if desired)
|
||||
class iterator_base
|
||||
|
||||
template<bool Const>
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
// Public typedefs
|
||||
using table_type = this_type;
|
||||
using key_type = this_type::key_type;
|
||||
// Typedefs
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = this_type::difference_type;
|
||||
using difference_type = this_type::difference_type;
|
||||
|
||||
private:
|
||||
using entry_type = hashedEntry;
|
||||
//- The HashTable container type
|
||||
using table_type = typename std::conditional
|
||||
<
|
||||
Const,
|
||||
const this_type,
|
||||
this_type
|
||||
>::type;
|
||||
|
||||
// Private Data
|
||||
//- The node-type being addressed
|
||||
using node_type = typename std::conditional
|
||||
<
|
||||
Const,
|
||||
const this_type::node_type,
|
||||
this_type::node_type
|
||||
>::type;
|
||||
|
||||
//- Currently selected entry.
|
||||
// MUST be the first member for easy comparison between iterators
|
||||
// and for reinterpret_cast from nullObject
|
||||
entry_type* entryPtr_;
|
||||
//- The key type
|
||||
using key_type = this_type::key_type;
|
||||
|
||||
//- Pointer to the hash-table for which this is an iterator
|
||||
// This allows use of the default bitwise copy/assignment
|
||||
table_type* hashTable_;
|
||||
//- The object type being addressed
|
||||
using mapped_type = typename std::conditional
|
||||
<
|
||||
Const,
|
||||
const this_type::mapped_type,
|
||||
this_type::mapped_type
|
||||
>::type;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- True if iterator points to an entry
|
||||
// This can be used directly instead of comparing to end()
|
||||
inline bool found() const;
|
||||
|
||||
//- The key associated with the iterator
|
||||
inline const Key& key() const;
|
||||
|
||||
// Member Operators
|
||||
|
||||
//- Compare hash-entry element pointers.
|
||||
// Independent of const/non-const access
|
||||
inline bool operator==(const Iterator<true>& iter) const;
|
||||
inline bool operator!=(const Iterator<true>& iter) const;
|
||||
|
||||
inline bool operator==(const Iterator<false>& iter) const;
|
||||
inline bool operator!=(const Iterator<false>& iter) const;
|
||||
|
||||
//- Current hash index within the hash-table data.
|
||||
// A signed value, since erase() uses a negative value to signal
|
||||
// the erasure state.
|
||||
label hashIndex_;
|
||||
|
||||
protected:
|
||||
friend class HashTable; // For begin/find constructors
|
||||
|
||||
// Protected Data
|
||||
|
||||
//- The selected entry.
|
||||
// MUST be the first member for easy comparison between iterators
|
||||
// and for reinterpret_cast from nullObject
|
||||
node_type* entry_;
|
||||
|
||||
//- The hash-table container being iterated on.
|
||||
// Using a pointer allows default bitwise copy/assignment
|
||||
table_type* container_;
|
||||
|
||||
//- Index within the hash-table data.
|
||||
// A signed value, since iterator_erase() needs a negative value
|
||||
// to mark the position.
|
||||
label index_;
|
||||
|
||||
|
||||
// Protected Constructors
|
||||
|
||||
//- Construct null (end iterator)
|
||||
inline Iterator();
|
||||
|
||||
//- Construct from begin of hash-table
|
||||
inline Iterator(bool, table_type* tbl);
|
||||
|
||||
//- Construct by finding key in hash table
|
||||
inline Iterator(table_type* tbl, const Key& key);
|
||||
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Increment to the next position
|
||||
inline void increment();
|
||||
|
||||
//- The referenced object/value element
|
||||
inline T& element() const;
|
||||
//- The object associated with the iterator
|
||||
inline mapped_type& object() const
|
||||
{
|
||||
return entry_->mapped();
|
||||
}
|
||||
|
||||
//- Erase the entry at the current position
|
||||
bool erase();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null (end iterator)
|
||||
inline iterator_base();
|
||||
|
||||
//- Construct from begin of hash-table
|
||||
inline explicit iterator_base(const table_type* hashTbl);
|
||||
|
||||
//- Construct from hash table, element and hash index
|
||||
inline iterator_base
|
||||
(
|
||||
const table_type* hashTbl,
|
||||
const entry_type* elmt,
|
||||
const label hashIndex
|
||||
);
|
||||
|
||||
// Member functions/operators
|
||||
|
||||
//- True if iterator points to an entry
|
||||
// This can be used directly instead of comparing to end()
|
||||
inline bool found() const;
|
||||
|
||||
//- Return the Key corresponding to the iterator
|
||||
inline const Key& key() const;
|
||||
|
||||
//- Compare hash-entry element pointers
|
||||
inline bool operator==(const iterator_base& iter) const;
|
||||
inline bool operator!=(const iterator_base& iter) const;
|
||||
//- Permit an explicit cast to the other (const/non-const) searcher
|
||||
inline explicit operator const Iterator<!Const>&() const
|
||||
{
|
||||
return *reinterpret_cast<const Iterator<!Const>*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Low-level entry erasure using iterator internals.
|
||||
// This invalidates the iterator until the next ++ operation.
|
||||
// \return True if the corresponding entry existed and was removed
|
||||
bool iterator_erase(node_type*& entry, label& index);
|
||||
|
||||
public:
|
||||
|
||||
//- An iterator wrapper for returning a reference to the key
|
||||
template<class WrappedIterator>
|
||||
class key_iterator_base
|
||||
:
|
||||
public WrappedIterator
|
||||
{
|
||||
public:
|
||||
using value_type = this_type::key_type;
|
||||
using pointer = const Key*;
|
||||
using reference = const Key&;
|
||||
|
||||
//- Implicit conversion
|
||||
inline key_iterator_base(const WrappedIterator& iter);
|
||||
|
||||
//- Return the key
|
||||
inline reference operator*() const;
|
||||
inline reference operator()() const;
|
||||
|
||||
inline key_iterator_base& operator++();
|
||||
inline key_iterator_base operator++(int);
|
||||
};
|
||||
|
||||
|
||||
// STL iterator
|
||||
|
||||
//- Forward iterator with non-const access
|
||||
class iterator
|
||||
:
|
||||
public iterator_base
|
||||
public Iterator<false>
|
||||
{
|
||||
friend class HashTable; // Uses iterator::erase() method
|
||||
using entry_type = hashedEntry;
|
||||
|
||||
public:
|
||||
// Typedefs
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = this_type::difference_type;
|
||||
|
||||
// Public typedefs
|
||||
using table_type = this_type;
|
||||
using value_type = this_type::value_type;
|
||||
using pointer = this_type::pointer;
|
||||
using reference = this_type::reference;
|
||||
using key_type = this_type::key_type;
|
||||
using mapped_type = this_type::mapped_type;
|
||||
using value_type = this_type::value_type;
|
||||
using pointer = this_type::pointer;
|
||||
using reference = this_type::reference;
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null (end iterator)
|
||||
inline iterator();
|
||||
inline iterator() {}
|
||||
|
||||
//- Construct from begin of hash-table
|
||||
inline explicit iterator(table_type* hashTbl);
|
||||
//- Copy construct from similar access type
|
||||
inline explicit iterator(const Iterator<false>& iter)
|
||||
:
|
||||
Iterator<false>(iter)
|
||||
{}
|
||||
|
||||
//- Construct from hash table, element and hash index
|
||||
// Used by the hash-table find() method.
|
||||
inline iterator
|
||||
(
|
||||
table_type* hashTbl,
|
||||
entry_type* elmt,
|
||||
const label hashIndex
|
||||
);
|
||||
|
||||
// Member functions/operators
|
||||
|
||||
//- Return non-const access to referenced object
|
||||
inline reference object() const;
|
||||
//- Non-const access to referenced object
|
||||
using Iterator<false>::object;
|
||||
|
||||
//- Return non-const access to referenced object
|
||||
inline reference operator*() const;
|
||||
inline reference operator()() const;
|
||||
//- Non-const access to referenced object
|
||||
inline reference operator*() const { return this->object(); }
|
||||
inline reference operator()() const { return this->object(); }
|
||||
|
||||
inline iterator& operator++();
|
||||
inline iterator operator++(int);
|
||||
@ -666,54 +797,111 @@ public:
|
||||
//- Forward iterator with const access
|
||||
class const_iterator
|
||||
:
|
||||
public iterator_base
|
||||
public Iterator<true>
|
||||
{
|
||||
using entry_type = const hashedEntry;
|
||||
|
||||
public:
|
||||
// Typedefs
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = this_type::difference_type;
|
||||
|
||||
// Public typedefs
|
||||
using table_type = const this_type;
|
||||
using value_type = const this_type::value_type;
|
||||
using pointer = this_type::const_pointer;
|
||||
using reference = this_type::const_reference;
|
||||
using key_type = this_type::key_type;
|
||||
using mapped_type = const this_type::mapped_type;
|
||||
using value_type = const this_type::value_type;
|
||||
using pointer = this_type::const_pointer;
|
||||
using reference = this_type::const_reference;
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null (end iterator)
|
||||
inline const_iterator();
|
||||
inline const_iterator() {}
|
||||
|
||||
//- Construct from begin of hash-table
|
||||
inline explicit const_iterator(table_type* hashTbl);
|
||||
//- Copy construct from similar access type
|
||||
inline explicit const_iterator(const Iterator<true>& iter)
|
||||
:
|
||||
Iterator<true>(iter)
|
||||
{}
|
||||
|
||||
//- Construct from hash table, element and hash index.
|
||||
// Used by the hash-table find() method.
|
||||
inline const_iterator
|
||||
(
|
||||
table_type* hashTbl,
|
||||
entry_type* elmt,
|
||||
const label hashIndex
|
||||
);
|
||||
//- Copy construct from dissimilar access type
|
||||
inline explicit const_iterator(const Iterator<false>& iter)
|
||||
:
|
||||
Iterator<true>
|
||||
(
|
||||
static_cast<const Iterator<true>&>(iter)
|
||||
)
|
||||
{}
|
||||
|
||||
//- Implicit conversion from dissimilar access type
|
||||
inline const_iterator(const iterator& iter)
|
||||
:
|
||||
const_iterator(reinterpret_cast<const const_iterator&>(iter))
|
||||
{}
|
||||
|
||||
//- Copy construct from iterator
|
||||
inline const_iterator(const iterator& iter);
|
||||
|
||||
// Member functions/operators
|
||||
|
||||
//- Return const access to referenced object
|
||||
inline reference object() const;
|
||||
//- Const access to referenced object
|
||||
using Iterator<true>::object;
|
||||
|
||||
//- Return const access to referenced object
|
||||
inline reference operator*() const;
|
||||
inline reference operator()() const;
|
||||
//- Const access to referenced object
|
||||
inline reference operator*() const { return this->object(); }
|
||||
inline reference operator()() const { return this->object(); }
|
||||
|
||||
inline const_iterator& operator++();
|
||||
inline const_iterator operator++(int);
|
||||
|
||||
// Assignment
|
||||
|
||||
const_iterator& operator=(const const_iterator&) = default;
|
||||
|
||||
// Allow assign from iterator to const_iterator
|
||||
const_iterator& operator=(const iterator& iter)
|
||||
{
|
||||
return this->operator=
|
||||
(
|
||||
reinterpret_cast<const const_iterator&>(iter)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Iterating over keys only
|
||||
|
||||
//- An iterator wrapper for returning a reference to the key
|
||||
template<class Iter>
|
||||
class key_iterator_base
|
||||
:
|
||||
public Iter
|
||||
{
|
||||
public:
|
||||
using value_type = this_type::key_type;
|
||||
using pointer = const Key*;
|
||||
using reference = const Key&;
|
||||
|
||||
//- Implicit conversion
|
||||
inline key_iterator_base(const Iter& iter)
|
||||
:
|
||||
Iter(iter)
|
||||
{}
|
||||
|
||||
//- Return the key
|
||||
inline reference operator*() const { return this->key(); }
|
||||
inline reference operator()() const { return this->key(); }
|
||||
|
||||
inline key_iterator_base& operator++()
|
||||
{
|
||||
this->increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline key_iterator_base operator++(int)
|
||||
{
|
||||
key_iterator_base iter(*this);
|
||||
this->increment();
|
||||
return iter;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Forward iterator returning the key
|
||||
using key_iterator = key_iterator_base<iterator>;
|
||||
|
||||
@ -793,6 +981,7 @@ inline void Swap
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "HashTableI.H"
|
||||
#include "HashTableIterI.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
|
||||
@ -36,6 +36,8 @@ defineTypeNameAndDebug(HashTableCore, 0);
|
||||
// Approximately labelMax/4
|
||||
const Foam::label Foam::HashTableCore::maxTableSize(1L << (sizeof(label)*8-3));
|
||||
|
||||
Foam::zero::null Foam::HashTableCore::zeroNullElement;
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||
|
||||
@ -50,7 +52,7 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
|
||||
return maxTableSize;
|
||||
}
|
||||
|
||||
// Enforce power of two - makes for a very fast modulus.
|
||||
// Enforce power of two for fast modulus in hash index calculations.
|
||||
// Use unsigned for these calculations.
|
||||
//
|
||||
// - The lower limit (8) is somewhat arbitrary, but if the hash table
|
||||
@ -65,7 +67,8 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
|
||||
{
|
||||
return powerOfTwo;
|
||||
}
|
||||
else if (size & (size-1)) // <- Modulus of i^2
|
||||
|
||||
if (size & (size-1)) // <- Modulus of i^2
|
||||
{
|
||||
// Determine power-of-two. Brute-force is fast enough.
|
||||
while (powerOfTwo < size)
|
||||
@ -75,10 +78,8 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
|
||||
|
||||
return powerOfTwo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ SourceFiles
|
||||
#include "uLabel.H"
|
||||
#include "className.H"
|
||||
#include "nullObject.H"
|
||||
#include "zero.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -77,20 +78,16 @@ struct HashTableCore
|
||||
template<class IteratorType, class TableType>
|
||||
inline static IteratorType iterator_begin(TableType& table);
|
||||
|
||||
//- Factory method to create a const iterator begin
|
||||
template<class IteratorType, class TableType>
|
||||
inline static IteratorType iterator_begin(const TableType& table);
|
||||
|
||||
//- Factory method to create a const iterator begin
|
||||
template<class IteratorType, class TableType>
|
||||
inline static IteratorType iterator_cbegin(const TableType& table);
|
||||
|
||||
//- Factory method to create a non-const iterator end
|
||||
//- Factory method to return an iterator end
|
||||
// Simply reinterprets a NullObject as a hash-table iterator.
|
||||
template<class IteratorType>
|
||||
inline static const IteratorType& iterator_end();
|
||||
|
||||
//- Factory method to create a const iterator cend
|
||||
//- Factory method to return an iterator cend
|
||||
// Simply reinterprets a NullObject as a hash-table iterator.
|
||||
template<class IteratorType>
|
||||
inline static const IteratorType& iterator_cend();
|
||||
@ -116,6 +113,13 @@ struct HashTableCore
|
||||
inline const IteratorType& end() const;
|
||||
inline const IteratorType& cend() const;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
//- A static zero::null for dereferencing as a dummy HashSet element
|
||||
static zero::null zeroNullElement;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -35,16 +35,6 @@ inline IteratorType Foam::HashTableCore::iterator_begin
|
||||
}
|
||||
|
||||
|
||||
template<class IteratorType, class TableType>
|
||||
inline IteratorType Foam::HashTableCore::iterator_begin
|
||||
(
|
||||
const TableType& table
|
||||
)
|
||||
{
|
||||
return IteratorType(table.begin());
|
||||
}
|
||||
|
||||
|
||||
template<class IteratorType, class TableType>
|
||||
inline IteratorType Foam::HashTableCore::iterator_cbegin
|
||||
(
|
||||
|
||||
@ -25,30 +25,14 @@ License
|
||||
|
||||
#include "error.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Classes * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::hashedEntry::hashedEntry
|
||||
(
|
||||
const Key& key,
|
||||
const T& obj,
|
||||
hashedEntry* next
|
||||
)
|
||||
:
|
||||
key_(key),
|
||||
obj_(obj),
|
||||
next_(next)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::label
|
||||
Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
|
||||
{
|
||||
// size is power of two - this is the modulus
|
||||
return Hash()(key) & (tableSize_ - 1);
|
||||
// capacity is always a power of two - this is the modulus
|
||||
return Hash()(key) & (capacity_ - 1);
|
||||
}
|
||||
|
||||
|
||||
@ -57,21 +41,76 @@ Foam::HashTable<T, Key, Hash>::hashKeyIndex(const Key& key) const
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::label Foam::HashTable<T, Key, Hash>::capacity() const
|
||||
{
|
||||
return tableSize_;
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::label Foam::HashTable<T, Key, Hash>::size() const
|
||||
{
|
||||
return nElmts_;
|
||||
return size_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline bool Foam::HashTable<T, Key, Hash>::empty() const
|
||||
{
|
||||
return !nElmts_;
|
||||
return !size_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
|
||||
{
|
||||
if (size_)
|
||||
{
|
||||
return Iterator<true>(this, key).found();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::iterator
|
||||
Foam::HashTable<T, Key, Hash>::find
|
||||
(
|
||||
const Key& key
|
||||
)
|
||||
{
|
||||
if (size_)
|
||||
{
|
||||
return iterator(Iterator<false>(this, key));
|
||||
}
|
||||
|
||||
return iterator();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::find
|
||||
(
|
||||
const Key& key
|
||||
) const
|
||||
{
|
||||
return this->cfind(key);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::cfind
|
||||
(
|
||||
const Key& key
|
||||
) const
|
||||
{
|
||||
if (size_)
|
||||
{
|
||||
return const_iterator(Iterator<true>(this, key));
|
||||
}
|
||||
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
|
||||
@ -82,7 +121,7 @@ inline bool Foam::HashTable<T, Key, Hash>::insert
|
||||
const T& obj
|
||||
)
|
||||
{
|
||||
return this->set(key, obj, true);
|
||||
return this->set(key, obj, false); // No overwrite
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +132,7 @@ inline bool Foam::HashTable<T, Key, Hash>::set
|
||||
const T& obj
|
||||
)
|
||||
{
|
||||
return this->set(key, obj, false);
|
||||
return this->set(key, obj, true); // Overwrite
|
||||
}
|
||||
|
||||
|
||||
@ -112,7 +151,7 @@ inline const T& Foam::HashTable<T, Key, Hash>::lookup
|
||||
const T& deflt
|
||||
) const
|
||||
{
|
||||
const_iterator iter = this->find(key);
|
||||
const const_iterator iter(this->cfind(key));
|
||||
return iter.found() ? iter.object() : deflt;
|
||||
}
|
||||
|
||||
@ -122,7 +161,7 @@ inline const T& Foam::HashTable<T, Key, Hash>::lookup
|
||||
template<class T, class Key, class Hash>
|
||||
inline T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key)
|
||||
{
|
||||
iterator iter = this->find(key);
|
||||
const iterator iter(this->find(key));
|
||||
|
||||
if (!iter.found())
|
||||
{
|
||||
@ -139,7 +178,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key)
|
||||
template<class T, class Key, class Hash>
|
||||
inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
|
||||
{
|
||||
const_iterator iter = this->find(key);
|
||||
const const_iterator iter(this->cfind(key));
|
||||
|
||||
if (!iter.found())
|
||||
{
|
||||
@ -156,14 +195,14 @@ inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
|
||||
template<class T, class Key, class Hash>
|
||||
inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key)
|
||||
{
|
||||
iterator iter = this->find(key);
|
||||
const iterator iter(this->find(key));
|
||||
|
||||
if (iter.found())
|
||||
{
|
||||
return iter.object();
|
||||
}
|
||||
|
||||
this->insert(key, T());
|
||||
this->insert(key, mapped_type());
|
||||
return find(key).object();
|
||||
}
|
||||
|
||||
@ -175,7 +214,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()
|
||||
const T& deflt
|
||||
)
|
||||
{
|
||||
iterator iter = this->find(key);
|
||||
const iterator iter(this->find(key));
|
||||
|
||||
if (iter.found())
|
||||
{
|
||||
@ -198,412 +237,6 @@ inline const T& Foam::HashTable<T, Key, Hash>::operator()
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base()
|
||||
:
|
||||
entryPtr_(nullptr),
|
||||
hashTable_(nullptr),
|
||||
hashIndex_(0)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
|
||||
(
|
||||
const table_type* hashTbl,
|
||||
const entry_type* elmt,
|
||||
const label hashIndex
|
||||
)
|
||||
:
|
||||
entryPtr_(const_cast<entry_type*>(elmt)),
|
||||
hashTable_(const_cast<table_type*>(hashTbl)),
|
||||
hashIndex_(hashIndex)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
|
||||
(
|
||||
const table_type* hashTbl
|
||||
)
|
||||
:
|
||||
entryPtr_(nullptr),
|
||||
hashTable_(const_cast<table_type*>(hashTbl)),
|
||||
hashIndex_(0)
|
||||
{
|
||||
if (hashTable_ && hashTable_->nElmts_)
|
||||
{
|
||||
// find first non-nullptr table entry
|
||||
while
|
||||
(
|
||||
!(entryPtr_ = hashTable_->table_[hashIndex_])
|
||||
&& ++hashIndex_ < hashTable_->tableSize_
|
||||
)
|
||||
{}
|
||||
|
||||
if (hashIndex_ >= hashTable_->tableSize_)
|
||||
{
|
||||
// make into an end iterator
|
||||
entryPtr_ = nullptr;
|
||||
hashIndex_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline void
|
||||
Foam::HashTable<T, Key, Hash>::iterator_base::increment()
|
||||
{
|
||||
// A negative index is a special value from erase
|
||||
if (hashIndex_ < 0)
|
||||
{
|
||||
// the markPos='-curPos-1', but we wish to continue at 'curPos-1'
|
||||
// thus use '-(markPos+1) -1'
|
||||
hashIndex_ = -(hashIndex_+1) - 1;
|
||||
}
|
||||
else if (entryPtr_)
|
||||
{
|
||||
if (entryPtr_->next_)
|
||||
{
|
||||
// Move to next element on the SLList
|
||||
entryPtr_ = entryPtr_->next_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// // if we reach here (entryPtr_ is nullptr) it is already at the end()
|
||||
// // we should probably stop
|
||||
// }
|
||||
|
||||
|
||||
// Step to the next table entry
|
||||
while
|
||||
(
|
||||
++hashIndex_ < hashTable_->tableSize_
|
||||
&& !(entryPtr_ = hashTable_->table_[hashIndex_])
|
||||
)
|
||||
{}
|
||||
|
||||
if (hashIndex_ >= hashTable_->tableSize_)
|
||||
{
|
||||
// make into an end iterator
|
||||
entryPtr_ = nullptr;
|
||||
hashIndex_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline bool
|
||||
Foam::HashTable<T, Key, Hash>::iterator_base::found() const
|
||||
{
|
||||
return entryPtr_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const Key& Foam::HashTable<T, Key, Hash>::iterator_base::key() const
|
||||
{
|
||||
return entryPtr_->key_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline T& Foam::HashTable<T, Key, Hash>::iterator_base::element() const
|
||||
{
|
||||
return entryPtr_->obj_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator==
|
||||
(
|
||||
const iterator_base& iter
|
||||
) const
|
||||
{
|
||||
return entryPtr_ == iter.entryPtr_;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator!=
|
||||
(
|
||||
const iterator_base& iter
|
||||
) const
|
||||
{
|
||||
return entryPtr_ != iter.entryPtr_;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * key iterator base * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
template<class WrappedIterator>
|
||||
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
::key_iterator_base
|
||||
(
|
||||
const WrappedIterator& iter
|
||||
)
|
||||
:
|
||||
WrappedIterator(iter)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
template<class WrappedIterator>
|
||||
inline const Key&
|
||||
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
::operator*() const
|
||||
{
|
||||
return this->key();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
template<class WrappedIterator>
|
||||
inline const Key&
|
||||
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
::operator()() const
|
||||
{
|
||||
return this->key();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
template<class WrappedIterator>
|
||||
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>&
|
||||
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
::operator++()
|
||||
{
|
||||
this->increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
template<class WrappedIterator>
|
||||
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
|
||||
::operator++(int)
|
||||
{
|
||||
key_iterator_base old = *this;
|
||||
this->increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator::iterator()
|
||||
:
|
||||
iterator_base()
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator::iterator
|
||||
(
|
||||
table_type* hashTbl
|
||||
)
|
||||
:
|
||||
iterator_base(hashTbl)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::iterator::iterator
|
||||
(
|
||||
table_type* hashTbl,
|
||||
entry_type* elmt,
|
||||
const label hashIndex
|
||||
)
|
||||
:
|
||||
iterator_base(hashTbl, elmt, hashIndex)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline T&
|
||||
Foam::HashTable<T, Key, Hash>::iterator::object() const
|
||||
{
|
||||
return this->element();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline T&
|
||||
Foam::HashTable<T, Key, Hash>::iterator::operator*() const
|
||||
{
|
||||
return this->object();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline T&
|
||||
Foam::HashTable<T, Key, Hash>::iterator::operator()() const
|
||||
{
|
||||
return this->object();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::iterator&
|
||||
Foam::HashTable<T, Key, Hash>::iterator::operator++()
|
||||
{
|
||||
this->increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::iterator
|
||||
Foam::HashTable<T, Key, Hash>::iterator::operator++(int)
|
||||
{
|
||||
iterator old = *this;
|
||||
this->increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator()
|
||||
:
|
||||
iterator_base()
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
|
||||
(
|
||||
const HashTable<T, Key, Hash>::iterator& iter
|
||||
)
|
||||
:
|
||||
iterator_base(iter)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
|
||||
(
|
||||
table_type* hashTbl
|
||||
)
|
||||
:
|
||||
iterator_base(hashTbl)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
|
||||
(
|
||||
table_type* hashTbl,
|
||||
entry_type* elmt,
|
||||
const label hashIndex
|
||||
)
|
||||
:
|
||||
iterator_base(hashTbl, elmt, hashIndex)
|
||||
{}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const T&
|
||||
Foam::HashTable<T, Key, Hash>::const_iterator::object() const
|
||||
{
|
||||
return this->element();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const T&
|
||||
Foam::HashTable<T, Key, Hash>::const_iterator::operator*() const
|
||||
{
|
||||
return this->object();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const T&
|
||||
Foam::HashTable<T, Key, Hash>::const_iterator::operator()() const
|
||||
{
|
||||
return this->object();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator&
|
||||
Foam::HashTable<T, Key, Hash>::const_iterator::operator++()
|
||||
{
|
||||
this->increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::const_iterator::operator++(int)
|
||||
{
|
||||
const_iterator old = *this;
|
||||
this->increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::iterator
|
||||
Foam::HashTable<T, Key, Hash>::begin()
|
||||
{
|
||||
return iterator(this);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::begin() const
|
||||
{
|
||||
return const_iterator(this);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline typename Foam::HashTable<T, Key, Hash>::const_iterator
|
||||
Foam::HashTable<T, Key, Hash>::cbegin() const
|
||||
{
|
||||
return const_iterator(this);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const typename Foam::HashTable<T, Key, Hash>::iterator&
|
||||
Foam::HashTable<T, Key, Hash>::end()
|
||||
{
|
||||
return iterator_end<iterator>();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
|
||||
Foam::HashTable<T, Key, Hash>::end() const
|
||||
{
|
||||
return iterator_end<const_iterator>();
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
|
||||
Foam::HashTable<T, Key, Hash>::cend() const
|
||||
{
|
||||
return iterator_cend<const_iterator>();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, class Key, class Hash>
|
||||
|
||||
@ -33,17 +33,17 @@ template<class T, class Key, class Hash>
|
||||
Foam::HashTable<T, Key, Hash>::HashTable(Istream& is, const label size)
|
||||
:
|
||||
HashTableCore(),
|
||||
nElmts_(0),
|
||||
tableSize_(HashTableCore::canonicalSize(size)),
|
||||
size_(0),
|
||||
capacity_(HashTableCore::canonicalSize(size)),
|
||||
table_(nullptr)
|
||||
{
|
||||
if (tableSize_)
|
||||
if (capacity_)
|
||||
{
|
||||
table_ = new hashedEntry*[tableSize_];
|
||||
table_ = new node_type*[capacity_];
|
||||
|
||||
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
|
||||
for (label i=0; i < capacity_; ++i)
|
||||
{
|
||||
table_[hashIdx] = nullptr;
|
||||
table_[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,10 +60,10 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::printInfo(Ostream& os) const
|
||||
label maxChain = 0;
|
||||
unsigned avgChain = 0;
|
||||
|
||||
for (label hashIdx = 0; hashIdx < tableSize_; ++hashIdx)
|
||||
for (label i=0; i < capacity_; ++i)
|
||||
{
|
||||
label count = 0;
|
||||
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||
for (node_type* ep = table_[i]; ep; ep = ep->next_)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
@ -81,7 +81,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::printInfo(Ostream& os) const
|
||||
}
|
||||
|
||||
os << "HashTable<T,Key,Hash>"
|
||||
<< " elements:" << size() << " slots:" << used << "/" << tableSize_
|
||||
<< " elements:" << size() << " slots:" << used << "/" << capacity_
|
||||
<< " chaining(avg/max):" << (used ? (float(avgChain)/used) : 0)
|
||||
<< "/" << maxChain << endl;
|
||||
|
||||
@ -145,7 +145,7 @@ Foam::Istream& Foam::operator>>
|
||||
{
|
||||
is.fatalCheck(FUNCTION_NAME);
|
||||
|
||||
// Anull list
|
||||
// Anull existing table
|
||||
L.clear();
|
||||
|
||||
is.fatalCheck(FUNCTION_NAME);
|
||||
@ -154,7 +154,7 @@ Foam::Istream& Foam::operator>>
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
||||
"operator>>(Istream&, HashTable&) : "
|
||||
"reading first token"
|
||||
);
|
||||
|
||||
@ -163,11 +163,11 @@ Foam::Istream& Foam::operator>>
|
||||
const label s = firstToken.labelToken();
|
||||
|
||||
// Read beginning of contents
|
||||
const char delimiter = is.readBeginList("HashTable<T, Key, Hash>");
|
||||
const char delimiter = is.readBeginList("HashTable");
|
||||
|
||||
if (s)
|
||||
{
|
||||
if (2*s > L.tableSize_)
|
||||
if (2*s > L.capacity_)
|
||||
{
|
||||
L.resize(2*s);
|
||||
}
|
||||
@ -182,7 +182,7 @@ Foam::Istream& Foam::operator>>
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
||||
"operator>>(Istream&, HashTable&) : "
|
||||
"reading entry"
|
||||
);
|
||||
}
|
||||
@ -224,15 +224,11 @@ Foam::Istream& Foam::operator>>
|
||||
|
||||
Key key;
|
||||
is >> key;
|
||||
|
||||
T element;
|
||||
is >> element;
|
||||
|
||||
L.insert(key, element);
|
||||
L.insert(key, pTraits<T>(is));
|
||||
|
||||
is.fatalCheck
|
||||
(
|
||||
"operator>>(Istream&, HashTable<T, Key, Hash>&) : "
|
||||
"operator>>(Istream&, HashTable&) : "
|
||||
"reading entry"
|
||||
);
|
||||
|
||||
@ -262,19 +258,26 @@ Foam::Ostream& Foam::operator<<
|
||||
const HashTable<T, Key, Hash>& tbl
|
||||
)
|
||||
{
|
||||
using const_iterator = typename HashTable<T, Key, Hash>::const_iterator;
|
||||
const label sz = tbl.size();
|
||||
|
||||
// Write size and start delimiter
|
||||
os << nl << tbl.size() << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
// Write contents
|
||||
for (const_iterator iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
||||
if (sz)
|
||||
{
|
||||
os << iter.key() << token::SPACE << iter.object() << nl;
|
||||
}
|
||||
// Size and start list delimiter
|
||||
os << nl << sz << nl << token::BEGIN_LIST << nl;
|
||||
|
||||
// Write end delimiter
|
||||
os << token::END_LIST;
|
||||
// Contents
|
||||
for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
|
||||
{
|
||||
os << iter.key() << token::SPACE << iter.object() << nl;
|
||||
}
|
||||
|
||||
os << token::END_LIST; // End list delimiter
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty hash table
|
||||
os << sz << token::BEGIN_LIST << token::END_LIST;
|
||||
}
|
||||
|
||||
os.check(FUNCTION_NAME);
|
||||
return os;
|
||||
|
||||
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
|
||||
A HashTable to objects of type \<T\> with a label key.
|
||||
|
||||
Note
|
||||
The Map contents are unordered.
|
||||
When the key order is important, use the sortedToc() method to obtain
|
||||
a list of sorted keys and use that for further access.
|
||||
|
||||
See also
|
||||
PtrMap
|
||||
|
||||
@ -65,13 +70,19 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct given initial size
|
||||
Map(const label size = 128)
|
||||
//- Construct null with default table size
|
||||
Map()
|
||||
:
|
||||
parent_type()
|
||||
{}
|
||||
|
||||
//- Construct with given table size
|
||||
explicit Map(const label size)
|
||||
:
|
||||
parent_type(size)
|
||||
{}
|
||||
|
||||
//- Construct from Istream
|
||||
//- Construct from Istream with default table size
|
||||
Map(Istream& is)
|
||||
:
|
||||
parent_type(is)
|
||||
@ -96,7 +107,7 @@ public:
|
||||
{}
|
||||
|
||||
//- Construct by transferring the parameter contents
|
||||
Map(const Xfer<HashTable<T, label, Hash<label>>>& map)
|
||||
Map(const Xfer<parent_type>& map)
|
||||
:
|
||||
parent_type(map)
|
||||
{}
|
||||
|
||||
@ -62,8 +62,14 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null with default table size
|
||||
PtrMap()
|
||||
:
|
||||
parent_type()
|
||||
{}
|
||||
|
||||
//- Construct given initial map size
|
||||
PtrMap(const label size = 128)
|
||||
explicit PtrMap(const label size)
|
||||
:
|
||||
parent_type(size)
|
||||
{}
|
||||
|
||||
Reference in New Issue
Block a user