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:
Mark Olesen
2023-07-25 15:45:23 +02:00
parent 11a1f78338
commit 03ca52b036
11 changed files with 190 additions and 85 deletions

View File

@ -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;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -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;

View File

@ -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:

View File

@ -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)
{ {
list2.try_emplace(i, (50 + 1.3*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));
}
} }
#endif
PtrList<Scalar> listApp; PtrList<Scalar> listApp;
for (label i = 0; i < 5; ++i) for (label i = 0; i < 5; ++i)

View File

@ -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;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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
( (

View File

@ -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);

View File

@ -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)
{ {