ENH: simplify copy/filling of List containers. Make swap noexcept

- internal use of std::fill instead of legacy manual code

- use UList<T>::deepCopy() to reduce code duplication
This commit is contained in:
Mark Olesen
2023-07-27 13:03:25 +02:00
parent 3430ab3aa8
commit f717f79833
13 changed files with 169 additions and 221 deletions

View File

@ -250,7 +250,7 @@ public:
//- Swap content, independent of sizing parameter
template<int AnySizeMin>
inline void swap(DynamicList<T, AnySizeMin>& other);
inline void swap(DynamicList<T, AnySizeMin>& other) noexcept;
//- Transfer contents of the argument List into this.
inline void transfer(List<T>& list);

View File

@ -373,6 +373,18 @@ inline void Foam::DynamicList<T, SizeMin>::resize_nocopy
}
// template<class T, int SizeMin>
// inline void Foam::DynamicList<T, SizeMin>::resize_fill
// (
// const label len,
// const T& val
// )
// {
// this->doResize(true, len); // nocopy = true
// this->fill_uniform(val);
// }
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::resize
(
@ -448,7 +460,7 @@ template<int AnySizeMin>
inline void Foam::DynamicList<T, SizeMin>::swap
(
DynamicList<T, AnySizeMin>& other
)
) noexcept
{
if
(

View File

@ -43,13 +43,10 @@ Foam::DynamicList<T, SizeMin>::DynamicList(Istream& is)
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template<class T, int SizeMin>
Foam::Istream& Foam::DynamicList<T, SizeMin>::readList
(
Istream& is
)
Foam::Istream& Foam::DynamicList<T, SizeMin>::readList(Istream& is)
{
DynamicList<T, SizeMin>& list = *this;

View File

@ -28,6 +28,7 @@ License
#include "UList.H"
#include "SLList.H"
// <algorithm> already included by stdFoam.H
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
@ -372,6 +373,7 @@ inline void Foam::FixedList<T, N>::resize_nocopy(const label n)
template<class T, unsigned N>
inline void Foam::FixedList<T, N>::fill(const T& val)
{
// Usually small enough that parallel execution is pointless...
for (unsigned i=0; i<N; ++i)
{
v_[i] = val;
@ -382,6 +384,7 @@ inline void Foam::FixedList<T, N>::fill(const T& val)
template<class T, unsigned N>
inline void Foam::FixedList<T, N>::fill(const Foam::zero)
{
// Usually small enough that parallel execution is pointless...
for (unsigned i=0; i<N; ++i)
{
v_[i] = Zero;

View File

@ -244,10 +244,8 @@ Foam::Istream& Foam::FixedList<T, N>::readList
"reading the single entry"
);
for (unsigned i=0; i<N; ++i)
{
list[i] = elem; // Copy the value
}
// Fill with the value
this->fill(elem);
}
// End of contents marker

View File

@ -54,7 +54,7 @@ void Foam::List<T>::doResize(const label len)
// - when used as storage for DynamicList, it is possible to have
// a zero-sized List with a non-null data pointer.
if (this->v_) delete[] this->v_;
delete[] this->v_;
this->size_ = len;
this->v_ = new T[len];
}
@ -64,7 +64,9 @@ void Foam::List<T>::doResize(const label len)
T* nv = new T[len];
// ie, std::copy(this->v_, this->v_ + overlap, nv);
// Like std::copy(this->v_, this->v_ + overlap, nv);
// but with move semantics!
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
@ -137,12 +139,7 @@ Foam::List<T>::List(const label len, const T& val)
if (len)
{
doAlloc();
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
{
vp[i] = val;
}
this->fill_uniform(val);
}
}
@ -163,8 +160,9 @@ Foam::List<T>::List(const label len, const Foam::zero)
{
doAlloc();
// fill_uniform()
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
for (label i = 0; i < len; ++i)
{
vp[i] = Zero;
}
@ -200,109 +198,49 @@ Foam::List<T>::List(const Foam::one, const Foam::zero)
template<class T>
Foam::List<T>::List(const UList<T>& a)
Foam::List<T>::List(const UList<T>& list)
:
UList<T>(nullptr, a.size_)
UList<T>(nullptr, list.size_)
{
const label len = this->size_;
if (len)
if (this->size_ > 0)
{
doAlloc();
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
std::memcpy
(
static_cast<void*>(this->v_), a.v_, this->size_bytes()
);
}
else
#endif
{
List_ACCESS(T, (*this), vp);
List_CONST_ACCESS(T, a, ap);
for (label i = 0; i < len; ++i)
{
vp[i] = ap[i];
}
}
UList<T>::deepCopy(list);
}
}
template<class T>
Foam::List<T>::List(const List<T>& a)
Foam::List<T>::List(const List<T>& list)
:
UList<T>(nullptr, a.size_)
UList<T>(nullptr, list.size_)
{
const label len = this->size_;
if (len)
if (this->size_ > 0)
{
doAlloc();
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
std::memcpy
(
static_cast<void*>(this->v_), a.v_, this->size_bytes()
);
}
else
#endif
{
List_ACCESS(T, (*this), vp);
List_CONST_ACCESS(T, a, ap);
for (label i = 0; i < len; ++i)
{
vp[i] = ap[i];
}
}
UList<T>::deepCopy(list);
}
}
template<class T>
Foam::List<T>::List(List<T>& a, bool reuse)
Foam::List<T>::List(List<T>& list, bool reuse)
:
UList<T>(nullptr, a.size_)
UList<T>(nullptr, list.size_)
{
if (reuse)
{
// Steal content
this->v_ = a.v_;
a.v_ = nullptr;
a.size_ = 0;
this->v_ = list.v_;
list.v_ = nullptr;
list.size_ = 0;
return;
}
const label len = this->size_;
if (len)
if (this->size_)
{
doAlloc();
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
std::memcpy
(
static_cast<void*>(this->v_), a.v_, this->size_bytes()
);
}
else
#endif
{
List_ACCESS(T, (*this), vp);
List_CONST_ACCESS(T, a, ap);
for (label i = 0; i < len; ++i)
{
vp[i] = ap[i];
}
}
UList<T>::deepCopy(list);
}
}
@ -318,6 +256,7 @@ Foam::List<T>::List(const UList<T>& list, const labelUList& indices)
{
doAlloc();
// Copy indirect
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
@ -340,13 +279,16 @@ Foam::List<T>::List
{
const label len = label(N);
doAlloc();
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
{
vp[i] = list[indices[i]];
doAlloc();
// Copy indirect
List_ACCESS(T, (*this), vp);
for (label i = 0; i < len; ++i)
{
vp[i] = list[indices[i]];
}
}
}
@ -431,10 +373,7 @@ Foam::List<T>::List(SLList<T>&& list)
template<class T>
Foam::List<T>::~List()
{
if (this->v_)
{
delete[] this->v_;
}
delete[] this->v_;
}
@ -443,14 +382,16 @@ Foam::List<T>::~List()
template<class T>
void Foam::List<T>::resize(const label len, const T& val)
{
label idx = this->size_;
const label oldLen = this->size_;
this->doResize(len);
List_ACCESS(T, *this, vp);
while (idx < len)
// Fill trailing part with new values
if (oldLen < this->size_)
{
vp[idx] = val;
++idx;
std::fill
(
(this->v_ + oldLen), (this->v_ + this->size_), val
);
}
}
@ -463,7 +404,7 @@ void Foam::List<T>::transfer(List<T>& list)
return; // Self-assignment is a no-op
}
// Clear and swap - could also check for self assignment
// Clear and swap
clear();
this->size_ = list.size_;
this->v_ = list.v_;
@ -489,37 +430,18 @@ void Foam::List<T>::transfer(DynamicList<T, SizeMin>& list)
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T>
void Foam::List<T>::operator=(const UList<T>& a)
void Foam::List<T>::operator=(const UList<T>& list)
{
if (this == &a)
if (this == &list)
{
return; // Self-assignment is a no-op
}
reAlloc(a.size_);
reAlloc(list.size_);
const label len = this->size_;
if (len)
if (this->size_ > 0)
{
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
std::memcpy
(
static_cast<void*>(this->v_), a.v_, this->size_bytes()
);
}
else
#endif
{
List_ACCESS(T, (*this), vp);
List_CONST_ACCESS(T, a, ap);
for (label i = 0; i < len; ++i)
{
vp[i] = ap[i];
}
}
UList<T>::deepCopy(list);
}
}
@ -532,7 +454,12 @@ void Foam::List<T>::operator=(const List<T>& list)
return; // Self-assignment is a no-op
}
operator=(static_cast<const UList<T>&>(list));
reAlloc(list.size_);
if (this->size_ > 0)
{
UList<T>::deepCopy(list);
}
}
@ -545,6 +472,8 @@ void Foam::List<T>::operator=(const SLList<T>& list)
if (len)
{
// std::copy(list.begin(), list.end(), this->v_);
T* iter = this->begin();
for (const T& val : list)
@ -582,6 +511,7 @@ void Foam::List<T>::operator=(const IndirectListBase<T, Addr>& list)
if (len)
{
// copyList ...
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)

View File

@ -85,7 +85,7 @@ class List
// Discards old storage (if any). Does not copy old contents
inline void reAlloc(const label len);
//- Copy all list contents
//- Copy all list contents. Uses operator[] on the input list
template<class List2>
inline void copyList(const List2& list);
@ -142,13 +142,13 @@ public:
List(const Foam::one, const Foam::zero);
//- Copy construct from list
List(const List<T>& a);
List(const List<T>& list);
//- Copy construct contents from list
explicit List(const UList<T>& a);
explicit List(const UList<T>& list);
//- Construct as copy or re-use as specified
List(List<T>& a, bool reuse);
List(List<T>& list, bool reuse);
//- Copy construct subset of list
List(const UList<T>& list, const labelUList& indices);

View File

@ -55,11 +55,14 @@ template<class T>
template<class List2>
inline void Foam::List<T>::copyList(const List2& list)
{
// NB: operator[] for list read access (eg, an indirect list)
// cannot necessarily replace with std::copy
const label len = this->size_;
for (label i=0; i<len; ++i)
for (label i = 0; i < len; ++i)
{
this->operator[](i) = list[i];
this->v_[i] = list[i];
}
}
@ -79,10 +82,13 @@ inline Foam::List<T>::List
{
doAlloc();
// Like std::copy() or std::copy_n()
// but without any requirements on the iterator category
InputIterator iter = begIter;
for (label i = 0; i < len; ++i)
{
this->operator[](i) = *iter;
this->v_[i] = *iter;
++iter;
}
}
@ -149,6 +155,14 @@ inline void Foam::List<T>::resize_nocopy(const label len)
}
// template<class T>
// inline void Foam::List<T>::resize_fill(const label len, const T& val)
// {
// this->reAlloc(len);
// this->fill_uniform(val);
// }
template<class T>
inline T& Foam::List<T>::newElmt(const label i)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2022 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -50,9 +50,6 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
{
List<T>& list = *this;
// Anull list
list.clear();
is.fatalCheck(FUNCTION_NAME);
token tok(is);
@ -63,6 +60,7 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
{
// Compound: simply transfer contents
list.clear(); // Clear old contents
list.transfer
(
dynamicCast<token::Compound<List<T>>>
@ -77,8 +75,8 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
const label len = tok.labelToken();
// Resize to actual length read
list.resize(len);
// Resize to length required
list.resize_nocopy(len);
if (is.format() == IOstreamOption::BINARY && is_contiguous<T>::value)
{
@ -96,7 +94,7 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
is.fatalCheck
(
"List<T>::readList(Istream&) : "
"reading the binary block"
"reading binary block"
);
}
}
@ -133,10 +131,8 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
"reading the single entry"
);
for (label i=0; i<len; ++i)
{
list[i] = elem; // Copy the value
}
// Fill with the value
this->fill_uniform(elem);
}
}
@ -148,6 +144,8 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
{
// "(...)" : read as SLList and transfer contents
list.clear(); // Clear old contents
is.putBack(tok); // Putback the opening bracket
SLList<T> sll(is); // Read as singly-linked list
@ -156,6 +154,8 @@ Foam::Istream& Foam::List<T>::readList(Istream& is)
}
else
{
list.clear(); // Clear old contents
FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found "
<< tok.info() << nl

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.
@ -105,35 +105,20 @@ void Foam::UList<T>::swapLast(const label i)
template<class T>
void Foam::UList<T>::deepCopy(const UList<T>& list)
{
const label len = this->size_;
if (len != list.size_)
if (this->size_ != list.size_)
{
FatalErrorInFunction
<< "Lists have different sizes: "
<< len << " != " << list.size() << nl
<< this->size_ << " != " << list.size() << nl
<< abort(FatalError);
}
else if (len)
else if (this->size_ > 0)
{
#ifdef USEMEMCPY
if (is_contiguous<T>::value)
{
std::memcpy
(
static_cast<void*>(this->v_), list.v_, this->size_bytes()
);
}
else
#endif
{
List_ACCESS(T, (*this), lhs);
List_CONST_ACCESS(T, list, rhs);
for (label i = 0; i < len; ++i)
{
lhs[i] = rhs[i];
}
}
// Can also dispatch with
// - std::execution::parallel_unsequenced_policy
// - std::execution::unsequenced_policy
std::copy(list.cbegin(), list.cend(), this->v_);
}
}
@ -142,17 +127,19 @@ template<class T>
template<class Addr>
void Foam::UList<T>::deepCopy(const IndirectListBase<T, Addr>& list)
{
const label len = this->size_;
if (len != list.size())
if (this->size_ != list.size())
{
FatalErrorInFunction
<< "Lists have different sizes: "
<< len << " != " << list.size() << nl
<< this->size_ << " != " << list.size() << nl
<< abort(FatalError);
}
else if (len)
else if (this->size_)
{
// copyList()
const label len = this->size_;
List_ACCESS(T, (*this), lhs);
for (label i = 0; i < len; ++i)
{
@ -164,28 +151,15 @@ void Foam::UList<T>::deepCopy(const IndirectListBase<T, Addr>& list)
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T>
void Foam::UList<T>::operator=(const T& val)
{
const label len = this->size();
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
{
vp[i] = val;
}
}
template<class T>
void Foam::UList<T>::operator=(const Foam::zero)
{
// fill_uniform()
const label len = this->size();
List_ACCESS(T, (*this), vp);
for (label i=0; i < len; ++i)
for (label i = 0; i < len; ++i)
{
vp[i] = Zero;
}

View File

@ -118,6 +118,10 @@ protected:
//- always addresses a valid section of the list.
labelRange validateRange(const labelRange& requestedRange) const;
//- Assign all entries to the given value
// Caution: method name subject to change
inline void fill_uniform(const T& val);
//- No copy assignment (default: shallow copy)
//
// Assignment may need to be shallow (copy pointer)
@ -347,7 +351,7 @@ public:
// Copy
//- Copy the pointer and size held by the given UList
inline void shallowCopy(const UList<T>& list);
inline void shallowCopy(const UList<T>& list) noexcept;
//- Copy elements of the given UList. Sizes must match!
void deepCopy(const UList<T>& list);
@ -390,7 +394,7 @@ public:
inline operator const Foam::List<T>&() const;
//- Assignment of all entries to the given value
void operator=(const T& val);
inline void operator=(const T& val);
//- Assignment of all entries to zero
void operator=(const Foam::zero);
@ -468,7 +472,7 @@ public:
static constexpr label max_size() noexcept { return labelMax; }
//- Swap content with another UList of the same type in constant time
inline void swap(UList<T>& list);
inline void swap(UList<T>& list) noexcept;
// STL member operators
@ -703,15 +707,12 @@ template<class T>
struct Hash<UList<T>> : UList<T>::hasher {};
//- Object access operator or list access operator.
//- Object access operator or list access operator (default is pass-through)
//- \sa ListListOps::combine()
template<class T>
struct accessOp
{
const T& operator()(const T& obj) const
{
return obj; // Default is pass-through
}
const T& operator()(const T& obj) const { return obj; }
};
@ -719,10 +720,7 @@ struct accessOp
template<class T>
struct emptyOp
{
bool operator()(const T& obj) const
{
return obj.empty();
}
bool operator()(const T& obj) const { return obj.empty(); }
};
@ -730,10 +728,7 @@ struct emptyOp
template<class T>
struct sizeOp
{
label operator()(const T& obj) const
{
return obj.size();
}
label operator()(const T& obj) const { return obj.size(); }
};

View File

@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "error.H"
// <algorithm> already included by stdFoam.H
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -46,6 +47,25 @@ inline Foam::UList<T>::UList(T* __restrict__ v, const label len) noexcept
{}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class T>
inline void Foam::UList<T>::fill_uniform(const T& val)
{
// Can also dispatch with
// - std::execution::parallel_unsequenced_policy
// - std::execution::unsequenced_policy
if (this->size_ > 0)
{
std::fill_n
(
this->v_, this->size_, val
);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
@ -268,7 +288,7 @@ inline bool Foam::UList<T>::contains(const T& val, label pos) const
template<class T>
inline void Foam::UList<T>::shallowCopy(const UList<T>& list)
inline void Foam::UList<T>::shallowCopy(const UList<T>& list) noexcept
{
size_ = list.size_;
v_ = list.v_;
@ -277,6 +297,13 @@ inline void Foam::UList<T>::shallowCopy(const UList<T>& list)
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class T>
inline void Foam::UList<T>::operator=(const T& val)
{
this->fill_uniform(val);
}
namespace Foam
{
// Template specialization for bool
@ -439,7 +466,7 @@ inline void Foam::UList<T>::setAddressableSize(const label n) noexcept
template<class T>
inline void Foam::UList<T>::swap(UList<T>& list)
inline void Foam::UList<T>::swap(UList<T>& list) noexcept
{
if (&list == this)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -264,10 +264,8 @@ Foam::Istream& Foam::UList<T>::readList(Istream& is)
"reading the single entry"
);
for (label i=0; i<len; ++i)
{
list[i] = elem; // Copy the value
}
// Fill with the value
this->fill_uniform(elem);
}
}