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:
@ -84,33 +100,33 @@ int main(int argc, char *argv[])
<< typeid(HashSet<label>::hasher).name() << nl << nl;
hashedWordList words
{
({
"abc",
"def",
"ghi"
};
});
words = { "def", "ghi", "xy", "all", "end", "all" };
wordHashSet setA
{
({
"xx",
"yy",
"zz"
};
});
setA = { "kjhk", "kjhk2", "abced" };
HashTable<label> tableA
{
({
{ "value1", 1 },
{ "value2", 2 },
{ "value3", 3 }
};
});
HashTable<nil> tableB;
tableB.insert("value4", nil());
tableB.insert("value5", nil());
tableB.insert("value6", nil());
tableB.emplace("value4");
tableB.emplace("value5");
tableB.emplace("value6");
Info<< "tableA keys: "; tableA.writeKeys(Info) << endl;
@ -123,11 +139,11 @@ int main(int argc, char *argv[])
}
Map<label> mapA
{
({
{ 1, 1 },
{ 2, 2 },
{ 3, 3 }
};
});
mapA.set(4, 4);
Info<< "hashedWordList: " << words << nl
@ -185,9 +201,9 @@ int main(int argc, char *argv[])
}
labelHashSet setB
{
({
1, 11, 42
};
});
Info<<"Set with min/max:" << minMax(setB)
<< " min:" << min(setB) << " max:" << max(setB) << nl;
@ -309,6 +325,26 @@ int main(int argc, char *argv[])
Info<< "setA1: " << setA1 << 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;
}

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:
int main(int argc, char *argv[])
{
HashTable<label, Foam::string> table1
{
HashTable<Label, Foam::string> table0
({
{"abc", 123},
{"kjhk", 10},
{"kjhk2", 12}
};
});
Info<< "table1: " << table1 << nl
<< "toc: " << flatOutput(table1.toc()) << nl;
Info<< "table0: " << table0 << nl
<< "toc: " << flatOutput(table0.toc()) << nl;
HashTable<label, label, Hash<label>> table2
{
({
{3, 10},
{5, 12},
{7, 16}
};
});
Info<< "table2: " << table2 << nl
<< "toc: " << flatOutput(table2.toc()) << nl;
@ -127,7 +157,7 @@ int main(int argc, char *argv[])
table1.insert("ghi", 15);
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" })
{
@ -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);
ptable1.insert("abc", autoPtr<Label>::New(5));
ptable1.insert("def", autoPtr<Label>::New(10));
ptable1.insert("ghi", autoPtr<Label>::New(15));
ptable1.insert("jkl", autoPtr<Label>::New(20));
ptable1.emplace("def", 10);
ptable1.emplace("ghi", 15);
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" })
{
@ -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;
}
@ -277,6 +335,28 @@ int main(int argc, char *argv[])
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;

View File

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

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
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 * * * * * * * * * * * * * //
template<class T, class Key, class Hash>

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -173,6 +173,16 @@ public:
//- Clear all entries from table and delete any allocated pointers
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

View File

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

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
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 * * * * * * * * * * * * * //
template<class Key, class Hash>

View File

@ -197,7 +197,7 @@ public:
//- Same as insert (no value to overwrite)
bool set(const Key& key)
{
return insert(key);
return this->parent_type::emplace(key);
}
//- Unset the specified key - same as erase
@ -207,6 +207,16 @@ public:
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
@ -370,7 +380,7 @@ public:
//- Add entries to this HashSet
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);
//- Only retain unique entries (xor)

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -359,7 +359,8 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
{
if (!capacity_)
{
resize(2);
// Same as default sizing
resize(128);
}
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)...);
++size_;
if (double(size_)/capacity_ > 0.8 && capacity_ < maxTableSize)
if (0.8*capacity_ < size_) // Resize after 80% fill factor
{
#ifdef FULLDEBUG
DebugInFunction << "Doubling table size\n";
#endif
resize(2*capacity_);
if (capacity_ < maxTableSize) resize(2*capacity_);
}
}
else if (overwrite)
@ -425,10 +422,7 @@ bool Foam::HashTable<T, Key, Hash>::setEntry
}
else
{
// Do not overwrite existing entry (STL 'insert' convention)
#ifdef FULLDEBUG
DebugInFunction << "Not inserting " << key << ": already in table\n";
#endif
// Not overwriting existing entry
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>
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
// it correctly and tries to call as (iterator) instead.
iterator& it = const_cast<iterator&>(iter);
return iterator_erase(it.entry_, it.index_);
return iterator_erase(const_cast<iterator&>(iter));
}
@ -454,7 +492,7 @@ template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::erase(const Key& 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)
{
#ifdef FULLDEBUG
DebugInFunction << "New table size == old table size\n";
#endif
return;
}
else if (!newCapacity)
@ -617,7 +651,8 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
if (size_)
{
WarningInFunction
<< "HashTable contains " << size_ << " cannot resize(0)" << nl;
<< "HashTable contains " << size_
<< " elements, cannot resize(0)" << nl;
}
else
{
@ -646,8 +681,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
// Move to new table[] but with new chaining.
label nMove = size_; // Allow early completion
for (label i=0; nMove && i < oldCapacity; ++i)
for (label i = 0, nPending = size_; nPending && i < oldCapacity; ++i)
{
for (node_type* ep = oldTable[i]; ep; /*nil*/)
{
@ -661,8 +695,8 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
table_[newIdx] = ep;
}
ep = next; // continue in the linked-list
--nMove; // note any early completion
ep = next; // continue in the linked-list
--nPending; // note any early completion
}
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 * * * * * * * * * * * * * //
template<class T, class Key, class Hash>

View File

@ -206,6 +206,17 @@ private:
template<class... 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
Istream& readTable(Istream& is);
@ -532,6 +543,16 @@ public:
//- Transfer contents into this table.
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
@ -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:
//- 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>
inline const T& Foam::HashTable<T, Key, Hash>::lookup
(

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,7 +39,7 @@ Foam::HashTable<T, Key, Hash>::Iterator<Const>::Iterator
container_(tbl),
index_(0)
{
if (tbl->size())
if (container_ && container_->size())
{
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
//
template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::iterator_erase
(
node_type*& entry,
label& index
)
bool Foam::HashTable<T, Key, Hash>::iterator_erase(iterator& iter)
{
node_type* entry = iter.entry_;
const label index = iter.index_;
// Safeguard against the following:
// - empty table
// - nullptr entry
@ -98,8 +97,8 @@ bool Foam::HashTable<T, Key, Hash>::iterator_erase
// Had previous element in linked list - reposition to there
prev->next_ = entry->next_;
delete entry;
entry = prev;
iter.entry_ = prev;
return true;
}
@ -108,7 +107,7 @@ bool Foam::HashTable<T, Key, Hash>::iterator_erase
delete entry;
// 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
// 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.
// Retrieve: (-(index+1))
index = (-index - 1);
iter.index_ = (-index - 1);
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<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

View File

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

View File

@ -109,7 +109,7 @@ inline Foam::IOobjectList::IOobjectList
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::IOobjectList::add(autoPtr<IOobject>&& objectPtr)
inline bool Foam::IOobjectList::add(autoPtr<IOobject>& 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)
{