From 5ee8f19bdd0ba88895c29ac36834ea638e7ccc30 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 25 Apr 2025 10:34:42 +0200
Subject: [PATCH] ENH: refine handling of DynamicList/DynamicField resizing

- previously had special resizing treatment for the corner case when
  the addressable size and the new capacity are identical. However,
  that particular approach (to minimize copying) meant that the exact
  deallocation size would likely be incorrect.
  Having the correct deallocation size becomes more important with
  alternative allocators.

  Introduce resize_copy() protected function to limit the number
  of elements copied during the resize.

ENH: provide DynamicList/DynamicField constructor with sizing

- allows fine-grained creation of a DynamicList/DynamicField with a
  given size/capacity without an initial value.

COMP: typo in code for DynamicList::push_back() with IndirectList
---
 applications/test/DynamicList/Make/files      |  2 +-
 ...est-DynamicList.C => Test-DynamicList.cxx} |  0
 applications/test/DynamicList2/Make/files     |  2 +-
 ...t-DynamicList2.C => Test-DynamicList2.cxx} | 22 ++++++-
 applications/test/List3/Make/files            |  2 +-
 .../List3/{Test-List3.C => Test-List3.cxx}    |  0
 applications/test/PackedList1/Make/files      |  2 +-
 ...est-PackedList1.C => Test-PackedList1.cxx} |  0
 applications/test/PackedList2/Make/files      |  2 +-
 ...est-PackedList2.C => Test-PackedList2.cxx} |  0
 applications/test/UIndirectList/Make/files    |  2 +-
 ...UIndirectList.C => Test-UIndirectList.cxx} |  0
 applications/test/bitSet2/Make/files          |  2 +-
 .../{Test-bitSet2.C => Test-bitSet2.cxx}      |  2 +-
 .../containers/Bits/PackedList/PackedList.H   |  5 +-
 .../containers/Bits/PackedList/PackedListI.H  |  2 +-
 .../Lists/DynamicList/DynamicList.H           | 42 +++++++-----
 .../Lists/DynamicList/DynamicListI.H          | 57 ++++++----------
 src/OpenFOAM/containers/Lists/List/List.C     | 57 +++++++++-------
 src/OpenFOAM/containers/Lists/List/List.H     | 14 ++--
 src/OpenFOAM/containers/Lists/List/ListI.H    | 14 ++--
 .../PtrLists/PtrDynList/PtrDynList.H          | 13 +++-
 .../PtrLists/PtrDynList/PtrDynListI.H         | 16 ++++-
 .../containers/PtrLists/PtrList/PtrList.H     |  2 +-
 .../fields/Fields/DynamicField/DynamicField.H | 53 ++++++++-------
 .../Fields/DynamicField/DynamicFieldI.H       | 66 +++++++++----------
 26 files changed, 216 insertions(+), 163 deletions(-)
 rename applications/test/DynamicList/{Test-DynamicList.C => Test-DynamicList.cxx} (100%)
 rename applications/test/DynamicList2/{Test-DynamicList2.C => Test-DynamicList2.cxx} (87%)
 rename applications/test/List3/{Test-List3.C => Test-List3.cxx} (100%)
 rename applications/test/PackedList1/{Test-PackedList1.C => Test-PackedList1.cxx} (100%)
 rename applications/test/PackedList2/{Test-PackedList2.C => Test-PackedList2.cxx} (100%)
 rename applications/test/UIndirectList/{Test-UIndirectList.C => Test-UIndirectList.cxx} (100%)
 rename applications/test/bitSet2/{Test-bitSet2.C => Test-bitSet2.cxx} (99%)

diff --git a/applications/test/DynamicList/Make/files b/applications/test/DynamicList/Make/files
index b496842582c..76d78735b0c 100644
--- a/applications/test/DynamicList/Make/files
+++ b/applications/test/DynamicList/Make/files
@@ -1,3 +1,3 @@
-Test-DynamicList.C
+Test-DynamicList.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-DynamicList
diff --git a/applications/test/DynamicList/Test-DynamicList.C b/applications/test/DynamicList/Test-DynamicList.cxx
similarity index 100%
rename from applications/test/DynamicList/Test-DynamicList.C
rename to applications/test/DynamicList/Test-DynamicList.cxx
diff --git a/applications/test/DynamicList2/Make/files b/applications/test/DynamicList2/Make/files
index 78b8198c6a0..ceb29c77127 100644
--- a/applications/test/DynamicList2/Make/files
+++ b/applications/test/DynamicList2/Make/files
@@ -1,3 +1,3 @@
-Test-DynamicList2.C
+Test-DynamicList2.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-DynamicList2
diff --git a/applications/test/DynamicList2/Test-DynamicList2.C b/applications/test/DynamicList2/Test-DynamicList2.cxx
similarity index 87%
rename from applications/test/DynamicList2/Test-DynamicList2.C
rename to applications/test/DynamicList2/Test-DynamicList2.cxx
index e75e0d29862..ef47d267834 100644
--- a/applications/test/DynamicList2/Test-DynamicList2.C
+++ b/applications/test/DynamicList2/Test-DynamicList2.cxx
@@ -52,7 +52,8 @@ void printInfo
     if (showSize)
     {
         Info<< " size=\"" << list.size()
-            << "\" capacity=\"" << list.capacity() << "\"";
+            << "\" capacity=\"" << list.capacity() << "\""
+            << "\" min=\"" << SizeMin << "\"" ;
         if (list.cdata())
         {
             Info<< " ptr=\"" << name(list.cdata()) << "\"";
@@ -79,7 +80,8 @@ void printInfo
     if (showSize)
     {
         Info<< " size=\"" << list.size()
-            << "\" capacity=\"" << list.capacity() << "\"";
+            << "\" capacity=\"" << list.capacity() << "\""
+            << "\" min=\"" << SizeMin << "\"" ;
         if (list.cdata())
         {
             Info<< " ptr=\"" << name(list.cdata()) << "\"";
@@ -168,6 +170,22 @@ int main(int argc, char *argv[])
         printInfo("", list2);
     }
 
+    {
+        DynamicList<float, 32> list1(std::pair<label,label>(16,0));
+        list1 = -1;
+
+        Info<< "construct with specified size/capacity" << nl;
+        printInfo("", list1);
+    }
+
+    {
+        DynamicList<float, 32> list1(std::pair<label,label>(8,16));
+        list1 = -1;
+
+        Info<< "construct with specified size/capacity" << nl;
+        printInfo("", list1);
+    }
+
     Info<< "\nEnd\n";
 
     return 0;
diff --git a/applications/test/List3/Make/files b/applications/test/List3/Make/files
index 640cc113d78..93c443e14e2 100644
--- a/applications/test/List3/Make/files
+++ b/applications/test/List3/Make/files
@@ -1,3 +1,3 @@
-Test-List3.C
+Test-List3.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-List3
diff --git a/applications/test/List3/Test-List3.C b/applications/test/List3/Test-List3.cxx
similarity index 100%
rename from applications/test/List3/Test-List3.C
rename to applications/test/List3/Test-List3.cxx
diff --git a/applications/test/PackedList1/Make/files b/applications/test/PackedList1/Make/files
index 76843f21f9f..0b2b68d6ff5 100644
--- a/applications/test/PackedList1/Make/files
+++ b/applications/test/PackedList1/Make/files
@@ -1,3 +1,3 @@
-Test-PackedList1.C
+Test-PackedList1.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-PackedList1
diff --git a/applications/test/PackedList1/Test-PackedList1.C b/applications/test/PackedList1/Test-PackedList1.cxx
similarity index 100%
rename from applications/test/PackedList1/Test-PackedList1.C
rename to applications/test/PackedList1/Test-PackedList1.cxx
diff --git a/applications/test/PackedList2/Make/files b/applications/test/PackedList2/Make/files
index ce31f2fa8dd..7c20add1a55 100644
--- a/applications/test/PackedList2/Make/files
+++ b/applications/test/PackedList2/Make/files
@@ -1,3 +1,3 @@
-Test-PackedList2.C
+Test-PackedList2.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-PackedList2
diff --git a/applications/test/PackedList2/Test-PackedList2.C b/applications/test/PackedList2/Test-PackedList2.cxx
similarity index 100%
rename from applications/test/PackedList2/Test-PackedList2.C
rename to applications/test/PackedList2/Test-PackedList2.cxx
diff --git a/applications/test/UIndirectList/Make/files b/applications/test/UIndirectList/Make/files
index 8f705219896..9be6c131786 100644
--- a/applications/test/UIndirectList/Make/files
+++ b/applications/test/UIndirectList/Make/files
@@ -1,3 +1,3 @@
-Test-UIndirectList.C
+Test-UIndirectList.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-UIndirectList
diff --git a/applications/test/UIndirectList/Test-UIndirectList.C b/applications/test/UIndirectList/Test-UIndirectList.cxx
similarity index 100%
rename from applications/test/UIndirectList/Test-UIndirectList.C
rename to applications/test/UIndirectList/Test-UIndirectList.cxx
diff --git a/applications/test/bitSet2/Make/files b/applications/test/bitSet2/Make/files
index ff546fa179b..e3ceca9e230 100644
--- a/applications/test/bitSet2/Make/files
+++ b/applications/test/bitSet2/Make/files
@@ -1,3 +1,3 @@
-Test-bitSet2.C
+Test-bitSet2.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-bitSet2
diff --git a/applications/test/bitSet2/Test-bitSet2.C b/applications/test/bitSet2/Test-bitSet2.cxx
similarity index 99%
rename from applications/test/bitSet2/Test-bitSet2.C
rename to applications/test/bitSet2/Test-bitSet2.cxx
index fb9bc746a18..8f9f5d487e2 100644
--- a/applications/test/bitSet2/Test-bitSet2.C
+++ b/applications/test/bitSet2/Test-bitSet2.cxx
@@ -499,7 +499,7 @@ int main(int argc, char *argv[])
         Info<<"bitSet ";
         report(list4);
 
-        list4.shrink();
+        list4.shrink_to_fit();
         Info<<"shrunk ";
         report(list4);
 
diff --git a/src/OpenFOAM/containers/Bits/PackedList/PackedList.H b/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
index 5bdbbceb6a1..aa6c7559623 100644
--- a/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
+++ b/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
@@ -406,7 +406,10 @@ public:
         inline void clearStorage();
 
         //- Shrink the allocated space to what is actually used.
-        inline void shrink();
+        inline void shrink_to_fit();
+
+        //- Alias for shrink_to_fit()
+        void shrink() { this->shrink_to_fit(); }
 
         //- Swap contents with argument
         inline void swap(PackedList<Width>& rhs);
diff --git a/src/OpenFOAM/containers/Bits/PackedList/PackedListI.H b/src/OpenFOAM/containers/Bits/PackedList/PackedListI.H
index 8bdd10ddcc7..a8e7f93dd9f 100644
--- a/src/OpenFOAM/containers/Bits/PackedList/PackedListI.H
+++ b/src/OpenFOAM/containers/Bits/PackedList/PackedListI.H
@@ -597,7 +597,7 @@ inline void Foam::PackedList<Width>::clearStorage()
 
 
 template<unsigned Width>
-inline void Foam::PackedList<Width>::shrink()
+inline void Foam::PackedList<Width>::shrink_to_fit()
 {
     // Any unneeded space allocated?
     const label nblocks = num_blocks(size());
diff --git a/src/OpenFOAM/containers/Lists/DynamicList/DynamicList.H b/src/OpenFOAM/containers/Lists/DynamicList/DynamicList.H
index 78385c9b5bf..bf8768d9bc1 100644
--- a/src/OpenFOAM/containers/Lists/DynamicList/DynamicList.H
+++ b/src/OpenFOAM/containers/Lists/DynamicList/DynamicList.H
@@ -120,6 +120,9 @@ public:
         //- Construct an empty list with given initial capacity
         inline explicit DynamicList(const label initialCapacity);
 
+        //- Construct with given size and capacity
+        inline explicit DynamicList(const std::pair<label,label>& sizing);
+
         //- Construct with given size and value for all elements.
         inline DynamicList(const label len, const T& val);
 
@@ -133,21 +136,21 @@ public:
         template<int AnySizeMin>
         inline DynamicList(const DynamicList<T, AnySizeMin>& lst);
 
-        //- Construct from UList. Size set to UList size.
+        //- Copy construct from UList. Size set to UList size.
         //  Also constructs from DynamicList with different sizing parameters.
         inline explicit DynamicList(const UList<T>& lst);
 
         //- Copy construct subset of list
         inline DynamicList(const UList<T>& list, const labelUList& indices);
 
-        //- Construct from a FixedList
+        //- Copy construct from a FixedList
         template<unsigned N>
         inline explicit DynamicList(const FixedList<T, N>& lst);
 
-        //- Construct from an initializer list. Size set to list size.
+        //- Copy construct from an initializer list. Size set to list size.
         inline explicit DynamicList(std::initializer_list<T> lst);
 
-        //- Construct from IndirectList. Size set to addressing size.
+        //- Copy construct from IndirectList. Size set to addressing size.
         template<class Addr>
         inline explicit DynamicList(const IndirectListBase<T, Addr>& lst);
 
@@ -200,7 +203,7 @@ public:
 
         //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
         //- Does not perform any memory management or resizing.
-        inline void setCapacity_unsafe(const label len) noexcept;
+        void setCapacity_unsafe(const label len) noexcept { capacity_ = len; }
 
         //- Reserve allocation space for at least this size, allocating new
         //- space if required and \em retaining old content.
@@ -238,12 +241,6 @@ public:
         //  Otherwise all entries will be uninitialized.
         inline void resize_nocopy(const label len);
 
-        //- Same as resize()
-        void setSize(const label n) { this->resize(n); }
-
-        //- Same as resize()
-        void setSize(const label n, const T& val) { this->resize(n, val); }
-
         //- Clear the addressed list, i.e. set the size to zero.
         //  Allocated size does not change
         inline void clear() noexcept;
@@ -259,9 +256,6 @@ public:
         //  \note when empty() it will delete any allocated memory.
         inline void shrink_unsafe();
 
-        //- Calls shrink_to_fit() and returns a reference to the DynamicList.
-        inline DynamicList<T, SizeMin>& shrink();
-
 
     // Edit
 
@@ -304,7 +298,7 @@ public:
         template<class Addr>
         inline void push_back(const IndirectListBase<T, Addr>& lst);
 
-        //- Move append list
+        //- Move append another list to the end of this list
         inline void push_back(List<T>&& list);
 
         //- Move append list
@@ -355,10 +349,10 @@ public:
             //- Return non-const access to an element, resizing list if needed
             inline T& operator()(const label i);
 
-            //- Assignment of all addressed entries to the given value
+            //- Assign addressed entries to the given value
             inline void operator=(const T& val);
 
-            //- Assignment of all entries to zero
+            //- Assign addressed entries to zero
             inline void operator=(Foam::zero);
 
             //- Assignment to UList
@@ -418,6 +412,20 @@ public:
 
     // Housekeeping
 
+        //- Alias for resize()
+        void setSize(const label n) { this->resize(n); }
+
+        //- Alias for resize()
+        void setSize(const label n, const T& val) { this->resize(n, val); }
+
+        //- Calls shrink_to_fit() and returns a reference to the DynamicList.
+        //FOAM_DEPRECATED_FOR(2025-04, "shrink_to_fit()")
+        DynamicList<T, SizeMin>& shrink()
+        {
+            this->shrink_to_fit();
+            return *this;
+        }
+
         //- Copy append an element to the end of this list.
         //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
         void append(const T& val) { this->push_back(val); }
diff --git a/src/OpenFOAM/containers/Lists/DynamicList/DynamicListI.H b/src/OpenFOAM/containers/Lists/DynamicList/DynamicListI.H
index a3c004cd8ae..17e199242d1 100644
--- a/src/OpenFOAM/containers/Lists/DynamicList/DynamicListI.H
+++ b/src/OpenFOAM/containers/Lists/DynamicList/DynamicListI.H
@@ -42,7 +42,7 @@ inline void Foam::DynamicList<T, SizeMin>::doAssignDynList
     if (capacity_ < len)
     {
         // Needs more space for the copy operation
-        List<T>::setAddressableSize(capacity_);  // Use entire space
+        List<T>::setAddressableSize(capacity_);
         List<T>::resize_nocopy(len);
         capacity_ = List<T>::size();
     }
@@ -68,23 +68,14 @@ inline void Foam::DynamicList<T, SizeMin>::doCapacity
     // Addressable length, possibly truncated by new capacity
     const label currLen = Foam::min(List<T>::size(), newCapacity);
 
-    // Corner case...
-    if (List<T>::size() == newCapacity)
-    {
-        // Adjust addressable size to trigger proper resizing.
-        // Using (old size+1) is safe since it does not affect the 'overlap'
-        // of old and new addressable regions, but incurs fewew copy
-        // operations than extending to use the current capacity would.
-        List<T>::setAddressableSize(currLen+1);
-    }
-
+    List<T>::setAddressableSize(capacity_);
     if (nocopy)
     {
         List<T>::resize_nocopy(newCapacity);
     }
     else
     {
-        List<T>::resize(newCapacity);
+        List<T>::resize_copy(currLen, newCapacity);
     }
 
     capacity_ = List<T>::size();
@@ -153,6 +144,19 @@ inline Foam::DynamicList<T, SizeMin>::DynamicList(const label initialCapacity)
 }
 
 
+template<class T, int SizeMin>
+inline Foam::DynamicList<T, SizeMin>::DynamicList
+(
+    const std::pair<label,label>& sizing
+)
+:
+    List<T>(std::max(sizing.first, sizing.second)),
+    capacity_(List<T>::size())
+{
+    List<T>::setAddressableSize(sizing.first);
+}
+
+
 template<class T, int SizeMin>
 inline Foam::DynamicList<T, SizeMin>::DynamicList
 (
@@ -326,16 +330,6 @@ inline void Foam::DynamicList<T, SizeMin>::setCapacity_nocopy
 }
 
 
-template<class T, int SizeMin>
-inline void Foam::DynamicList<T, SizeMin>::setCapacity_unsafe
-(
-    const label len
-) noexcept
-{
-    capacity_ = len;
-}
-
-
 template<class T, int SizeMin>
 inline void Foam::DynamicList<T, SizeMin>::reserve
 (
@@ -448,8 +442,7 @@ inline void Foam::DynamicList<T, SizeMin>::shrink_to_fit()
     const label currLen = List<T>::size();
     if (currLen < capacity_)
     {
-        // Adjust addressable size to trigger proper resizing
-        List<T>::setAddressableSize(currLen+1);
+        List<T>::setAddressableSize(capacity_);
         List<T>::resize(currLen);
         capacity_ = List<T>::size();
     }
@@ -468,15 +461,6 @@ inline void Foam::DynamicList<T, SizeMin>::shrink_unsafe()
 }
 
 
-template<class T, int SizeMin>
-inline Foam::DynamicList<T, SizeMin>&
-Foam::DynamicList<T, SizeMin>::shrink()
-{
-    this->shrink_to_fit();
-    return *this;
-}
-
-
 template<class T, int SizeMin>
 inline void
 Foam::DynamicList<T, SizeMin>::swap(List<T>& list)
@@ -608,7 +592,7 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
     const UList<T>& list
 )
 {
-    if (this == &list)
+    if (FOAM_UNLIKELY(this == &list))
     {
         FatalErrorInFunction
             << "Attempted push_back to self"
@@ -662,8 +646,7 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
 
     const label idx = this->size();
     const label n = list.size();
-
-    resize(list + n);
+    resize(idx + n);
 
     auto iter = this->begin(idx);
 
@@ -680,7 +663,7 @@ inline void Foam::DynamicList<T, SizeMin>::push_back
     List<T>&& list
 )
 {
-    if (this == &list)
+    if (FOAM_UNLIKELY(this == &list))
     {
         FatalErrorInFunction
             << "Attempted push_back to self"
diff --git a/src/OpenFOAM/containers/Lists/List/List.C b/src/OpenFOAM/containers/Lists/List/List.C
index bdf09f58c57..c9707ef29bc 100644
--- a/src/OpenFOAM/containers/Lists/List/List.C
+++ b/src/OpenFOAM/containers/Lists/List/List.C
@@ -31,31 +31,34 @@ License
 #include "PtrList.H"
 #include "contiguous.H"
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
 template<class T>
-void Foam::List<T>::doResize(const label len)
+void Foam::List<T>::resize_copy(const label count, const label len)
 {
-    if (len == this->size_)
-    {
-        return;
-    }
+    // Only a limited number of internal size checks.
+    // Caller knows what they are doing.
 
-    if (len > 0)
+    if (FOAM_LIKELY(len > 0))
     {
         // With sign-check to avoid spurious -Walloc-size-larger-than
-        const label overlap = Foam::min(this->size_, len);
+        // const label oldLen = this->size_;
+        const label overlap = Foam::min(count, len);
+        // Extra safety, not currently necessary:
+        // const label overlap = Foam::min(Foam::min(count, oldLen), len);
+
+        T* old = this->v_;
 
         if (overlap > 0)
         {
             // Recover overlapping content when resizing
-            T* old = this->v_;
+
             this->size_ = len;
             this->v_ = new T[len];
 
             // Can dispatch with
-            // - std::execution::parallel_unsequenced_policy
-            // - std::execution::unsequenced_policy
+            // - std::execution::par_unseq
+            // - std::execution::unseq
             std::move(old, (old + overlap), this->v_);
 
             delete[] old;
@@ -63,7 +66,8 @@ void Foam::List<T>::doResize(const label len)
         else
         {
             // No overlapping content
-            delete[] this->v_;
+            delete[] old;
+
             this->size_ = len;
             this->v_ = new T[len];
         }
@@ -71,7 +75,7 @@ void Foam::List<T>::doResize(const label len)
     else
     {
         // Or only #ifdef FULLDEBUG
-        if (len < 0)
+        if (FOAM_UNLIKELY(len < 0))
         {
             FatalErrorInFunction
                 << "bad size " << len
@@ -91,14 +95,17 @@ Foam::List<T>::List(const label len)
 :
     UList<T>(nullptr, len)
 {
-    if (len < 0)
+    if (FOAM_UNLIKELY(len < 0))
     {
         FatalErrorInFunction
             << "bad size " << len
             << abort(FatalError);
     }
 
-    doAlloc();
+    if (len > 0)
+    {
+        doAlloc();
+    }
 }
 
 
@@ -107,14 +114,14 @@ Foam::List<T>::List(const label len, const T& val)
 :
     UList<T>(nullptr, len)
 {
-    if (len < 0)
+    if (FOAM_UNLIKELY(len < 0))
     {
         FatalErrorInFunction
             << "bad size " << len
             << abort(FatalError);
     }
 
-    if (len)
+    if (len > 0)
     {
         doAlloc();
         UList<T>::operator=(val);
@@ -127,14 +134,14 @@ Foam::List<T>::List(const label len, Foam::zero)
 :
     UList<T>(nullptr, len)
 {
-    if (len < 0)
+    if (FOAM_UNLIKELY(len < 0))
     {
         FatalErrorInFunction
             << "bad size " << len
             << abort(FatalError);
     }
 
-    if (len)
+    if (len > 0)
     {
         doAlloc();
         UList<T>::operator=(Foam::zero{});
@@ -206,10 +213,8 @@ Foam::List<T>::List(List<T>& list, bool reuse)
         this->v_ = list.v_;
         list.v_ = nullptr;
         list.size_ = 0;
-        return;
     }
-
-    if (this->size_)
+    else if (this->size_ > 0)
     {
         doAlloc();
         UList<T>::deepCopy(list);
@@ -316,7 +321,13 @@ template<class T>
 void Foam::List<T>::resize(const label len, const T& val)
 {
     const label oldLen = this->size_;
-    this->doResize(len);
+
+    if (oldLen == len)
+    {
+        return;
+    }
+
+    this->resize_copy(oldLen, len);
 
     // Fill trailing part with new values
     if (oldLen < this->size_)
diff --git a/src/OpenFOAM/containers/Lists/List/List.H b/src/OpenFOAM/containers/Lists/List/List.H
index 8f2d96a99f3..5c9d7d1c8f3 100644
--- a/src/OpenFOAM/containers/Lists/List/List.H
+++ b/src/OpenFOAM/containers/Lists/List/List.H
@@ -93,10 +93,6 @@ class List
         template<class ListType, class ListIndices>
         inline void copyList(const ListType& list, const ListIndices& indices);
 
-        //- Change allocation size of List, retaining old contents.
-        //  Backend for resize
-        void doResize(const label len);
-
         //- Construct given begin/end iterators and number of elements
         //  Since the size is provided, the end iterator is actually ignored.
         template<class InputIterator>
@@ -118,6 +114,16 @@ class List
         void setCapacity_nocopy(const label len) { resize_nocopy(len); }
 
 
+protected:
+
+    // Protected Member Functions
+
+        //- Low-level resizing (backend for resize).
+        //- Change allocation size of list, retaining the first count contents.
+        //  \note Only uses a limited number of internal checks.
+        void resize_copy(const label count, const label len);
+
+
 public:
 
     // Related types
diff --git a/src/OpenFOAM/containers/Lists/List/ListI.H b/src/OpenFOAM/containers/Lists/List/ListI.H
index bdb510f8374..228df08392b 100644
--- a/src/OpenFOAM/containers/Lists/List/ListI.H
+++ b/src/OpenFOAM/containers/Lists/List/ListI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2023 OpenCFD Ltd.
+    Copyright (C) 2017-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -102,7 +102,7 @@ inline Foam::List<T>::List
 :
     UList<T>(nullptr, len)
 {
-    if (this->size_)
+    if (len > 0)
     {
         doAlloc();
 
@@ -149,9 +149,9 @@ namespace Foam
 {
     // Template specialization for bool. Fills new entries with false
     template<>
-    inline void List<bool>::resize(const label newLen)
+    inline void List<bool>::resize(const label len)
     {
-        this->resize(newLen, false);
+        this->resize(len, false);
     }
 }
 
@@ -159,7 +159,10 @@ namespace Foam
 template<class T>
 inline void Foam::List<T>::resize(const label len)
 {
-    this->doResize(len);
+    if (this->size_ != len)
+    {
+        this->resize_copy(this->size_, len);
+    }
 }
 
 
@@ -269,7 +272,6 @@ inline void Foam::List<T>::push_back(const IndirectListBase<T, Addr>& list)
 
     const label idx = this->size();
     const label n = list.size();
-
     resize(idx + n);
 
     auto iter = this->begin(idx);
diff --git a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H
index ee33bbef2d2..f55ee7e022c 100644
--- a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H
+++ b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H
@@ -76,9 +76,12 @@ public:
         //- Default construct
         inline constexpr PtrDynList() noexcept;
 
-        //- Construct with given capacity.
+        //- Construct with given initial capacity
         inline explicit PtrDynList(const label len);
 
+        //- Construct with given size and capacity
+        inline explicit PtrDynList(const std::pair<label,label>& sizing);
+
         //- Copy construct using 'clone()' method on each element
         inline PtrDynList(const PtrDynList<T, SizeMin>& list);
 
@@ -107,6 +110,10 @@ public:
         //- Size of the underlying storage.
         label capacity() const noexcept { return capacity_; }
 
+        //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
+        //- Does not perform any memory management or resizing.
+        void setCapacity_unsafe(const label len) noexcept { capacity_ = len; }
+
         //- Reserve allocation space for at least this size.
         inline void reserve(const label len);
 
@@ -138,8 +145,8 @@ public:
         //  \note when empty() it will delete any allocated memory.
         inline void shrink_unsafe();
 
-        //- Calls shrink_to_fit()
-        void shrink() { shrink_to_fit(); }
+        //- Alias for shrink_to_fit()
+        void shrink() { this->shrink_to_fit(); }
 
 
     // Edit
diff --git a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H
index fccedeccfbd..79763cf3985 100644
--- a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H
+++ b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H
@@ -49,6 +49,19 @@ inline Foam::PtrDynList<T, SizeMin>::PtrDynList(const label len)
 }
 
 
+template<class T, int SizeMin>
+inline Foam::PtrDynList<T, SizeMin>::PtrDynList
+(
+    const std::pair<label,label>& sizing
+)
+:
+    PtrList<T>(std::max(sizing.first, sizing.second)),
+    capacity_(PtrList<T>::size())
+{
+    PtrList<T>::setAddressableSize(sizing.first);
+}
+
+
 template<class T, int SizeMin>
 inline Foam::PtrDynList<T, SizeMin>::PtrDynList
 (
@@ -220,8 +233,7 @@ inline void Foam::PtrDynList<T, SizeMin>::shrink_to_fit()
     const label currLen = PtrList<T>::size();
     if (currLen < capacity_)
     {
-        // Adjust addressable size to trigger proper resizing
-        PtrList<T>::setAddressableSize(currLen+1);
+        PtrList<T>::setAddressableSize(capacity_);
         PtrList<T>::resize(currLen);
         capacity_ = PtrList<T>::size();
     }
diff --git a/src/OpenFOAM/containers/PtrLists/PtrList/PtrList.H b/src/OpenFOAM/containers/PtrLists/PtrList/PtrList.H
index 72c83892780..89e4a9688ab 100644
--- a/src/OpenFOAM/containers/PtrLists/PtrList/PtrList.H
+++ b/src/OpenFOAM/containers/PtrLists/PtrList/PtrList.H
@@ -249,7 +249,7 @@ public:
         }
 
         //- Same as resize()
-        void setSize(const label newLen) { this->resize(newLen); }
+        void setSize(const label n) { this->resize(n); }
 
         //- Move append an element to the end of the list
         //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
diff --git a/src/OpenFOAM/fields/Fields/DynamicField/DynamicField.H b/src/OpenFOAM/fields/Fields/DynamicField/DynamicField.H
index 5f73c83e117..7451c5ffdef 100644
--- a/src/OpenFOAM/fields/Fields/DynamicField/DynamicField.H
+++ b/src/OpenFOAM/fields/Fields/DynamicField/DynamicField.H
@@ -29,6 +29,7 @@ Class
 
 Description
     Dynamically sized Field.
+    Similar to DynamicList, but inheriting from a Field instead of a List.
 
 SourceFiles
     DynamicFieldI.H
@@ -95,15 +96,6 @@ class DynamicField
 
 public:
 
-    // Static Member Functions
-
-        //- Return a null DynamicField (reference to a nullObject).
-        static const DynamicField<T, SizeMin>& null() noexcept
-        {
-            return NullObjectRef<DynamicField<T, SizeMin>>();
-        }
-
-
     // Constructors
 
         //- Default construct, an empty field without allocation.
@@ -112,11 +104,14 @@ public:
         //- Construct empty field with given initial capacity
         inline explicit DynamicField(const label initialCapacity);
 
+        //- Construct with given size and capacity
+        inline explicit DynamicField(const std::pair<label,label>& sizing);
+
         //- 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 Foam::zero);
+        inline DynamicField(const label len, Foam::zero);
 
         //- Copy construct
         inline DynamicField(const DynamicField<T, SizeMin>& list);
@@ -222,7 +217,7 @@ public:
 
         //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
         //- Does not perform any memory management or resizing.
-        inline void setCapacity_unsafe(const label len) noexcept;
+        void setCapacity_unsafe(const label len) noexcept { capacity_ = len; }
 
         //- Reserve allocation space for at least this size, allocating new
         //- space if required and \em retaining old content.
@@ -248,21 +243,18 @@ public:
         //  setting values (as per List usage).
         inline void resize(const label len);
 
-        //- Alter addressable size and fill new space with constant value
+        //- Alter addressable size and fill \em new entries with constant value
         inline void resize(const label len, const T& val);
 
+        //- Alter addressable size and set val for \em all addressed entries
+        inline void resize_fill(const label len, const T& val);
+
         //- Alter addressable list size, allocating new space if required
         //- \em without necessarily recovering old content.
         //  If no reallocation is required, the contents remain untouched.
         //  Otherwise all entries will be uninitialized.
         inline void resize_nocopy(const label len);
 
-        //- Alias for resize()
-        void setSize(const label n) { this->resize(n); }
-
-        //- Alias for resize()
-        void setSize(const label n, const T& val) { this->resize(n, val); }
-
         //- Clear the addressed list, i.e. set the size to zero.
         //  Allocated size does not change
         inline void clear() noexcept;
@@ -278,9 +270,6 @@ public:
         //  \note when empty() it will delete any allocated memory.
         inline void shrink_unsafe();
 
-        //- Calls shrink_to_fit() and returns a reference to the DynamicField.
-        inline DynamicField<T, SizeMin>& shrink();
-
 
     // Edit
 
@@ -289,11 +278,11 @@ public:
 
         //- Swap content, independent of sizing parameter
         template<int AnySizeMin>
-        inline void swap(DynamicField<T, AnySizeMin>& other);
+        inline void swap(DynamicField<T, AnySizeMin>& other) noexcept;
 
         //- Swap content with DynamicList, independent of sizing parameter
         template<int AnySizeMin>
-        inline void swap(DynamicList<T, AnySizeMin>& other);
+        inline void swap(DynamicList<T, AnySizeMin>& other) noexcept;
 
         //- Transfer the parameter contents into this
         inline void transfer(List<T>& list);
@@ -311,7 +300,7 @@ public:
         template<class... Args>
         inline T& emplace_back(Args&&... args);
 
-        //- Copy append an element at the end of the list
+        //- Copy append an element to the end of the list
         inline void push_back(const T& val);
 
         //- Move append an element
@@ -340,7 +329,7 @@ public:
         inline void operator=(const T& val);
 
         //- Assign addressed entries to zero
-        inline void operator=(const Foam::zero);
+        inline void operator=(Foam::zero);
 
         //- Copy assignment
         inline void operator=(const UList<T>& list);
@@ -392,6 +381,20 @@ public:
 
     // Housekeeping
 
+        //- Alias for resize()
+        void setSize(const label n) { this->resize(n); }
+
+        //- Alias for resize()
+        void setSize(const label n, const T& val) { this->resize(n, val); }
+
+        //- Calls shrink_to_fit() and returns a reference to the DynamicField.
+        //FOAM_DEPRECATED_FOR(2025-04, "shrink_to_fit()")
+        DynamicField<T, SizeMin>& shrink()
+        {
+            this->shrink_to_fit();
+            return *this;
+        }
+
         //- Append an element at the end of the list
         //FOAM_DEPRECATED_FOR(2022-10, "push_back()")
         void append(const T& val) { this->push_back(val); }
diff --git a/src/OpenFOAM/fields/Fields/DynamicField/DynamicFieldI.H b/src/OpenFOAM/fields/Fields/DynamicField/DynamicFieldI.H
index 18012d91f2b..1b5b6fd69d1 100644
--- a/src/OpenFOAM/fields/Fields/DynamicField/DynamicFieldI.H
+++ b/src/OpenFOAM/fields/Fields/DynamicField/DynamicFieldI.H
@@ -40,7 +40,7 @@ inline void Foam::DynamicField<T, SizeMin>::doAssignDynList
     if (capacity_ < len)
     {
         // Needs more space for the copy operation
-        List<T>::setAddressableSize(capacity_);  // Use entire space
+        List<T>::setAddressableSize(capacity_);
         List<T>::resize_nocopy(len);
         capacity_ = List<T>::size();
     }
@@ -66,19 +66,14 @@ inline void Foam::DynamicField<T, SizeMin>::doCapacity
     // Addressable length, possibly truncated by new capacity
     const label currLen = Foam::min(List<T>::size(), newCapacity);
 
-    // Corner case - see comments in DynamicList doCapacity
-    if (List<T>::size() == newCapacity)
-    {
-        List<T>::setAddressableSize(currLen+1);
-    }
-
+    List<T>::setAddressableSize(capacity_);
     if (nocopy)
     {
         List<T>::resize_nocopy(newCapacity);
     }
     else
     {
-        List<T>::resize(newCapacity);
+        List<T>::resize_copy(currLen, newCapacity);
     }
 
     capacity_ = List<T>::size();
@@ -147,6 +142,19 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField(const label initialCapacity)
 }
 
 
+template<class T, int SizeMin>
+inline Foam::DynamicField<T, SizeMin>::DynamicField
+(
+    const std::pair<label,label>& sizing
+)
+:
+    Field<T>(std::max(sizing.first, sizing.second)),
+    capacity_(Field<T>::size())
+{
+    List<T>::setAddressableSize(sizing.first);
+}
+
+
 template<class T, int SizeMin>
 inline Foam::DynamicField<T, SizeMin>::DynamicField
 (
@@ -163,7 +171,7 @@ template<class T, int SizeMin>
 inline Foam::DynamicField<T, SizeMin>::DynamicField
 (
     const label len,
-    const Foam::zero
+    Foam::zero
 )
 :
     Field<T>(len, Foam::zero{}),
@@ -423,16 +431,6 @@ inline void Foam::DynamicField<T, SizeMin>::setCapacity_nocopy
 }
 
 
-template<class T, int SizeMin>
-inline void Foam::DynamicField<T, SizeMin>::setCapacity_unsafe
-(
-    const label len
-) noexcept
-{
-    capacity_ = len;
-}
-
-
 template<class T, int SizeMin>
 inline void Foam::DynamicField<T, SizeMin>::reserve
 (
@@ -491,6 +489,18 @@ inline void Foam::DynamicField<T, SizeMin>::resize_nocopy
 }
 
 
+template<class T, int SizeMin>
+inline void Foam::DynamicField<T, SizeMin>::resize_fill
+(
+    const label len,
+    const T& val
+)
+{
+    this->doResize(true, len);  // nocopy = true
+    UList<T>::operator=(val);
+}
+
+
 template<class T, int SizeMin>
 inline void Foam::DynamicField<T, SizeMin>::resize
 (
@@ -534,8 +544,7 @@ inline void Foam::DynamicField<T, SizeMin>::shrink_to_fit()
 
     if (currLen < capacity_)
     {
-        // Adjust addressable size to trigger proper resizing
-        List<T>::setAddressableSize(currLen+1);
+        List<T>::setAddressableSize(capacity_);
         List<T>::resize(currLen);
         capacity_ = List<T>::size();
     }
@@ -554,15 +563,6 @@ inline void Foam::DynamicField<T, SizeMin>::shrink_unsafe()
 }
 
 
-template<class T, int SizeMin>
-inline Foam::DynamicField<T, SizeMin>&
-Foam::DynamicField<T, SizeMin>::shrink()
-{
-    this->shrink_to_fit();
-    return *this;
-}
-
-
 template<class T, int SizeMin>
 inline void
 Foam::DynamicField<T, SizeMin>::swap(List<T>& list)
@@ -592,7 +592,7 @@ template<int AnySizeMin>
 inline void Foam::DynamicField<T, SizeMin>::swap
 (
     DynamicField<T, AnySizeMin>& other
-)
+) noexcept
 {
     if
     (
@@ -616,7 +616,7 @@ template<int AnySizeMin>
 inline void Foam::DynamicField<T, SizeMin>::swap
 (
     DynamicList<T, AnySizeMin>& other
-)
+) noexcept
 {
     if
     (
@@ -822,7 +822,7 @@ inline void Foam::DynamicField<T, SizeMin>::operator=
 template<class T, int SizeMin>
 inline void Foam::DynamicField<T, SizeMin>::operator=
 (
-    const Foam::zero
+    Foam::zero
 )
 {
     UList<T>::operator=(Foam::zero{});
-- 
GitLab