ENH: improved handling of PtrList copies/cloning

- the logic has been revised to allow list copying with nullptr entries.
  These previously would have thrown an error.

- remove PtrList trimTrailingNull() method.
  It was unused and would result in inconsistent addressing sizes.

FIX: inconsistent sizing used for DynamicList/PtrDynList clearStorage()

- older code did not reset addressable size prior to clearStorage()
  or transfer(). Only a latent bug until memory pools are used.
This commit is contained in:
Mark Olesen
2025-08-27 09:25:54 +02:00
parent a85b0f0736
commit 697b8a1436
15 changed files with 401 additions and 215 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -86,20 +86,7 @@ Ostream& printAddr
const UPtrList<T>& list
)
{
const label len = list.size();
// Size and start delimiter
os << nl << indent << len << nl
<< indent << token::BEGIN_LIST << incrIndent << nl;
for (label i=0; i < len; ++i)
{
os << "addr=" << Foam::name(list.get(i)) << nl;
}
// End delimiter
os << decrIndent << indent << token::END_LIST << nl;
return os;
return list.printAddresses(os);
}
@ -176,11 +163,11 @@ Ostream& print
{
const label cap = list.capacity();
for (label i=len; i < cap; ++i)
for (label i = len; i < cap; ++i)
{
const T* ptr = list.get(i);
os << "unused " << name(ptr) << nl;
os << "unused " << Foam::name(ptr) << nl;
}
}
@ -518,6 +505,7 @@ int main(int argc, char *argv[])
print(Info, dynlist1d);
Info<< "addresses:" << nl;
dynlist1d.printAddresses(Info, true);
printAddr(Info, dynlist1d);
PtrList<Scalar> list1d;

View File

@ -255,7 +255,7 @@ public:
// Edit
//- Swap with plain List content. Implies shrink_to_fit().
inline void swap(List<T>& list);
inline void swap(List<T>& other);
//- Swap content, independent of sizing parameter
template<int AnySizeMin>
@ -264,7 +264,7 @@ public:
//- Transfer contents of the argument List into this.
inline void transfer(List<T>& list);
//- Transfer contents of any sized DynamicList into this.
//- Transfer contents of any DynamicList into this.
template<int AnySizeMin>
inline void transfer(DynamicList<T, AnySizeMin>& list);

View File

@ -445,6 +445,8 @@ inline void Foam::DynamicList<T, SizeMin>::clear() noexcept
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::clearStorage()
{
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
List<T>::clear();
capacity_ = 0;
}
@ -465,12 +467,15 @@ inline void Foam::DynamicList<T, SizeMin>::shrink_to_fit()
template<class T, int SizeMin>
inline void
Foam::DynamicList<T, SizeMin>::swap(List<T>& list)
Foam::DynamicList<T, SizeMin>::swap(List<T>& other)
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&other)
)
)
{
return; // Self-swap is a no-op
@ -480,7 +485,7 @@ Foam::DynamicList<T, SizeMin>::swap(List<T>& list)
this->shrink_to_fit();
// Swap storage and addressable size
UList<T>::swap(list);
UList<T>::swap(other);
// Update capacity
capacity_ = List<T>::size();
@ -496,8 +501,11 @@ inline void Foam::DynamicList<T, SizeMin>::swap
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&other)
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&other)
)
)
{
return; // Self-swap is a no-op
@ -515,6 +523,10 @@ template<class T, int SizeMin>
inline void
Foam::DynamicList<T, SizeMin>::transfer(List<T>& list)
{
// No check for self-assignment (different types)
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
List<T>::transfer(list);
capacity_ = List<T>::size();
}
@ -530,18 +542,22 @@ Foam::DynamicList<T, SizeMin>::transfer
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
// Take over storage as-is (without shrink)
capacity_ = list.capacity();
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
List<T>::transfer(static_cast<List<T>&>(list));
list.clearStorage(); // capacity=0 etc.
capacity_ = list.capacity();
list.setCapacity_unsafe(0); // All contents moved
}
@ -594,7 +610,14 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
const UList<T>& list
)
{
if (FOAM_UNLIKELY(this == &list))
if
(
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
FatalErrorInFunction
<< "Attempted push_back to self"
@ -665,7 +688,14 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
List<T>&& list
)
{
if (FOAM_UNLIKELY(this == &list))
if
(
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
FatalErrorInFunction
<< "Attempted push_back to self"
@ -675,6 +705,7 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
const label idx = List<T>::size();
resize(idx + list.size());
// Move the elements
std::move(list.begin(), list.end(), this->begin(idx));
list.clear();
@ -688,7 +719,26 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
DynamicList<T, AnySizeMin>&& list
)
{
push_back(std::move(static_cast<List<T>&>(list)));
if
(
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
FatalErrorInFunction
<< "Attempted push_back to self"
<< abort(FatalError);
}
const label idx = List<T>::size();
resize(idx + list.size());
// Move the elements
std::move(list.begin(), list.end(), this->begin(idx));
list.clearStorage(); // Deletion, capacity=0 etc.
}
@ -866,15 +916,22 @@ inline void Foam::DynamicList<T, SizeMin>::operator=
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::operator=
(
const DynamicList<T, SizeMin>& lst
const DynamicList<T, SizeMin>& list
)
{
if (this == &lst)
if
(
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
doAssignDynList(lst);
doAssignDynList(list);
}
@ -887,8 +944,11 @@ inline void Foam::DynamicList<T, SizeMin>::operator=
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
@ -912,44 +972,41 @@ template<class T, int SizeMin>
template<class Addr>
inline void Foam::DynamicList<T, SizeMin>::operator=
(
const IndirectListBase<T, Addr>& lst
const IndirectListBase<T, Addr>& list
)
{
// NOTE: Self-assignment needs special handling
/// if
/// (
/// static_cast<const UList<T>*>(this)
/// == static_cast<const UList<T>*>(&list.values())
/// )
// if
// (
// FOAM_UNLIKELY
// (
// static_cast<const UList<T>*>(this)
// == static_cast<const UList<T>*>(&list.values())
// )
// )
// { ... }
doAssignDynList(lst);
doAssignDynList(list);
}
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::operator=
(
List<T>&& lst
List<T>&& list
)
{
clear();
transfer(lst);
this->transfer(list);
}
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::operator=
(
DynamicList<T, SizeMin>&& lst
DynamicList<T, SizeMin>&& list
)
{
if (this == &lst)
{
return; // Self-assignment is a no-op
}
clear();
transfer(lst);
this->transfer(list);
}
@ -960,17 +1017,7 @@ inline void Foam::DynamicList<T, SizeMin>::operator=
DynamicList<T, AnySizeMin>&& list
)
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
)
{
return; // Self-assignment is a no-op
}
clear();
transfer(list);
this->transfer(list);
}

View File

@ -238,14 +238,18 @@ public:
//- Auto-sizes list as required.
inline autoPtr<T> set(const label i, const tmp<T>& ptr);
//- Reorder elements. Reordering must be unique (ie, shuffle).
inline void reorder(const labelUList& oldToNew);
// Writing
//- Print pointer addresses to Ostream (debugging only).
// Optionally print addresses within the upper (capacity) region
Ostream& printAddresses(Ostream& os, const bool full=false) const;
// Member Operators
//- Copy (clone) assignment
inline void operator=(const PtrList<T>& list);
inline void operator=(const UPtrList<T>& list);
//- Copy (clone) assignment
inline void operator=(const PtrDynList<T, SizeMin>& list);

View File

@ -226,6 +226,8 @@ inline void Foam::PtrDynList<T, SizeMin>::clear()
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::clearStorage()
{
// Consistent allocated sizing
PtrList<T>::setAddressableSize(capacity_);
PtrList<T>::clear();
capacity_ = 0;
}
@ -258,8 +260,11 @@ inline void Foam::PtrDynList<T, SizeMin>::swap(PtrList<T>& list)
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
)
)
{
return; // Self-swap is a no-op
@ -285,8 +290,11 @@ inline void Foam::PtrDynList<T, SizeMin>::swap
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&other)
FOAM_UNLIKELY
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&other)
)
)
{
return; // Self-swap is a no-op
@ -303,15 +311,10 @@ inline void Foam::PtrDynList<T, SizeMin>::swap
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::transfer(PtrList<T>& list)
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
)
{
return; // Self assignment is a no-op
}
// No check for self-assignment (different types)
// Consistent allocated sizing
PtrList<T>::setAddressableSize(capacity_);
PtrList<T>::transfer(list);
capacity_ = PtrList<T>::size();
}
@ -326,18 +329,22 @@ inline void Foam::PtrDynList<T, SizeMin>::transfer
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
)
)
{
return; // Self assignment is a no-op
}
// Take over storage as-is (without shrink)
capacity_ = list.capacity();
// Consistent allocated sizing
PtrList<T>::setAddressableSize(capacity_);
PtrList<T>::transfer(static_cast<PtrList<T>&>(list));
list.clearStorage(); // capacity=0 etc.
capacity_ = list.capacity();
list.setCapacity_unsafe(0); // All contents moved
}
@ -414,8 +421,11 @@ inline void Foam::PtrDynList<T, SizeMin>::push_back
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&other)
FOAM_UNLIKELY
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&other)
)
)
{
FatalErrorInFunction
@ -557,11 +567,20 @@ inline Foam::autoPtr<T> Foam::PtrDynList<T, SizeMin>::set
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::reorder(const labelUList& oldToNew)
Foam::Ostream& Foam::PtrDynList<T, SizeMin>::printAddresses
(
Ostream& os,
const bool full
) const
{
// Shrinking first is a bit annoying, but saves needing a special version.
this->shrink_to_fit();
PtrList<T>::reorder(oldToNew);
if (full)
{
return this->ptrs_.printAddresses(os, capacity_);
}
else
{
return UPtrList<T>::printAddresses(os);
}
}
@ -570,16 +589,23 @@ inline void Foam::PtrDynList<T, SizeMin>::reorder(const labelUList& oldToNew)
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::operator=
(
const PtrList<T>& list
const UPtrList<T>& list
)
{
if (this == &list)
if
(
FOAM_UNLIKELY
(
static_cast<const UPtrList<T>*>(this)
== static_cast<const UPtrList<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
this->resize(list.size());
PtrList<T>::operator=(list);
capacity_ = PtrList<T>::size();
}
@ -589,13 +615,20 @@ inline void Foam::PtrDynList<T, SizeMin>::operator=
const PtrDynList<T, SizeMin>& list
)
{
if (this == &list)
if
(
FOAM_UNLIKELY
(
static_cast<const UPtrList<T>*>(this)
== static_cast<const UPtrList<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
PtrList<T>::operator=(list);
capacity_ = PtrList<T>::size();
this->resize(list.size());
PtrList<T>::operator=(static_cast<UPtrList<T>&>(list));
}
@ -608,14 +641,18 @@ inline void Foam::PtrDynList<T, SizeMin>::operator=
{
if
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const PtrList<T>*>(this)
== static_cast<const PtrList<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
PtrList<T>::operator=(list);
this->resize(list.size());
PtrList<T>::operator=(static_cast<UPtrList<T>&>(list));
capacity_ = PtrList<T>::size();
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2019 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,26 +29,55 @@ License
#include "PtrList.H"
#include "SLPtrList.H"
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class T>
Foam::PtrList<T>::PtrList(PtrList<T>& list, bool reuse)
:
UPtrList<T>(list, reuse)
template<bool CheckSelf>
void Foam::PtrList<T>::copyPtrList(const UPtrList<T>& list)
{
if (!reuse)
// Check for self-assignment here instead of caller
if constexpr (CheckSelf)
{
// This works like an inplace clone method
const label len = this->size();
for (label i=0; i<len; ++i)
if (FOAM_UNLIKELY(this == &list))
{
this->ptrs_[i] = (list[i]).clone().ptr();
return; // Self-assignment is a no-op
}
}
const label len = list.size();
// Truncate (frees old pointers) or extend the length
PtrList<T>::resize(len);
for (label i = 0; i < len; ++i)
{
const T* src = list.get(i);
if (src)
{
if (this->ptrs_[i])
{
// Deep copy values into existing destination
*(this->ptrs_[i]) = *src;
}
else
{
// Clone pointers for new entries
this->ptrs_[i] = src->clone().ptr();
}
}
else
{
// No source pointer, so remove destination (if any) too
delete this->ptrs_[i];
this->ptrs_[i] = nullptr;
}
}
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
template<class T>
Foam::PtrList<T>::PtrList(const SLPtrList<T>& list)
:
@ -122,45 +151,4 @@ void Foam::PtrList<T>::resize(const label newLen)
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T>
void Foam::PtrList<T>::operator=(const PtrList<T>& list)
{
if (this == &list)
{
return; // Self-assignment is a no-op
}
const label oldLen = this->size();
const label newLen = list.size();
// Truncate (frees old pointers) or extend the length
resize(newLen);
if (newLen < oldLen)
{
// Copy values for existing entries
for (label i=0; i<newLen; ++i)
{
(*this)[i] = list[i];
}
}
else
{
// Copy values for existing entries
for (label i=0; i<oldLen; ++i)
{
(*this)[i] = list[i];
}
// Clone pointers for new entries
for (label i=oldLen; i<newLen; ++i)
{
this->ptrs_[i] = (list[i]).clone().ptr();
}
}
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -70,6 +70,15 @@ class PtrList
:
public UPtrList<T>
{
// Private Member Functions
//- Copy assignment.
// For existing list entries, values are copied from the list.
// For new list entries, pointers are cloned from the list.
template<bool CheckSelf>
void copyPtrList(const UPtrList<T>& list);
protected:
// Protected Member Functions
@ -103,7 +112,7 @@ public:
inline PtrList(const PtrList<T>& list, const CloneArg& cloneArgs);
//- Construct as copy or re-use as specified
PtrList(PtrList<T>& list, bool reuse);
inline PtrList(PtrList<T>& list, bool reuse);
//- Copy construct using 'clone()' on each element of SLPtrList\<T\>
explicit PtrList(const SLPtrList<T>& list);
@ -221,6 +230,11 @@ public:
// Member Operators
//- Copy assignment.
// For existing list entries, values are copied from the list.
// For new list entries, pointers are cloned from the list.
void operator=(const UPtrList<T>& list);
//- Copy assignment.
// For existing list entries, values are copied from the list.
// For new list entries, pointers are cloned from the list.

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -60,6 +60,23 @@ inline Foam::PtrList<T>::PtrList(PtrList<T>&& list) noexcept
{}
template<class T>
inline Foam::PtrList<T>::PtrList(PtrList<T>& list, bool reuse)
:
UPtrList<T>()
{
if (reuse)
{
transfer(list);
}
else
{
// No check for self-assignment
copyPtrList<false>(list);
}
}
template<class T>
inline Foam::PtrList<T>::PtrList(UList<T*>& list)
:
@ -278,7 +295,7 @@ inline Foam::autoPtr<T> Foam::PtrList<T>::release(const label i)
template<class T>
inline void Foam::PtrList<T>::transfer(PtrList<T>& list)
{
if (this == &list)
if (FOAM_UNLIKELY(this == &list))
{
return; // Self-assignment is a no-op
}
@ -290,6 +307,22 @@ inline void Foam::PtrList<T>::transfer(PtrList<T>& list)
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T>
inline void Foam::PtrList<T>::operator=(const UPtrList<T>& list)
{
// With check for self-assignment
this->copyPtrList<true>(list);
}
template<class T>
inline void Foam::PtrList<T>::operator=(const PtrList<T>& list)
{
// With check for self-assignment
this->copyPtrList<true>(list);
}
template<class T>
inline void Foam::PtrList<T>::operator=(PtrList<T>&& list)
{

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -99,11 +99,10 @@ Foam::label Foam::Detail::PtrListDetail<T>::find_next_not(label pos) const
template<class T>
void Foam::Detail::PtrListDetail<T>::free()
{
List<T*>& ptrs = *this;
const label len = ptrs.size();
// Presume they were allocated from front to back...
for (label i = len - 1; i >= 0; --i)
List<T*>& ptrs = *this;
for (auto i = this->size()-1; i >= 0; --i)
{
delete ptrs[i];
ptrs[i] = nullptr;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -147,6 +147,10 @@ public:
// Use with care
inline void setAddressableSize(const label n) noexcept;
//- Write pointer values to Ostream (debugging only).
// Optionally allow addressing beyond the regular range
Ostream& printAddresses(Ostream& os, label maxLen = -1) const;
//- Write output, optionally silently trimming nullptrs
Ostream& write(Ostream& os, const bool trimNull=false) const;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,6 +31,45 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
Foam::Ostream& Foam::Detail::PtrListDetail<T>::printAddresses
(
Ostream& os,
label maxLen
) const
{
if (maxLen <= 0)
{
maxLen = this->size();
}
const label len = Foam::min(this->size(), maxLen);
// The (output) size and start delimiter
os << nl << indent << maxLen << nl
<< indent << token::BEGIN_LIST << nl;
// const T* const * iter = this->cdata();
const auto* iter = this->cdata();
// Contents
for (label i = 0; i < len; ++i)
{
os << indent << " " << Foam::name(iter[i]) << nl;
}
for (label i = len; i < maxLen; ++i)
{
os << indent << " [" << Foam::name(iter[i]) << ']' << nl;
}
// End delimiter
os << indent << token::END_LIST << nl;
os.check(FUNCTION_NAME);
return os;
}
template<class T>
Foam::Ostream& Foam::Detail::PtrListDetail<T>::write
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
Copyright (C) 2015-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -65,23 +65,6 @@ Foam::label Foam::UPtrList<T>::squeezeNull()
}
template<class T>
void Foam::UPtrList<T>::trimTrailingNull()
{
label newLen = this->size();
for (label i = newLen-1; i >= 0 && !ptrs_[i]; --i)
{
--newLen;
}
// Or mutable?
// const_cast<Detail::PtrListDetail<T>&>(ptrs_).setAddressableSize(newLen);
ptrs_.setAddressableSize(newLen);
}
template<class T>
void Foam::UPtrList<T>::reorder(const labelUList& oldToNew, const bool check)
{
@ -98,7 +81,7 @@ void Foam::UPtrList<T>::reorder(const labelUList& oldToNew, const bool check)
Detail::PtrListDetail<T> newList(len);
for (label i=0; i<len; ++i)
for (label i = 0; i < len; ++i)
{
const label newIdx = oldToNew[i];
@ -127,7 +110,8 @@ void Foam::UPtrList<T>::reorder(const labelUList& oldToNew, const bool check)
newList.checkNonNull();
}
ptrs_.transfer(newList);
// Copy the pointers, do not swap or transfer lists!
ptrs_ = newList;
}
@ -148,7 +132,7 @@ void Foam::UPtrList<T>::sortOrder(const labelUList& order, const bool check)
Detail::PtrListDetail<T> newList(len);
Detail::PtrListDetail<T> guard(len);
for (label i=0; i<len; ++i)
for (label i = 0; i < len; ++i)
{
const label oldIdx = order[i];
@ -179,16 +163,35 @@ void Foam::UPtrList<T>::sortOrder(const labelUList& order, const bool check)
newList.checkNonNull();
}
ptrs_.transfer(newList);
// Copy the pointers, do not swap or transfer lists!
ptrs_ = newList;
}
// * * * * * * * * * * * * * * * Ostream Operators * * * * * * * * * * * * * //
template<class T>
Foam::Ostream& Foam::UPtrList<T>::printAddresses(Ostream& os) const
{
return ptrs_.printAddresses(os);
}
template<class T>
Foam::Ostream& Foam::UPtrList<T>::writeList
(
Ostream& os,
const bool trimNull
) const
{
return ptrs_.write(os, trimNull);
}
template<class T>
Foam::Ostream& Foam::operator<<(Ostream& os, const UPtrList<T>& list)
{
return list.ptrs_.write(os);
return list.writeList(os, false); // Do not ignore null
}

View File

@ -314,10 +314,6 @@ public:
// \return the number of non-null entries
label squeezeNull();
//- Reduce addressable list size to ignore any trailing null pointers.
// The reduces the effective list length without reallocation
void trimTrailingNull();
//- Append an element to the end of the list
inline void push_back(T* ptr);
@ -382,9 +378,18 @@ public:
inline void operator=(UPtrList<T>&& list);
// Writing
//- Print pointer addresses to Ostream (debugging only)
Ostream& printAddresses(Ostream& os) const;
//- Write UPtrList to Ostream, optionally ignoring null entries
Ostream& writeList(Ostream& os, const bool trimNull=false) const;
// IOstream Operators
//- Write UPtrList to Ostream
//- Write UPtrList to Ostream. Does not ignore null entries
friend Ostream& operator<< <T>(Ostream& os, const UPtrList<T>& list);

View File

@ -269,7 +269,7 @@ public:
// Edit
//- Swap with plain List content. Implies shrink_to_fit().
inline void swap(List<T>& list);
inline void swap(List<T>& other);
//- Swap content, independent of sizing parameter
template<int AnySizeMin>

View File

@ -567,12 +567,12 @@ inline void Foam::DynamicField<T, SizeMin>::shrink_to_fit()
template<class T, int SizeMin>
inline void
Foam::DynamicField<T, SizeMin>::swap(List<T>& list)
Foam::DynamicField<T, SizeMin>::swap(List<T>& other)
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
== static_cast<const List<T>*>(&other)
)
{
return; // Self-swap is a no-op
@ -582,7 +582,7 @@ Foam::DynamicField<T, SizeMin>::swap(List<T>& list)
this->shrink_to_fit();
// Swap storage and addressable size
UList<T>::swap(list);
UList<T>::swap(other);
// Update capacity
capacity_ = List<T>::size();
@ -658,17 +658,22 @@ inline void Foam::DynamicField<T, SizeMin>::transfer
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const UList<T>*>(this)
== static_cast<const UList<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
// Take over storage as-is (without shrink)
capacity_ = list.capacity();
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
Field<T>::transfer(static_cast<List<T>&>(list));
list.clearStorage(); // capacity=0 etc.
capacity_ = list.capacity();
list.setCapacity_unsafe(0); // All contents moved
}
@ -681,17 +686,22 @@ inline void Foam::DynamicField<T, SizeMin>::transfer
{
if
(
static_cast<const List<T>*>(this)
== static_cast<const List<T>*>(&list)
FOAM_UNLIKELY
(
static_cast<const UList<T>*>(this)
== static_cast<const UList<T>*>(&list)
)
)
{
return; // Self-assignment is a no-op
}
// Take over storage as-is (without shrink)
capacity_ = list.capacity();
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
Field<T>::transfer(static_cast<List<T>&>(list));
list.clearStorage(); // capacity=0 etc.
capacity_ = list.capacity();
list.setCapacity_unsafe(0); // All contents moved
}
@ -744,7 +754,14 @@ inline void Foam::DynamicField<T, SizeMin>::push_back
const UList<T>& list
)
{
if (this == &list)
if
(
FOAM_UNLIKELY
(
static_cast<const UList<T>*>(this)
== static_cast<const UList<T>*>(&list)
)
)
{
FatalErrorInFunction
<< "Attempted push_back to self"
@ -764,7 +781,14 @@ inline void Foam::DynamicField<T, SizeMin>::push_back
List<T>&& list
)
{
if (this == &list)
if
(
FOAM_UNLIKELY
(
static_cast<const UList<T>*>(this)
== static_cast<const UList<T>*>(&list)
)
)
{
FatalErrorInFunction
<< "Attempted push_back to self"
@ -774,6 +798,7 @@ inline void Foam::DynamicField<T, SizeMin>::push_back
const label idx = List<T>::size();
resize(idx + list.size());
// Move the elements
std::move(list.begin(), list.end(), this->begin(idx));
list.clear();
@ -880,7 +905,7 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
List<T>&& list
)
{
transfer(list);
this->transfer(list);
}
@ -890,7 +915,7 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
DynamicField<T, SizeMin>&& list
)
{
transfer(list);
this->transfer(list);
}
@ -901,7 +926,7 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
DynamicField<T, AnySizeMin>&& list
)
{
transfer(list);
this->transfer(list);
}
@ -912,7 +937,7 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
DynamicList<T, AnySizeMin>&& list
)
{
transfer(list);
this->transfer(list);
}