ENH: refine PtrList emplace method, add emplace for autoPtr/refPtr...

* resize_null() methods for PtrList variants
  - for cases where an existing PtrList needs a specific size and
    but not retain any existing entries.

    Eg,
        ptrs.resize_null(100);

    vs.   ptrs.free();     ptr.resize(100);
    or    ptr.resize(100); ptrs.free();

* remove stored pointer before emplacing PtrList elements
  - may reduce memory peaks

* STYLE: static_cast of (nullptr) instead of reinterpret_cast of (0)

* COMP: implement emplace_set() for PtrDynList
  - previously missing, which meant it would have leaked through to the
    underlying PtrList definition

* emplace methods for autoPtr, refPtr, tmp
  - applies reset() with forwarding arguments.
    For example,

        tmp<GeoField> tfld = ...;

    later...

        tfld.emplace(io, mesh);

    vs.
        tfld.reset(new GeoField(io, mesh));
    or
        tfld.reset(tmp<GeoField>::New(io, mesh));

    The emplace() obviously has reduced typing, but also allows the
    existing stored pointer to be deleted *before* creating its
    replacement (reduces memory peaks).
This commit is contained in:
Mark Olesen 2023-07-21 10:22:15 +02:00
parent 5e334c0686
commit 63258d0b33
23 changed files with 272 additions and 69 deletions

View File

@ -47,43 +47,39 @@ class Scalar
public:
Scalar()
static bool verbose;
constexpr Scalar() noexcept
:
data_(0)
{}
Scalar(scalar val)
Scalar(scalar val) noexcept
:
data_(val)
{}
~Scalar()
{
Info<< "delete Scalar: " << data_ << endl;
if (verbose) Info<< "delete Scalar: " << data_ << endl;
}
const scalar& value() const
{
return data_;
}
scalar& value()
{
return data_;
}
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& val)
friend Ostream& operator<<(Ostream& os, const Scalar& item)
{
os << val.data_;
os << item.value();
return os;
}
};
bool Scalar::verbose = true;
// As per
@ -268,6 +264,22 @@ Ostream& report
int main(int argc, char *argv[])
{
#if 1
{
DLPtrList<Scalar> llist1;
Info<< "emplace_front: " << llist1.emplace_front(100) << nl;
Info<< "emplace_front: " << llist1.emplace_front(200) << nl;
Info<< "emplace_front: " << llist1.emplace_front(300) << nl;
Info<< "emplace_back: " << llist1.emplace_back(500) << nl;
Info<< "DLPtrList: " << llist1 << endl;
Scalar::verbose = false;
llist1.clear();
Scalar::verbose = true;
}
#endif
#if 0
{
DLPtrList<Scalar> llist1;
@ -349,6 +361,16 @@ int main(int argc, char *argv[])
list2.emplace(i, (10 + 1.3*i));
}
#if 0
list2.release(5);
list2.release(10);
forAll(list2, i)
{
list2.try_emplace(i, (50 + 1.3*i));
}
#endif
PtrList<Scalar> listApp;
for (label i = 0; i < 5; ++i)
{
@ -639,7 +661,7 @@ int main(int argc, char *argv[])
dynPlanes.set(6, new plane(vector(2,2,1), vector::one));
dynPlanes.set(10, new plane(vector(4,5,6), vector::one));
Info<< "emplaced :"
Info<< "emplaced[12]: "
<< dynPlanes.emplace(12, vector(3,2,1), vector::one) << endl;
dynPlanes.emplace_back(Zero, vector::one);

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.
@ -84,6 +84,20 @@ struct DerivedList : public List<T>
};
template<class T>
void printInfo(const autoPtr<T>& item, const bool verbose = false)
{
Info<< "autoPtr good:" << Switch::name(item.good())
<< " addr: " << Foam::name(item.get());
if (verbose && item)
{
Info<< " content: " << item();
}
Info<< nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
@ -112,6 +126,17 @@ int main(int argc, char *argv[])
Info<<"move unique to autoPtr: " << *list3 << nl;
Info<<"old is " << Switch(bool(list2)) << nl;
Info<< "before emplace: ";
printInfo(list, true);
list.emplace(4, label(-2));
Info<< "after emplace: ";
printInfo(list, true);
list.emplace(2, label(-4));
Info<< "after emplace: ";
printInfo(list, true);
}
// Confirm that forwarding with move construct actually works as expected

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020-2022 OpenCFD Ltd.
Copyright (C) 2020-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -105,12 +105,21 @@ int main()
Info<< nl << "Construct from reference" << nl;
scalarField f2(10, Foam::sqrt(2.0));
printInfo(refPtr<scalarField>(f2), true);
refPtr<scalarField> tfld2(f2);
printInfo(tfld2, true);
Info<< nl << "emplaced:"<< nl;
tfld2.emplace(25, scalar(1));
printInfo(tfld2, true);
}
{
Info<< nl << "Construct from New (is_pointer)" << nl;
auto tfld1 = refPtr<scalarField>::New(10, scalar(1));
auto tfld1 = refPtr<scalarField>::New(10, scalar(-1));
printInfo(tfld1, true);
Info<< nl << "emplaced:"<< nl;
tfld1.emplace(15, scalar(1));
printInfo(tfld1, true);
Info<< nl << "Dereferenced: " << *tfld1 << nl;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -78,7 +78,10 @@ int main()
}
{
auto tfld1 = tmp<scalarField>::New(20, Zero);
auto tfld1 = tmp<scalarField>::New(10, Zero);
printInfo(tfld1, true);
tfld1.emplace(20, Zero);
printInfo(tfld1, true);
// Hold on to the old content for a bit

View File

@ -165,6 +165,24 @@ public:
return *(parent_type::back());
}
//- Emplace construct new element at front of list. Return reference.
template<class... Args>
T& emplace_front(Args&&... args)
{
T* ptr = new T(std::forward<Args>(args)...);
this->push_front(ptr);
return *ptr; // OR: return *(parent_type::front());
}
//- Emplace construct new element at back of list. Return reference.
template<class... Args>
T& emplace_back(Args&&... args)
{
T* ptr = new T(std::forward<Args>(args)...);
this->push_back(ptr);
return *ptr; // OR: return *(parent_type::back());
}
//- Remove first element(s) from the list (deletes pointers)
void pop_front(label n = 1);

View File

@ -34,8 +34,8 @@ Description
#ifndef Foam_SLList_H
#define Foam_SLList_H
#include "SLListBase.H"
#include "LList.H"
#include "SLListBase.H"
#include "SLListFwd.H"
#endif

View File

@ -34,8 +34,8 @@ Description
#ifndef Foam_SLPtrList_H
#define Foam_SLPtrList_H
#include "SLListBase.H"
#include "LPtrList.H"
#include "SLListBase.H"
#include "SLPtrListFwd.H"
#endif

View File

@ -109,6 +109,11 @@ public:
//- Alter the addressed list size.
inline void resize(const label newLen);
//- Set the addressed list to the given size,
//- deleting all existing entries.
//- Afterwards the list contains all \c nullptr entries.
inline void resize_null(const label newLen);
//- Clear the addressed list, i.e. set the size to zero.
// Allocated size does not change
inline void clear();
@ -174,7 +179,14 @@ public:
//- Construct and set a new element at given position,
//- (discard old element at that location).
//- Return reference to the new list element.
//- Auto-sizes list as required.
// \param i - the location to set
// \param args arguments to forward to the constructor of the element
// \return reference to the new list element.
template<class... Args>
inline T& emplace_set(const label i, Args&&... args);
//- Same as emplace_set()
template<class... Args>
inline T& emplace(const label i, Args&&... args);

View File

@ -140,10 +140,30 @@ inline void Foam::PtrDynList<T, SizeMin>::resize(const label newLen)
}
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::resize_null(const label newLen)
{
if (capacity_ < newLen)
{
// Increase capacity (doubling)
capacity_ = max(SizeMin, max(newLen, label(2*capacity_)));
PtrList<T>::resize_null(capacity_);
}
else
{
PtrList<T>::free(); // Free (and nullify) old pointers
}
// Adjust addressed size
PtrList<T>::setAddressableSize(newLen);
}
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::clear()
{
(this->ptrs_).free(); // free old pointers
PtrList<T>::free(); // Free (and nullify) old pointers
PtrList<T>::setAddressableSize(0);
}
@ -367,6 +387,22 @@ inline void Foam::PtrDynList<T, SizeMin>::pop_back(label n)
}
template<class T, int SizeMin>
template<class... Args>
inline T& Foam::PtrDynList<T, SizeMin>::emplace_set
(
const label i,
Args&&... args
)
{
if (i >= this->size())
{
resize(i+1);
}
return this->PtrList<T>::emplace_set(i, std::forward<Args>(args)...);
}
template<class T, int SizeMin>
template<class... Args>
inline T& Foam::PtrDynList<T, SizeMin>::emplace
@ -375,9 +411,7 @@ inline T& Foam::PtrDynList<T, SizeMin>::emplace
Args&&... args
)
{
T* ptr = new T(std::forward<Args>(args)...);
(void)this->set(i, ptr);
return *ptr;
return this->emplace_set(i, std::forward<Args>(args)...);
}

View File

@ -70,7 +70,7 @@ Foam::PtrList<T>::PtrList(const SLPtrList<T>& list)
template<class T>
Foam::PtrList<T>::~PtrList()
{
(this->ptrs_).free(); // free old pointers
(this->ptrs_).free(); // Free old pointers
}
@ -110,14 +110,10 @@ void Foam::PtrList<T>::resize(const label newLen)
else if (newLen != oldLen)
{
// Truncation frees old pointers
for (label i=newLen; i<oldLen; ++i)
for (label i = newLen; i < oldLen; ++i)
{
T* ptr = this->ptrs_[i];
if (ptr)
{
delete ptr;
}
delete this->ptrs_[i];
this->ptrs_[i] = nullptr;
}
// Any new elements are initialized to nullptr.

View File

@ -147,6 +147,11 @@ public:
// New entries are initialized to nullptr, removed entries are deleted
void resize(const label newLen);
//- Set the addressed list to the given size,
//- deleting all existing entries.
//- Afterwards the list contains all \c nullptr entries.
inline void resize_null(const label newLen);
//- Construct and append an element to the end of the list,
//- return reference to the new list element
template<class... Args>
@ -172,7 +177,9 @@ public:
//- Construct and set a new element at given position,
//- (discard old element at that location).
//- Return reference to the new list element.
// \param i - the location to set
// \param args arguments to forward to the constructor of the element
// \return reference to the new list element.
template<class... Args>
inline T& emplace_set(const label i, Args&&... args);

View File

@ -66,7 +66,7 @@ inline Foam::PtrList<T>::PtrList(UList<T*>& list)
UPtrList<T>(list)
{
// Took ownership of the pointers
list = reinterpret_cast<T*>(0);
list = static_cast<T*>(nullptr);
}
@ -87,7 +87,7 @@ inline Foam::PtrList<T>::PtrList
template<class T>
inline void Foam::PtrList<T>::clear()
{
(this->ptrs_).free(); // Free and nullify old pointers
(this->ptrs_).free(); // Free (and nullify) old pointers
UPtrList<T>::clear();
}
@ -99,6 +99,14 @@ inline void Foam::PtrList<T>::free()
}
template<class T>
inline void Foam::PtrList<T>::resize_null(const label newLen)
{
(this->ptrs_).free(); // Free (and nullify) old pointers
UPtrList<T>::resize_null(newLen);
}
template<class T>
template<class... Args>
inline T& Foam::PtrList<T>::emplace_back(Args&&... args)
@ -172,8 +180,9 @@ template<class T>
template<class... Args>
inline T& Foam::PtrList<T>::emplace_set(const label i, Args&&... args)
{
(void) this->release(i); // delete old entry
T* ptr = new T(std::forward<Args>(args)...);
(void)this->set(i, ptr);
(void) UPtrList<T>::set(i, ptr);
return *ptr;
}
@ -182,9 +191,7 @@ template<class T>
template<class... Args>
inline T& Foam::PtrList<T>::emplace(const label i, Args&&... args)
{
T* ptr = new T(std::forward<Args>(args)...);
(void)this->set(i, ptr);
return *ptr;
return this->emplace_set(i, std::forward<Args>(args)...);
}

View File

@ -96,26 +96,14 @@ Foam::label Foam::Detail::PtrListDetail<T>::find_next_not(label pos) const
}
template<class T>
void Foam::Detail::PtrListDetail<T>::setNull()
{
List<T*>& ptrs = *this;
const label len = ptrs.size();
for (label i=0; i<len; ++i)
{
ptrs[i] = nullptr;
}
}
template<class T>
void Foam::Detail::PtrListDetail<T>::free()
{
List<T*>& ptrs = *this;
const label len = ptrs.size();
for (label i=0; i<len; ++i)
// Presume they were allocated from front to back...
for (label i = len - 1; i >= 0; --i)
{
delete ptrs[i];
ptrs[i] = nullptr;
@ -133,7 +121,7 @@ Foam::Detail::PtrListDetail<T>::clone(Args&&... args) const
PtrListDetail<T> cloned(len);
for (label i=0; i<len; ++i)
for (label i = 0; i < len; ++i)
{
const T* ptr = ptrs[i];

View File

@ -128,10 +128,6 @@ public:
// \note Method name as per bitSet
label find_next_not(label pos) const;
//- Reassign all pointers to nullptr, without deleting.
//- Does not affect the list size.
void setNull();
//- Delete allocated entries and reassign to nullptr.
//- Does not affect the list size.
void free();
@ -144,6 +140,9 @@ public:
// New entries are initialized to nullptr.
inline void resize(const label newLen);
//- Set the list to the given size and set all entries to nullptr.
inline void resize_null(const label newLen);
//- Set addressed size to be inconsistent with allocated storage.
// Use with care
inline void setAddressableSize(const label n) noexcept;
@ -160,6 +159,9 @@ public:
//- Move assignment
inline void operator=(PtrListDetail<T>&& list);
//- Assign all entries to nullptr (without deleting)
inline void operator=(std::nullptr_t);
// Housekeeping

View File

@ -37,7 +37,7 @@ inline constexpr Foam::Detail::PtrListDetail<T>::PtrListDetail() noexcept
template<class T>
inline Foam::Detail::PtrListDetail<T>::PtrListDetail(const label len)
:
List<T*>(len, reinterpret_cast<T*>(0))
List<T*>(len, static_cast<T*>(nullptr))
{}
@ -118,7 +118,22 @@ inline void Foam::Detail::PtrListDetail<T>::resize(const label newLen)
else if (newLen != List<T*>::size())
{
// Truncate or extend. Any new elements are initialized to nullptr.
List<T*>::resize(newLen, reinterpret_cast<T*>(0));
List<T*>::resize(newLen, static_cast<T*>(nullptr));
}
}
template<class T>
inline void Foam::Detail::PtrListDetail<T>::resize_null(const label newLen)
{
if (newLen <= 0)
{
List<T*>::clear();
}
else
{
List<T*>::resize_nocopy(newLen);
List<T*>::operator=(static_cast<T*>(nullptr));
}
}
@ -159,4 +174,11 @@ inline void Foam::Detail::PtrListDetail<T>::operator=
}
template<class T>
inline void Foam::Detail::PtrListDetail<T>::operator=(std::nullptr_t)
{
List<T*>::operator=(static_cast<T*>(nullptr));
}
// ************************************************************************* //

View File

@ -218,7 +218,7 @@ public:
//- Default construct
inline constexpr UPtrList() noexcept;
//- Construct with specified size, each element initialized to nullptr
//- Construct with specified size and set all entries to \c nullptr
inline explicit UPtrList(const label len);
//- Copy construct (shallow copies addresses)
@ -299,9 +299,13 @@ public:
inline void free();
//- Change the size of the list.
// New entries are initialized to nullptr.
//- Any new entries are \c nullptr.
inline void resize(const label newLen);
//- Set the list to the given size
//- and set \em all entries to \c nullptr.
inline void resize_null(const label newLen);
//- Squeeze out nullptr entries in the list of pointers after which
//- any null pointers will be at the end of the list
// \return the number of non-null entries

View File

@ -208,7 +208,7 @@ inline void Foam::UPtrList<T>::clear()
template<class T>
inline void Foam::UPtrList<T>::free()
{
ptrs_.setNull();
ptrs_ = nullptr;
}
@ -261,6 +261,13 @@ inline void Foam::UPtrList<T>::resize(const label newLen)
}
template<class T>
inline void Foam::UPtrList<T>::resize_null(const label newLen)
{
ptrs_.resize_null(newLen);
}
template<class T>
inline void Foam::UPtrList<T>::push_back(T* ptr)
{

View File

@ -216,6 +216,11 @@ public:
// \remark Same as move assign, but better for code documentation
inline void reset(autoPtr<T>&& other) noexcept;
//- Reset with emplace construction.
//- Return reference to the new content.
template<class... Args>
inline T& emplace(Args&&... args);
//- Swaps the managed object with other autoPtr.
inline void swap(autoPtr<T>& other) noexcept;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -61,6 +61,16 @@ inline void Foam::autoPtr<T>::reset(autoPtr<T>&& other) noexcept
}
template<class T>
template<class... Args>
inline T& Foam::autoPtr<T>::emplace(Args&&... args)
{
delete ptr_; // delete old entry
ptr_ = new T(std::forward<Args>(args)...);
return *ptr_;
}
template<class T>
inline void Foam::autoPtr<T>::swap(autoPtr<T>& other) noexcept
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2018-2022 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -249,6 +249,11 @@ public:
//- Reference tmp contents or transfer pointer ownership if possible
inline void reset(tmp<T>& rhs, bool reuse);
//- Reset with emplace construction.
//- Return reference to the new content.
template<class... Args>
inline T& emplace(Args&&... args);
//- Clear existing and set (const) reference from other
inline void cref(const refPtr<T>& other) noexcept;

View File

@ -371,6 +371,17 @@ inline void Foam::refPtr<T>::reset(tmp<T>& other, bool reuse)
}
template<class T>
template<class... Args>
inline T& Foam::refPtr<T>::emplace(Args&&... args)
{
clear(); // delete old entry
ptr_ = new T(std::forward<Args>(args)...);
type_ = PTR;
return *ptr_;
}
template<class T>
inline void Foam::refPtr<T>::cref(const refPtr<T>& other) noexcept
{

View File

@ -272,6 +272,11 @@ public:
//- Avoid inadvertent casting (to object)
void reset(const refPtr<T>&) = delete;
//- Reset with emplace construction.
//- Return reference to the new content.
template<class... Args>
inline T& emplace(Args&&... args);
//- Clear existing and set (const) reference from other
inline void cref(const tmp<T>& other) noexcept;

View File

@ -354,6 +354,17 @@ inline void Foam::tmp<T>::reset(tmp<T>&& other) noexcept
}
template<class T>
template<class... Args>
inline T& Foam::tmp<T>::emplace(Args&&... args)
{
clear(); // delete old entry
ptr_ = new T(std::forward<Args>(args)...);
type_ = PTR;
return *ptr_;
}
template<class T>
inline void Foam::tmp<T>::cref(const tmp<T>& other) noexcept
{