mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: PtrList, PtrDynList, HashPtrTable try_emplace() method
- naming like std::map::try_emplace(), it behaves like emplace_set() if there is no element at the given location otherwise a no-op ENH: reuse existing HashPtrTable 'slot' when setting pointers - avoids extra HashTable operations
This commit is contained in:
@ -55,10 +55,7 @@ public:
|
|||||||
i_(i)
|
i_(i)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const word& keyword() const
|
word& keyword() const noexcept { return keyword_; }
|
||||||
{
|
|
||||||
return keyword_;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const ent& e)
|
friend Ostream& operator<<(Ostream& os, const ent& e)
|
||||||
{
|
{
|
||||||
@ -74,28 +71,27 @@ class Scalar
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scalar()
|
static bool verbose;
|
||||||
:
|
|
||||||
data_(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Scalar(scalar val)
|
constexpr Scalar() noexcept : data_(0) {}
|
||||||
:
|
Scalar(scalar val) noexcept : data_(val) {}
|
||||||
data_(val)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~Scalar()
|
~Scalar()
|
||||||
{
|
{
|
||||||
Info<<"delete Scalar: " << data_ << endl;
|
if (verbose) Info<< "delete Scalar: " << data_ << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const Scalar& val)
|
scalar value() const noexcept { return data_; }
|
||||||
|
scalar& value() noexcept { return data_; }
|
||||||
|
|
||||||
|
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
||||||
{
|
{
|
||||||
os << val.data_;
|
os << item.value();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool Scalar::verbose = true;
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|||||||
@ -44,38 +44,28 @@ class Scalar
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scalar()
|
static bool verbose;
|
||||||
:
|
|
||||||
data_(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Scalar(scalar val)
|
constexpr Scalar() noexcept : data_(0) {}
|
||||||
:
|
Scalar(scalar val) noexcept : data_(val) {}
|
||||||
data_(val)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~Scalar()
|
~Scalar()
|
||||||
{
|
{
|
||||||
Info<<"delete Scalar: " << data_ << endl;
|
if (verbose) Info<< "delete Scalar: " << data_ << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scalar& value() const
|
const scalar& value() const noexcept { return data_; }
|
||||||
{
|
scalar& value() noexcept { return data_; }
|
||||||
return data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
scalar& value()
|
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
||||||
{
|
{
|
||||||
return data_;
|
os << item.value();
|
||||||
}
|
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const Scalar& val)
|
|
||||||
{
|
|
||||||
os << val.data_;
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool Scalar::verbose = true;
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void printTable(const HashPtrTable<T>& table)
|
void printTable(const HashPtrTable<T>& table)
|
||||||
@ -129,6 +119,9 @@ int main()
|
|||||||
myTable.set("natlog", new double(2.718282));
|
myTable.set("natlog", new double(2.718282));
|
||||||
myTable.insert("sqrt2", autoPtr<double>::New(1.414214));
|
myTable.insert("sqrt2", autoPtr<double>::New(1.414214));
|
||||||
myTable.insert("euler", autoPtr<double>::New(0.577216));
|
myTable.insert("euler", autoPtr<double>::New(0.577216));
|
||||||
|
myTable.set("def_0", nullptr);
|
||||||
|
myTable.emplace_set("def_1", 123);
|
||||||
|
myTable.emplace_set("def_2", 456);
|
||||||
|
|
||||||
HashTable<std::unique_ptr<double>> myTable1;
|
HashTable<std::unique_ptr<double>> myTable1;
|
||||||
|
|
||||||
@ -146,6 +139,14 @@ int main()
|
|||||||
Info<< "Initial table" << nl;
|
Info<< "Initial table" << nl;
|
||||||
printTable(myTable);
|
printTable(myTable);
|
||||||
|
|
||||||
|
myTable.try_emplace("def_0", 1000); // was nullptr, now value
|
||||||
|
myTable.try_emplace("def_1", 1001); // no-op
|
||||||
|
myTable.try_emplace("def_2", 1002); // no-op;
|
||||||
|
myTable.try_emplace("def_3", 1003); // was non-existent, now value
|
||||||
|
|
||||||
|
Info<< "after try_emplace" << nl;
|
||||||
|
printTable(myTable);
|
||||||
|
|
||||||
Info<< "print" << nl;
|
Info<< "print" << nl;
|
||||||
Info<< myTable2 << nl;
|
Info<< myTable2 << nl;
|
||||||
|
|
||||||
|
|||||||
@ -46,26 +46,27 @@ class Scalar
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// static bool verbose;
|
||||||
|
|
||||||
scalar data_;
|
scalar data_;
|
||||||
|
|
||||||
Scalar()
|
Scalar() : data_(0) {}
|
||||||
:
|
Scalar(scalar val) : data_(val) {}
|
||||||
data_(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Scalar(scalar s)
|
// ~Scalar() {}
|
||||||
:
|
|
||||||
data_(s)
|
|
||||||
{}
|
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const Scalar& s)
|
scalar value() const noexcept { return data_; }
|
||||||
|
scalar& value() noexcept { return data_; }
|
||||||
|
|
||||||
|
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
||||||
{
|
{
|
||||||
os << s.data_;
|
os << item.value();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// bool Scalar::verbose = true;
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
// Main program:
|
// Main program:
|
||||||
|
|||||||
@ -49,15 +49,8 @@ public:
|
|||||||
|
|
||||||
static bool verbose;
|
static bool verbose;
|
||||||
|
|
||||||
constexpr Scalar() noexcept
|
constexpr Scalar() noexcept : data_(0) {}
|
||||||
:
|
Scalar(scalar val) noexcept : data_(val) {}
|
||||||
data_(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Scalar(scalar val) noexcept
|
|
||||||
:
|
|
||||||
data_(val)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~Scalar()
|
~Scalar()
|
||||||
{
|
{
|
||||||
@ -67,10 +60,7 @@ public:
|
|||||||
scalar value() const noexcept { return data_; }
|
scalar value() const noexcept { return data_; }
|
||||||
scalar& value() noexcept { return data_; }
|
scalar& value() noexcept { return data_; }
|
||||||
|
|
||||||
autoPtr<Scalar> clone() const
|
autoPtr<Scalar> clone() const { return autoPtr<Scalar>::New(data_); }
|
||||||
{
|
|
||||||
return autoPtr<Scalar>::New(data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
||||||
{
|
{
|
||||||
@ -361,15 +351,19 @@ int main(int argc, char *argv[])
|
|||||||
list2.emplace(i, (10 + 1.3*i));
|
list2.emplace(i, (10 + 1.3*i));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
list2.release(5);
|
list2.release(5);
|
||||||
list2.release(10);
|
list2.release(10);
|
||||||
|
|
||||||
forAll(list2, i)
|
{
|
||||||
|
// Memory error (with fulldebug): const label len = (list2.size()+2);
|
||||||
|
const label len = list2.size();
|
||||||
|
Info<< "try_emplace " << len << " values" << nl;
|
||||||
|
|
||||||
|
for (label i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
list2.try_emplace(i, (50 + 1.3*i));
|
list2.try_emplace(i, (50 + 1.3*i));
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
PtrList<Scalar> listApp;
|
PtrList<Scalar> listApp;
|
||||||
for (label i = 0; i < 5; ++i)
|
for (label i = 0; i < 5; ++i)
|
||||||
|
|||||||
@ -45,28 +45,29 @@ class Scalar
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scalar()
|
static bool verbose;
|
||||||
:
|
|
||||||
data_(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Scalar(scalar val)
|
constexpr Scalar() noexcept : data_(0) {}
|
||||||
:
|
Scalar(scalar val) noexcept : data_(val) {}
|
||||||
data_(val)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~Scalar()
|
~Scalar()
|
||||||
{
|
{
|
||||||
Info<<"delete Scalar: " << data_ << endl;
|
if (verbose) Info<< "delete Scalar: " << data_ << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Ostream& operator<<(Ostream& os, const Scalar& val)
|
const scalar& value() const noexcept { return data_; }
|
||||||
|
scalar& value() noexcept { return data_; }
|
||||||
|
|
||||||
|
autoPtr<Scalar> clone() const { return autoPtr<Scalar>::New(data_); }
|
||||||
|
|
||||||
|
friend Ostream& operator<<(Ostream& os, const Scalar& item)
|
||||||
{
|
{
|
||||||
os << val.data_;
|
os << item.value();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool Scalar::verbose = true;
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|||||||
@ -78,6 +78,14 @@ class HashPtrTable
|
|||||||
template<class INew>
|
template<class INew>
|
||||||
void read(const dictionary& dict, const INew& inew);
|
void read(const dictionary& dict, const INew& inew);
|
||||||
|
|
||||||
|
//- Implementation for emplace_set and try_emplace
|
||||||
|
template<class... Args>
|
||||||
|
inline T& emplaceImpl
|
||||||
|
(
|
||||||
|
const bool overwrite,
|
||||||
|
const Key& key,
|
||||||
|
Args&&... args
|
||||||
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -233,6 +241,14 @@ public:
|
|||||||
template<class... Args>
|
template<class... Args>
|
||||||
inline T& emplace_set(const Key& key, Args&&... args);
|
inline T& emplace_set(const Key& key, Args&&... args);
|
||||||
|
|
||||||
|
//- Like emplace_set() but will not overwrite an occupied (non-null)
|
||||||
|
//- location.
|
||||||
|
// \param key - the location to set (unless already defined)
|
||||||
|
// \param args arguments to forward to the constructor of the element
|
||||||
|
// \return reference to the existing or the new element.
|
||||||
|
template<class... Args>
|
||||||
|
inline T& try_emplace(const Key& key, Args&&... args);
|
||||||
|
|
||||||
//- No insert() with raw pointers (potential memory leaks).
|
//- No insert() with raw pointers (potential memory leaks).
|
||||||
//- Use insert() with autoPtr or set()
|
//- Use insert() with autoPtr or set()
|
||||||
inline bool insert(const Key&, T*) = delete;
|
inline bool insert(const Key&, T*) = delete;
|
||||||
|
|||||||
@ -74,6 +74,42 @@ inline bool Foam::HashPtrTable<T, Key, Hash>::emplace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, class Key, class Hash>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::HashPtrTable<T, Key, Hash>::emplaceImpl
|
||||||
|
(
|
||||||
|
const bool overwrite,
|
||||||
|
const Key& key,
|
||||||
|
Args&&... args
|
||||||
|
)
|
||||||
|
{
|
||||||
|
T* ptr = nullptr;
|
||||||
|
|
||||||
|
// Replace existing entry unconditionally (overwrite = true)
|
||||||
|
// or only if nullptr (overwrite = false)
|
||||||
|
iterator iter(this->find(key));
|
||||||
|
if (iter.good())
|
||||||
|
{
|
||||||
|
ptr = iter.val();
|
||||||
|
|
||||||
|
if (overwrite || !ptr)
|
||||||
|
{
|
||||||
|
// Overwrite existing or replace nullptr
|
||||||
|
delete ptr;
|
||||||
|
ptr = new T(std::forward<Args>(args)...);
|
||||||
|
iter.val() = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr = new T(std::forward<Args>(args)...);
|
||||||
|
this->parent_type::set(key, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, class Key, class Hash>
|
template<class T, class Key, class Hash>
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
inline T& Foam::HashPtrTable<T, Key, Hash>::emplace_set
|
inline T& Foam::HashPtrTable<T, Key, Hash>::emplace_set
|
||||||
@ -82,9 +118,21 @@ inline T& Foam::HashPtrTable<T, Key, Hash>::emplace_set
|
|||||||
Args&&... args
|
Args&&... args
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
T* ptr = new T(std::forward<Args>(args)...);
|
// overwrite = true
|
||||||
(void)this->set(key, ptr);
|
return this->emplaceImpl(true, key, std::forward<Args>(args)...);
|
||||||
return *ptr;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, class Key, class Hash>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::HashPtrTable<T, Key, Hash>::try_emplace
|
||||||
|
(
|
||||||
|
const Key& key,
|
||||||
|
Args&&... args
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// overwrite = false
|
||||||
|
return this->emplaceImpl(false, key, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,16 +177,20 @@ inline bool Foam::HashPtrTable<T, Key, Hash>::set
|
|||||||
T* ptr
|
T* ptr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const T* old = this->get(key);
|
// Replace existing entry unconditionally
|
||||||
|
iterator iter(this->find(key));
|
||||||
const bool ok = this->parent_type::set(key, ptr);
|
if (iter.good())
|
||||||
|
|
||||||
if (ok && old != ptr)
|
|
||||||
{
|
{
|
||||||
delete const_cast<T*>(old);
|
if (iter.val() != ptr)
|
||||||
|
{
|
||||||
|
delete iter.val();
|
||||||
|
iter.val() = ptr;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
// Or add new entry
|
||||||
|
return this->parent_type::set(key, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -190,6 +190,13 @@ public:
|
|||||||
template<class... Args>
|
template<class... Args>
|
||||||
inline T& emplace(const label i, Args&&... args);
|
inline T& emplace(const label i, Args&&... args);
|
||||||
|
|
||||||
|
//- Like emplace_set() but will not overwrite an occupied location.
|
||||||
|
// \param i - the location to set (unless already defined)
|
||||||
|
// \param args arguments to forward to the constructor of the element
|
||||||
|
// \return reference to the existing or the new list element.
|
||||||
|
template<class... Args>
|
||||||
|
inline T& try_emplace(const label i, Args&&... args);
|
||||||
|
|
||||||
//- Set element to given pointer and return old element (can be null).
|
//- Set element to given pointer and return old element (can be null).
|
||||||
//- Auto-sizes list as required.
|
//- Auto-sizes list as required.
|
||||||
inline autoPtr<T> set(const label i, T* ptr);
|
inline autoPtr<T> set(const label i, T* ptr);
|
||||||
|
|||||||
@ -399,7 +399,7 @@ inline T& Foam::PtrDynList<T, SizeMin>::emplace_set
|
|||||||
{
|
{
|
||||||
resize(i+1);
|
resize(i+1);
|
||||||
}
|
}
|
||||||
return this->PtrList<T>::emplace_set(i, std::forward<Args>(args)...);
|
return PtrList<T>::emplace_set(i, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -415,6 +415,22 @@ inline T& Foam::PtrDynList<T, SizeMin>::emplace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, int SizeMin>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::PtrDynList<T, SizeMin>::try_emplace
|
||||||
|
(
|
||||||
|
const label i,
|
||||||
|
Args&&... args
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (i >= this->size())
|
||||||
|
{
|
||||||
|
resize(i+1);
|
||||||
|
}
|
||||||
|
return PtrList<T>::try_emplace(i, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, int SizeMin>
|
template<class T, int SizeMin>
|
||||||
inline Foam::autoPtr<T> Foam::PtrDynList<T, SizeMin>::set
|
inline Foam::autoPtr<T> Foam::PtrDynList<T, SizeMin>::set
|
||||||
(
|
(
|
||||||
|
|||||||
@ -187,6 +187,14 @@ public:
|
|||||||
template<class... Args>
|
template<class... Args>
|
||||||
inline T& emplace(const label i, Args&&... args);
|
inline T& emplace(const label i, Args&&... args);
|
||||||
|
|
||||||
|
//- Like emplace_set() but will not overwrite an occupied (non-null)
|
||||||
|
//- location.
|
||||||
|
// \param i - the location to set (unless already defined)
|
||||||
|
// \param args arguments to forward to the constructor of the element
|
||||||
|
// \return reference to the existing or the new list element.
|
||||||
|
template<class... Args>
|
||||||
|
inline T& try_emplace(const label i, Args&&... args);
|
||||||
|
|
||||||
//- Set element to given pointer and return old element (can be null)
|
//- Set element to given pointer and return old element (can be null)
|
||||||
// No-op if the new pointer value is identical to the current content.
|
// No-op if the new pointer value is identical to the current content.
|
||||||
inline autoPtr<T> set(const label i, T* ptr);
|
inline autoPtr<T> set(const label i, T* ptr);
|
||||||
|
|||||||
@ -195,6 +195,19 @@ inline T& Foam::PtrList<T>::emplace(const label i, Args&&... args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
template<class... Args>
|
||||||
|
inline T& Foam::PtrList<T>::try_emplace(const label i, Args&&... args)
|
||||||
|
{
|
||||||
|
T* ptr = UPtrList<T>::get(i);
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
return this->emplace_set(i, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline Foam::autoPtr<T> Foam::PtrList<T>::set(const label i, T* ptr)
|
inline Foam::autoPtr<T> Foam::PtrList<T>::set(const label i, T* ptr)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user