ENH: HashSet, HashTable, HashPtrTable merge() method

- name and functionality similar to std::unordered_map (C++17).
  Formalizes what had been previously been implemented in IOobjectList
  but now manages without pointer deletion/creation.
This commit is contained in:
Mark Olesen
2023-02-06 11:21:15 +01:00
parent aafcd0b9e0
commit 375a4792f9
16 changed files with 430 additions and 116 deletions

View File

@ -73,6 +73,22 @@ void printMinMax(const HashSet<Key, Hash>& set)
} }
template<class Key, class Hash>
void printHashSet(const HashSet<Key, Hash>& table)
{
Info<< table.size() << '(' << nl;
for (const auto& key : table.sortedToc())
{
const auto iter = table.find(key);
Info<< " " << key << " : " << Foam::name(&(iter.key())) << nl;
}
Info<< ')' << nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program: // Main program:
@ -84,33 +100,33 @@ int main(int argc, char *argv[])
<< typeid(HashSet<label>::hasher).name() << nl << nl; << typeid(HashSet<label>::hasher).name() << nl << nl;
hashedWordList words hashedWordList words
{ ({
"abc", "abc",
"def", "def",
"ghi" "ghi"
}; });
words = { "def", "ghi", "xy", "all", "end", "all" }; words = { "def", "ghi", "xy", "all", "end", "all" };
wordHashSet setA wordHashSet setA
{ ({
"xx", "xx",
"yy", "yy",
"zz" "zz"
}; });
setA = { "kjhk", "kjhk2", "abced" }; setA = { "kjhk", "kjhk2", "abced" };
HashTable<label> tableA HashTable<label> tableA
{ ({
{ "value1", 1 }, { "value1", 1 },
{ "value2", 2 }, { "value2", 2 },
{ "value3", 3 } { "value3", 3 }
}; });
HashTable<nil> tableB; HashTable<nil> tableB;
tableB.insert("value4", nil()); tableB.emplace("value4");
tableB.insert("value5", nil()); tableB.emplace("value5");
tableB.insert("value6", nil()); tableB.emplace("value6");
Info<< "tableA keys: "; tableA.writeKeys(Info) << endl; Info<< "tableA keys: "; tableA.writeKeys(Info) << endl;
@ -123,11 +139,11 @@ int main(int argc, char *argv[])
} }
Map<label> mapA Map<label> mapA
{ ({
{ 1, 1 }, { 1, 1 },
{ 2, 2 }, { 2, 2 },
{ 3, 3 } { 3, 3 }
}; });
mapA.set(4, 4); mapA.set(4, 4);
Info<< "hashedWordList: " << words << nl Info<< "hashedWordList: " << words << nl
@ -185,9 +201,9 @@ int main(int argc, char *argv[])
} }
labelHashSet setB labelHashSet setB
{ ({
1, 11, 42 1, 11, 42
}; });
Info<<"Set with min/max:" << minMax(setB) Info<<"Set with min/max:" << minMax(setB)
<< " min:" << min(setB) << " max:" << max(setB) << nl; << " min:" << min(setB) << " max:" << max(setB) << nl;
@ -309,6 +325,26 @@ int main(int argc, char *argv[])
Info<< "setA1: " << setA1 << nl Info<< "setA1: " << setA1 << nl
<< "setB1: " << setB1 << nl; << "setB1: " << setB1 << nl;
// Merging
{
wordHashSet set0({ "abc", "kjhk", "kjhk2" });
wordHashSet set1({ "abc", "def", "ghi", "jkl" });
Info<< nl
<< "Set0" << nl;
printHashSet(set0);
Info<< "Set1" << nl;
printHashSet(set1);
set1.merge(set0);
Info<< "merged 0" << nl;
printHashSet(set0);
Info<< "merged 1" << nl;
printHashSet(set1);
}
return 0; return 0;
} }

View File

@ -79,26 +79,56 @@ public:
}; };
template<class T, class Key, class Hash>
void printTable(const HashPtrTable<T, Key, Hash>& table)
{
Info<< table.size() << '(' << nl;
for (const auto& key : table.sortedToc())
{
const auto iter = table.find(key);
Info
<< " " << iter.key() << " (" << Foam::name(&(iter.key()))
<< ") : ";
if (iter.val())
{
Info<< *(iter.val());
}
else
{
Info<< "nullptr";
}
Info<< " (" << Foam::name(iter.val()) << ")" << nl;;
}
Info<< ')' << nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program: // Main program:
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
HashTable<label, Foam::string> table1 HashTable<Label, Foam::string> table0
{ ({
{"abc", 123},
{"kjhk", 10}, {"kjhk", 10},
{"kjhk2", 12} {"kjhk2", 12}
}; });
Info<< "table1: " << table1 << nl Info<< "table0: " << table0 << nl
<< "toc: " << flatOutput(table1.toc()) << nl; << "toc: " << flatOutput(table0.toc()) << nl;
HashTable<label, label, Hash<label>> table2 HashTable<label, label, Hash<label>> table2
{ ({
{3, 10}, {3, 10},
{5, 12}, {5, 12},
{7, 16} {7, 16}
}; });
Info<< "table2: " << table2 << nl Info<< "table2: " << table2 << nl
<< "toc: " << flatOutput(table2.toc()) << nl; << "toc: " << flatOutput(table2.toc()) << nl;
@ -127,7 +157,7 @@ int main(int argc, char *argv[])
table1.insert("ghi", 15); table1.insert("ghi", 15);
table1.insert("jkl", 20); table1.insert("jkl", 20);
Info<< nl << "Table toc: " << flatOutput(table1.toc()) << nl; Info<< nl << "Table toc: " << flatOutput(table1.sortedToc()) << nl;
for (const word k : { "abc" }) for (const word k : { "abc" })
{ {
@ -153,16 +183,30 @@ int main(int argc, char *argv[])
; ;
} }
} }
Info<< nl
<< "Table0: " << flatOutput(table0.sortedToc()) << nl
<< "Table1: " << flatOutput(table1.sortedToc()) << nl;
table1.merge(table0);
Info<< "merged 0: " << flatOutput(table0.sortedToc()) << nl
<< "merged 1: " << flatOutput(table1.sortedToc()) << nl;
} }
{ {
HashPtrTable<Label> ptable0(0);
ptable0.emplace("abc", 123),
ptable0.emplace("kjhk", 10);
ptable0.emplace("kjhk2", 12);
HashPtrTable<Label> ptable1(0); HashPtrTable<Label> ptable1(0);
ptable1.insert("abc", autoPtr<Label>::New(5)); ptable1.insert("abc", autoPtr<Label>::New(5));
ptable1.insert("def", autoPtr<Label>::New(10)); ptable1.emplace("def", 10);
ptable1.insert("ghi", autoPtr<Label>::New(15)); ptable1.emplace("ghi", 15);
ptable1.insert("jkl", autoPtr<Label>::New(20)); ptable1.emplace("jkl", 20);
Info<< nl << "PtrTable toc: " << flatOutput(ptable1.toc()) << nl; Info<< nl << "PtrTable toc: " << flatOutput(ptable1.sortedToc()) << nl;
for (const word k : { "abc" }) for (const word k : { "abc" })
{ {
@ -242,6 +286,20 @@ int main(int argc, char *argv[])
} }
} }
Info<< nl
<< "Table0" << nl;
printTable(ptable0);
Info<< "Table1" << nl;
printTable(ptable1);
ptable1.merge(ptable0);
Info<< "merged 0" << nl;
printTable(ptable0);
Info<< "merged 1" << nl;
printTable(ptable1);
Info<< nl << "Ending scope" << nl; Info<< nl << "Ending scope" << nl;
} }
@ -277,6 +335,28 @@ int main(int argc, char *argv[])
Info<< "got with " << (*iter).size() << nl; Info<< "got with " << (*iter).size() << nl;
} }
Info<< nl
<< "Test (DIY) insert_or_assign" << nl;
label nKeys = 0;
for (const auto& key : { "abc", "foo", "mno", "xyz" })
{
Info<< key;
if (ltable1.contains(key))
{
Info<< " : " << ltable1[key];
}
else
{
Info<< " : n/a";
}
/// ltable1.insert_or_assign(key, identity(++nKeys));
ltable1(key) = identity(++nKeys);
Info<< " --> " << ltable1[key] << nl;
}
} }
Info<< "\nEnd\n" << endl; Info<< "\nEnd\n" << endl;

View File

@ -334,7 +334,7 @@ int main(int argc, char *argv[])
Info<< "==target==" << nl; reportDetail(objects); Info<< "==target==" << nl; reportDetail(objects);
Info<< "==source==" << nl; reportDetail(other); Info<< "==source==" << nl; reportDetail(other);
objects.merge(std::move(other)); objects.merge(other);
Info<< nl << "After merge" << nl; Info<< nl << "After merge" << nl;
Info<< "==target==" << nl; reportDetail(objects); Info<< "==target==" << nl; reportDetail(objects);

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -150,6 +150,30 @@ void Foam::HashPtrTable<T, Key, Hash>::clear()
} }
template<class T, class Key, class Hash>
void Foam::HashPtrTable<T, Key, Hash>::merge
(
HashPtrTable<T, Key, Hash>& source
)
{
// Use parent merge (of raw pointer entries)
// and by-pass any pointer deletions etc.
parent_type::merge(static_cast<parent_type&>(source));
}
template<class T, class Key, class Hash>
void Foam::HashPtrTable<T, Key, Hash>::merge
(
HashPtrTable<T, Key, Hash>&& source
)
{
// Use parent merge (of raw pointer entries)
// and by-pass any pointer deletions etc.
parent_type::merge(static_cast<parent_type&>(source));
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -173,6 +173,16 @@ public:
//- Clear all entries from table and delete any allocated pointers //- Clear all entries from table and delete any allocated pointers
void clear(); void clear();
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashPtrTable<T, Key, Hash>& source);
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashPtrTable<T, Key, Hash>&& source);
// Reading/writing // Reading/writing

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2022 OpenCFD Ltd. Copyright (C) 2018-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -232,6 +232,20 @@ inline Foam::label Foam::HashSet<Key, Hash>::unset
} }
template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::merge(HashSet<Key, Hash>& source)
{
parent_type::merge(source);
}
template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::merge(HashSet<Key, Hash>&& source)
{
parent_type::merge(source);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class Key, class Hash> template<class Key, class Hash>

View File

@ -197,7 +197,7 @@ public:
//- Same as insert (no value to overwrite) //- Same as insert (no value to overwrite)
bool set(const Key& key) bool set(const Key& key)
{ {
return insert(key); return this->parent_type::emplace(key);
} }
//- Unset the specified key - same as erase //- Unset the specified key - same as erase
@ -207,6 +207,16 @@ public:
return this->parent_type::erase(key); return this->parent_type::erase(key);
} }
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashSet<Key, Hash>& source);
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashSet<Key, Hash>&& source);
// Convenience // Convenience
@ -370,7 +380,7 @@ public:
//- Add entries to this HashSet //- Add entries to this HashSet
this_type& operator|=(const this_type& rhs); this_type& operator|=(const this_type& rhs);
//- Only retain entries found in both HashSets //- Only retain entries contained in both HashSets
inline this_type& operator&=(const this_type& rhs); inline this_type& operator&=(const this_type& rhs);
//- Only retain unique entries (xor) //- Only retain unique entries (xor)

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -359,7 +359,8 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
{ {
if (!capacity_) if (!capacity_)
{ {
resize(2); // Same as default sizing
resize(128);
} }
const label index = hashKeyIndex(key); const label index = hashKeyIndex(key);
@ -384,13 +385,9 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
new node_type(table_[index], key, std::forward<Args>(args)...); new node_type(table_[index], key, std::forward<Args>(args)...);
++size_; ++size_;
if (double(size_)/capacity_ > 0.8 && capacity_ < maxTableSize) if (0.8*capacity_ < size_) // Resize after 80% fill factor
{ {
#ifdef FULLDEBUG if (capacity_ < maxTableSize) resize(2*capacity_);
DebugInFunction << "Doubling table size\n";
#endif
resize(2*capacity_);
} }
} }
else if (overwrite) else if (overwrite)
@ -425,10 +422,7 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
} }
else else
{ {
// Do not overwrite existing entry (STL 'insert' convention) // Not overwriting existing entry
#ifdef FULLDEBUG
DebugInFunction << "Not inserting " << key << ": already in table\n";
#endif
return false; return false;
} }
@ -436,6 +430,52 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
} }
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::insert_node(node_type* entry)
{
if (!entry) return;
if (!capacity_)
{
// Same as default sizing
resize(128);
}
const label index = hashKeyIndex(entry->key());
node_type* curr = nullptr;
//node_type* prev = nullptr;
for (node_type* ep = table_[index]; ep; ep = ep->next_)
{
if (entry->key() == ep->key())
{
curr = ep;
break;
}
//prev = ep;
}
if (!curr)
{
// Not found, insert it at the head
table_[index] = entry;
++size_;
if (0.8*capacity_ < size_) // Resize after 80% fill factor
{
if (capacity_ < maxTableSize) resize(2*capacity_);
}
}
else
{
FatalErrorInFunction
<< "Not inserting " << entry->key() << ": already in table\n"
<< exit(FatalError);
}
}
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter) bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
{ {
@ -444,9 +484,7 @@ bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
// The parameter should be (iterator&), but then the compiler doesn't find // The parameter should be (iterator&), but then the compiler doesn't find
// it correctly and tries to call as (iterator) instead. // it correctly and tries to call as (iterator) instead.
iterator& it = const_cast<iterator&>(iter); return iterator_erase(const_cast<iterator&>(iter));
return iterator_erase(it.entry_, it.index_);
} }
@ -454,7 +492,7 @@ template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::erase(const Key& key) bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
{ {
iterator iter(find(key)); iterator iter(find(key));
return erase(iter); return iterator_erase(iter);
} }
@ -605,10 +643,6 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
if (newCapacity == oldCapacity) if (newCapacity == oldCapacity)
{ {
#ifdef FULLDEBUG
DebugInFunction << "New table size == old table size\n";
#endif
return; return;
} }
else if (!newCapacity) else if (!newCapacity)
@ -617,7 +651,8 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
if (size_) if (size_)
{ {
WarningInFunction WarningInFunction
<< "HashTable contains " << size_ << " cannot resize(0)" << nl; << "HashTable contains " << size_
<< " elements, cannot resize(0)" << nl;
} }
else else
{ {
@ -646,8 +681,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
// Move to new table[] but with new chaining. // Move to new table[] but with new chaining.
label nMove = size_; // Allow early completion for (label i = 0, nPending = size_; nPending && i < oldCapacity; ++i)
for (label i=0; nMove && i < oldCapacity; ++i)
{ {
for (node_type* ep = oldTable[i]; ep; /*nil*/) for (node_type* ep = oldTable[i]; ep; /*nil*/)
{ {
@ -662,7 +696,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
} }
ep = next; // continue in the linked-list ep = next; // continue in the linked-list
--nMove; // note any early completion --nPending; // note any early completion
} }
oldTable[i] = nullptr; oldTable[i] = nullptr;
} }
@ -809,6 +843,46 @@ Foam::label Foam::HashTable<T, Key, Hash>::filterEntries
} }
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::merge(HashTable<T, Key, Hash>& source)
{
// Self-merge implicitly a no-op
if (node_type::stores_value())
{
// key/val pair
for (iterator iter = source.begin(); iter != source.end(); ++iter)
{
if (!contains(iter.key()))
{
node_type* entry = source.iterator_extract(iter);
this->insert_node(entry);
}
}
}
else
{
// key only, does not store a value.
// Since the key is const, juggling the node does not work
for (iterator iter = source.begin(); iter != source.end(); ++iter)
{
if (emplace(iter.key()))
{
source.erase(iter);
}
}
}
}
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::merge(HashTable<T, Key, Hash>&& source)
{
merge(source);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>

View File

@ -206,6 +206,17 @@ private:
template<class... Args> template<class... Args>
bool setEntry(const bool overwrite, const Key& key, Args&&... args); bool setEntry(const bool overwrite, const Key& key, Args&&... args);
//- Insert node (low-level). The node must not previously exist!
void insert_node(node_type* entry);
//- 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(iterator& iter);
//- Unlink node from iterator (low-level).
node_type* iterator_extract(iterator& iter);
//- Read hash table //- Read hash table
Istream& readTable(Istream& is); Istream& readTable(Istream& is);
@ -532,6 +543,16 @@ public:
//- Transfer contents into this table. //- Transfer contents into this table.
void transfer(HashTable<T, Key, Hash>& rhs); void transfer(HashTable<T, Key, Hash>& rhs);
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashTable<T, Key, Hash>& source);
//- Attempts to extract entries from source parameter and insert them
//- into \c this, does not overwrite existing entries.
//- The source will contains any items that could not be merged.
void merge(HashTable<T, Key, Hash>&& source);
// Member Operators // Member Operators
@ -714,11 +735,6 @@ protected:
} }
}; };
//- Low-level entry erasure using iterator internals.
// This invalidates the iterator until the next ++ operation.
// \return True if the corresponding entry existed and was removed
bool iterator_erase(node_type*& entry, label& index);
public: public:
//- Forward iterator with non-const access //- Forward iterator with non-const access

View File

@ -198,6 +198,32 @@ inline bool Foam::HashTable<T, Key, Hash>::set
} }
// FUTURE?
// If 'key' already exists, assign \c std::forward<T>(obj) to the
// entry. If it does not exist, uses insert()
//
// template<class T, class Key, class Hash>
// inline void Foam::HashTable<T, Key, Hash>::insert_or_assign
// (
// const Key& key,
// T&& obj
// )
// {
// iterator iter(this->find(key));
//
// if (iter.good())
// {
// iter.val() = std::forward<T>(obj);
// }
// else
// {
// this->setEntry(true, key, std::forward<T>(obj));
// // iter = this->find(key);
// }
// // return iter.val();
// }
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline const T& Foam::HashTable<T, Key, Hash>::lookup inline const T& Foam::HashTable<T, Key, Hash>::lookup
( (

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -39,7 +39,7 @@ Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
container_(tbl), container_(tbl),
index_(0) index_(0)
{ {
if (tbl->size()) if (container_ && container_->size())
{ {
const label index = container_->hashKeyIndex(key); const label index = container_->hashKeyIndex(key);
@ -62,12 +62,11 @@ Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
// Any changes here may need changes in the iterator increment() method // Any changes here may need changes in the iterator increment() method
// //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::iterator_erase bool Foam::HashTable<T, Key, Hash>::iterator_erase(iterator& iter)
(
node_type*& entry,
label& index
)
{ {
node_type* entry = iter.entry_;
const label index = iter.index_;
// Safeguard against the following: // Safeguard against the following:
// - empty table // - empty table
// - nullptr entry // - nullptr entry
@ -98,8 +97,8 @@ bool Foam::HashTable<T, Key, Hash>::iterator_erase
// Had previous element in linked list - reposition to there // Had previous element in linked list - reposition to there
prev->next_ = entry->next_; prev->next_ = entry->next_;
delete entry; delete entry;
entry = prev;
iter.entry_ = prev;
return true; return true;
} }
@ -108,7 +107,7 @@ bool Foam::HashTable<T, Key, Hash>::iterator_erase
delete entry; delete entry;
// Assign any non-nullptr value so it doesn't look like end() // Assign any non-nullptr value so it doesn't look like end()
entry = reinterpret_cast<node_type*>(this); iter.entry_ = reinterpret_cast<node_type*>(this);
// Mark the present index to continue and bring it back to the present // Mark the present index to continue and bring it back to the present
// location with the next index. // location with the next index.
@ -116,10 +115,72 @@ bool Foam::HashTable<T, Key, Hash>::iterator_erase
// Save: (-index-1), which has no ambiguity for index 0. // Save: (-index-1), which has no ambiguity for index 0.
// Retrieve: (-(index+1)) // Retrieve: (-(index+1))
index = (-index - 1); iter.index_ = (-index - 1);
return true; return true;
} }
//
// Any changes here may need changes in the iterator increment() method
//
template<class T, class Key, class Hash>
typename Foam::HashTable<T, Key, Hash>::node_type*
Foam::HashTable<T, Key, Hash>::iterator_extract(iterator& iter)
{
node_type* entry = iter.entry_;
const label index = iter.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 nullptr;
}
// 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 iterator to there
prev->next_ = entry->next_;
iter.entry_ = prev;
entry->next_ = nullptr;
return entry;
}
// Was first element on linked list
table_[index] = entry->next_;
iter.entry_ = table_[index];
entry->next_ = nullptr;
// 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))
iter.index_ = (-index - 1);
return entry;
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -70,7 +70,8 @@ inline Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
// //
// Any changes here may need changes in iterator_erase() method too // Any changes here may need changes in iterator_erase(), iterator_extract()
// methods too
// //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
template<bool Const> template<bool Const>

View File

@ -152,36 +152,6 @@ Foam::IOobjectList::IOobjectList
} }
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::IOobjectList::merge(IOobjectList&& other)
{
// Remove by name to avoid uncertainties about invalid iterators
label count = 0;
wordList keys(other.toc());
for (const word& key : keys)
{
if (!found(key))
{
if (IOobject::debug)
{
InfoInFunction << "Merge " << key << nl;
}
if (add(other.remove(key)))
{
++count;
}
}
}
return count;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
const Foam::IOobject* Foam::IOobjectList::cfindObject const Foam::IOobject* Foam::IOobjectList::cfindObject

View File

@ -224,19 +224,11 @@ public:
// Basic methods // Basic methods
//- Move insert IOobject into the list
inline bool add(autoPtr<IOobject>&& objectPtr);
//- Move insert IOobject into the list //- Move insert IOobject into the list
inline bool add(autoPtr<IOobject>& objectPtr); inline bool add(autoPtr<IOobject>& objectPtr);
//- Add objects from other to this list without overwriting //- Move insert IOobject into the list
//- existing keys. inline bool add(autoPtr<IOobject>&& objectPtr);
// After calling this, the other parameter will contains any items
// that could not be merged.
//
// \return number of items merged
label merge(IOobjectList&& other);
//- Remove object from the list, by name or by iterator. //- Remove object from the list, by name or by iterator.
// //
@ -362,7 +354,7 @@ public:
// word checkType = volScalarField::typeName; // word checkType = volScalarField::typeName;
// //
// Info<< checkType << "=" // Info<< checkType << "="
// << (classes.found(checkType) ? classes[checkType].size() : 0) // << (classes.contains(checkType) ? classes[checkType].size() : 0)
// << nl; // << nl;
// \endcode // \endcode
// Using the two-parameter HashTable::lookup method lets us avoid // Using the two-parameter HashTable::lookup method lets us avoid

View File

@ -109,7 +109,7 @@ inline Foam::IOobjectList::IOobjectList
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::IOobjectList::add(autoPtr<IOobject>&& objectPtr) inline bool Foam::IOobjectList::add(autoPtr<IOobject>& objectPtr)
{ {
if (objectPtr) if (objectPtr)
{ {
@ -120,7 +120,7 @@ inline bool Foam::IOobjectList::add(autoPtr<IOobject>&& objectPtr)
} }
inline bool Foam::IOobjectList::add(autoPtr<IOobject>& objectPtr) inline bool Foam::IOobjectList::add(autoPtr<IOobject>&& objectPtr)
{ {
if (objectPtr) if (objectPtr)
{ {