Commit 6cb6677d authored by Mark Olesen's avatar Mark Olesen
Browse files

BUG: guard against potential wasted memory in DynamicField

- specialize transfer and swap to ensure allocated capacity isn't
  forgotten.
parent 09efce91
......@@ -39,10 +39,7 @@ template<class T, int SizeMin>
Foam::tmp<Foam::DynamicField<T, SizeMin>>
Foam::DynamicField<T, SizeMin>::clone() const
{
return tmp<DynamicField<T, SizeMin>>
(
new DynamicField<T, SizeMin>(*this)
);
return tmp<DynamicField<T, SizeMin>>::New(*this);
}
......
......@@ -51,20 +51,20 @@ template<class T, int SizeMin> class DynamicField;
template<class T, int SizeMin>
Ostream& operator<<
(
Ostream&,
const DynamicField<T, SizeMin>&
Ostream& os,
const DynamicField<T, SizeMin>& fld
);
template<class T, int SizeMin>
Istream& operator>>
(
Istream&,
DynamicField<T, SizeMin>&
Istream& is,
DynamicField<T, SizeMin>& fld
);
/*---------------------------------------------------------------------------*\
Class DynamicField Declaration
Class DynamicField Declaration
\*---------------------------------------------------------------------------*/
template<class T, int SizeMin=64>
......@@ -84,7 +84,7 @@ class DynamicField
//- Copy assignment from another list
template<class ListType>
inline void assignDynField(const ListType& lst);
inline void assignDynField(const ListType& list);
public:
......@@ -102,15 +102,25 @@ public:
//- Construct null
inline constexpr DynamicField() noexcept;
//- Construct with given capacity.
//- Construct empty field with given reserve size.
explicit inline DynamicField(const label len);
//- Construct given size and initial value
inline DynamicField(const label len, const T& val);
//- Construct given size and initial value of zero
inline DynamicField(const label len, const zero);
//- Copy construct
inline DynamicField(const DynamicField<T, SizeMin>& lst);
inline DynamicField(const DynamicField<T, SizeMin>& list);
//- Copy construct with different sizing parameters
template<int AnySizeMin>
inline DynamicField(const DynamicField<T, AnySizeMin>& list);
//- Copy construct from UList. Size set to UList size.
// Also constructs from DynamicField with different sizing parameters.
explicit inline DynamicField(const UList<T>& lst);
explicit inline DynamicField(const UList<T>& list);
//- Copy construct from UIndirectList
explicit inline DynamicField(const UIndirectList<T>& list);
......@@ -118,9 +128,13 @@ public:
//- Move construct from List contents
explicit inline DynamicField(List<T>&& content);
//- Move construct from Field contents
//- Move construct from dynamic Field contents
inline DynamicField(DynamicField<T, SizeMin>&& content);
//- Move construct with different sizing parameters
template<int AnySizeMin>
inline DynamicField(DynamicField<T, AnySizeMin>&& content);
//- Construct by 1 to 1 mapping from the given field
inline DynamicField
(
......@@ -152,87 +166,108 @@ public:
// Member Functions
// Access
// Access
//- Size of the underlying storage.
inline label capacity() const;
// Edit
//- Alter the size of the underlying storage.
// The addressed size will be truncated if needed to fit, but will
// remain otherwise untouched.
// Use this or reserve() in combination with append().
inline void setCapacity(const label nElem);
//- Alter the addressed list size.
// New space will be allocated if required.
// Use this to resize the list prior to using the operator[] for
// setting values (as per List usage).
inline void setSize(const label nElem);
//- Alter the addressed list size and fill new space with a constant.
inline void setSize(const label nElem, const T& val);
//- Alter the addressed list size.
// New space will be allocated if required.
// Use this to resize the list prior to using the operator[] for
// setting values (as per List usage).
inline void resize(const label nElem);
//- Alter the addressed list size and fill new space with a
// constant.
inline void resize(const label nElem, const T& val);
//- Reserve allocation space for at least this size.
// Never shrinks the allocated size, use setCapacity() for that.
inline void reserve(const label nElem);
//- Size of the underlying storage.
inline label capacity() const;
//- Clear the addressed list, i.e. set the size to zero.
// Allocated size does not change
inline void clear();
// Edit
//- Clear the list and delete storage.
inline void clearStorage();
//- Alter the size of the underlying storage.
// The addressed size will be truncated if needed to fit, but will
// remain otherwise untouched.
// Use this or reserve() in combination with append().
inline void setCapacity(const label nElem);
//- Expand the addressable size to fit the allocated capacity.
// Returns the previous addressable size.
inline label expandStorage();
//- Alter the addressed list size.
// New space will be allocated if required.
// Use this to resize the list prior to using the operator[] for
// setting values (as per List usage).
inline void setSize(const label nElem);
//- Shrink the allocated space to the number of elements used.
// Returns a reference to the DynamicField.
inline DynamicField<T, SizeMin>& shrink();
//- Alter the addressed list size and fill new space with a
// constant.
inline void setSize(const label nElem, const T& val);
//- Swap content with any sized DynamicField
template<int AnySizeMin>
inline void swap(DynamicField<T, AnySizeMin>& list);
//- Alter the addressed list size.
// New space will be allocated if required.
// Use this to resize the list prior to using the operator[] for
// setting values (as per List usage).
inline void resize(const label nElem);
//- Transfer the parameter contents into this
inline void transfer(List<T>& list);
//- Alter the addressed list size and fill new space with a
// constant.
inline void resize(const label nElem, const T& val);
//- Transfer the parameter contents into this
template<int AnySizeMin>
inline void transfer(DynamicList<T, AnySizeMin>& list);
//- Reserve allocation space for at least this size.
// Never shrinks the allocated size, use setCapacity() for that.
inline void reserve(const label nElem);
//- Transfer the parameter contents into this
template<int AnySizeMin>
inline void transfer(DynamicField<T, AnySizeMin>& list);
//- Clear the addressed list, i.e. set the size to zero.
// Allocated size does not change
inline void clear();
//- Clear the list and delete storage.
inline void clearStorage();
//- Append an element at the end of the list
inline DynamicField<T, SizeMin>&
append(const T& val);
//- Expand the addressable size to fit the allocated capacity.
// Returns the previous addressable size.
inline label expandStorage();
//- Append a List at the end of this list
inline DynamicField<T, SizeMin>&
append(const UList<T>& list);
//- Shrink the allocated space to the number of elements used.
// Returns a reference to the DynamicField.
inline DynamicField<T, SizeMin>& shrink();
//- Remove and return the top element
inline T remove();
// Member Operators
// Member Operators
//- Append an element at the end of the list
inline DynamicField<T, SizeMin>&
append(const T& val);
//- Return non-const access to an element, resizing list if necessary
inline T& operator()(const label i);
//- Append a List at the end of this list
inline DynamicField<T, SizeMin>&
append(const UList<T>& lst);
//- Assign addressed entries to the given value
inline void operator=(const T& val);
//- Remove and return the top element
inline T remove();
//- Copy assignment
inline void operator=(const UList<T>& list);
//- Return non-const access to an element, resizing list if
// necessary
inline T& operator()(const label i);
//- Copy assignment
inline void operator=(const DynamicField<T, SizeMin>& list);
//- Assignment of all addressed entries to the given value
inline void operator=(const T& val);
//- Move assignment
inline void operator=(List<T>&& list);
//- Assignment to DynamicField
inline void operator=
(
const DynamicField<T, SizeMin>& lst
);
//- Move assignment
inline void operator=(DynamicField<T, SizeMin>&& list);
//- Assignment to UList
inline void operator=(const UList<T>& lst);
//- Move assignment
template<int AnySizeMin>
inline void operator=(DynamicField<T, AnySizeMin>&& list);
};
......
......@@ -29,23 +29,23 @@ template<class T, int SizeMin>
template<class ListType>
inline void Foam::DynamicField<T, SizeMin>::assignDynField
(
const ListType& lst
const ListType& list
)
{
const label newSize = lst.size();
const label newSize = list.size();
if (capacity_ >= newSize)
{
// Can copy w/o reallocating - adjust addressable size accordingly.
Field<T>::size(lst.size());
Field<T>::operator=(lst);
Field<T>::size(list.size());
Field<T>::operator=(list);
}
else
{
// Ensure list size consistency prior to copying.
Field<T>::size(capacity_);
Field<T>::operator=(lst);
Field<T>::operator=(list);
capacity_ = Field<T>::size();
}
}
......@@ -62,15 +62,11 @@ inline constexpr Foam::DynamicField<T, SizeMin>::DynamicField() noexcept
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const label len
)
inline Foam::DynamicField<T, SizeMin>::DynamicField(const label len)
:
Field<T>(len),
capacity_(Field<T>::size())
{
// We could also enforce sizing granularity
Field<T>::size(0);
}
......@@ -78,21 +74,57 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const DynamicField<T, SizeMin>& lst
const label len,
const T& val
)
:
Field<T>(len, val),
capacity_(Field<T>::size())
{}
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const label len,
const zero
)
:
Field<T>(len, Zero),
capacity_(Field<T>::size())
{}
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const DynamicField<T, SizeMin>& list
)
:
Field<T>(list),
capacity_(Field<T>::size())
{}
template<class T, int SizeMin>
template<int AnySizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const DynamicField<T, AnySizeMin>& list
)
:
Field<T>(lst),
capacity_(lst.capacity())
Field<T>(list),
capacity_(Field<T>::size())
{}
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const UList<T>& lst
const UList<T>& list
)
:
Field<T>(lst),
Field<T>(list),
capacity_(Field<T>::size())
{}
......@@ -100,10 +132,10 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
const UIndirectList<T>& lst
const UIndirectList<T>& list
)
:
Field<T>(lst),
Field<T>(list),
capacity_(Field<T>::size())
{}
......@@ -125,10 +157,24 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
DynamicField<T, SizeMin>&& content
)
:
Field<T>(std::move(content)),
capacity_(Field<T>::size())
Field<T>(),
capacity_(0)
{
transfer(content);
}
template<class T, int SizeMin>
template<int AnySizeMin>
inline Foam::DynamicField<T, SizeMin>::DynamicField
(
DynamicField<T, AnySizeMin>&& content
)
:
Field<T>(),
capacity_(0)
{
content.clear();
transfer(content);
}
......@@ -173,8 +219,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, int SizeMin>
inline Foam::label Foam::DynamicField<T, SizeMin>::capacity()
const
inline Foam::label Foam::DynamicField<T, SizeMin>::capacity() const
{
return capacity_;
}
......@@ -343,6 +388,73 @@ Foam::DynamicField<T, SizeMin>::shrink()
}
template<class T, int SizeMin>
template<int AnySizeMin>
inline void Foam::DynamicField<T, SizeMin>::swap
(
DynamicField<T, AnySizeMin>& lst
)
{
DynamicList<T, SizeMin>& cur = *this;
// Make addressable size identical to the allocated capacity
const label oldSize1 = cur.expandStorage();
const label oldSize2 = lst.expandStorage();
// Swap storage
Field<T>::swap(lst);
// Match capacity to the underlying allocated list size
cur.setCapacity(cur.size());
lst.setCapacity(lst.size());
// Set addressable size
cur.setSize(oldSize2);
lst.setSize(oldSize1);
}
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::transfer(List<T>& list)
{
// Take over storage, clear addressing for list.
capacity_ = list.size();
Field<T>::transfer(list);
}
template<class T, int SizeMin>
template<int AnySizeMin>
inline void Foam::DynamicField<T, SizeMin>::transfer
(
DynamicList<T, AnySizeMin>& list
)
{
// Take over storage as-is (without shrink, without using SizeMin)
// clear addressing and storage for old list.
capacity_ = list.capacity();
Field<T>::transfer(static_cast<Field<T>&>(list));
list.clearStorage(); // Ensure capacity=0
}
template<class T, int SizeMin>
template<int AnySizeMin>
inline void Foam::DynamicField<T, SizeMin>::transfer
(
DynamicField<T, AnySizeMin>& list
)
{
// Take over storage as-is (without shrink, without using SizeMin)
// clear addressing and storage for old list.
capacity_ = list.capacity();
Field<T>::transfer(static_cast<Field<T>&>(list));
list.clearStorage(); // Ensure capacity=0
}
template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>&
Foam::DynamicField<T, SizeMin>::append
......@@ -353,7 +465,7 @@ Foam::DynamicField<T, SizeMin>::append
const label idx = List<T>::size();
setSize(idx + 1);
this->operator[](idx) = val;
this->operator[](idx) = val; // copy element
return *this;
}
......@@ -362,21 +474,21 @@ template<class T, int SizeMin>
inline Foam::DynamicField<T, SizeMin>&
Foam::DynamicField<T, SizeMin>::append
(
const UList<T>& lst
const UList<T>& list
)
{
if (this == &lst)
if (this == &list)
{
FatalErrorInFunction
<< "attempted appending to self" << abort(FatalError);
}
label nextFree = List<T>::size();
setSize(nextFree + lst.size());
label idx = List<T>::size();
setSize(idx + list.size());
forAll(lst, i)
for (const T& val : list)
{
this->operator[](nextFree++) = lst[i];
this->operator[](idx++) = val; // copy element
}
return *this;
}
......@@ -432,26 +544,57 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::operator=
(
const DynamicField<T, SizeMin>& lst
const UList<T>& list
)
{
if (this == &lst)
assignDynField(list);
}
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::operator=
(
const DynamicField<T, SizeMin>& list
)
{
if (this == &list)
{
FatalErrorInFunction
<< "Attempted assignment to self" << abort(FatalError);
}
assignDynField(lst);
assignDynField(list);
}
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::operator=
(
List<T>&& list
)
{
transfer(list);
}
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::operator=
(
DynamicField<T, SizeMin>&& list
)
{
transfer(list);
}
template<class T, int SizeMin>
template<int AnySizeMin>
inline void Foam::DynamicField<T, SizeMin>::operator=
(
const UList<T>& lst
DynamicField<T, AnySizeMin>&& list
)
{
assignDynField(lst);
transfer(list);
}
......
......@@ -186,5 +186,4 @@ inline void Foam::Field<Type>::operator=(const zero)
}
// ************************************************************************* //
Markdown is supported