From 92d52243afaa01262ccabd6b359793b9ae26cff4 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Tue, 16 Nov 2021 15:17:12 +0100
Subject: [PATCH] ENH: support cref() and shallow copies (refPtr and tmp)

- enables building HashTables with shadowed variables

- support good() and valid() as synonyms in memory classes
---
 applications/test/refPtr/Test-refPtr.C        | 18 ++++++---
 applications/test/tmp/Test-tmp.C              | 20 +++++++---
 .../Field/PrecisionAdaptor/PrecisionAdaptor.H |  6 +--
 src/OpenFOAM/memory/autoPtr/autoPtr.H         | 11 +++++-
 src/OpenFOAM/memory/refPtr/refPtr.H           | 32 ++++++++++++++--
 src/OpenFOAM/memory/refPtr/refPtrI.H          | 37 +++++++++++++++++--
 src/OpenFOAM/memory/tmp/tmp.H                 | 36 ++++++++++++++----
 src/OpenFOAM/memory/tmp/tmpI.H                | 20 +++++++++-
 8 files changed, 148 insertions(+), 32 deletions(-)

diff --git a/applications/test/refPtr/Test-refPtr.C b/applications/test/refPtr/Test-refPtr.C
index b2594d186c3..823fdb71680 100644
--- a/applications/test/refPtr/Test-refPtr.C
+++ b/applications/test/refPtr/Test-refPtr.C
@@ -32,14 +32,22 @@ struct myScalarField : public scalarField
 template<class T>
 void printInfo(const refPtr<T>& item, const bool verbose = false)
 {
-    Info<< "refPtr valid:" << Switch::name(item.valid())
+    Info<< "refPtr good:" << Switch::name(item.good())
         << " pointer:" << Switch::name(item.is_pointer())
-        << " addr: " << name(item.get())
+        << " addr: " << Foam::name(item.get())
         << " movable:" << Switch(item.movable());
 
-    Info<< nl;
-
-    if (verbose && item.valid())
+    Info<< " move-constructible:"
+        << std::is_move_constructible<refPtr<T>>::value
+        << " move-assignable:"
+        << std::is_move_assignable<refPtr<T>>::value
+        << " nothrow:"
+        << std::is_nothrow_move_assignable<refPtr<T>>::value
+        << " trivially:"
+        << std::is_trivially_move_assignable<refPtr<T>>::value
+        << nl;
+
+    if (verbose && item)
     {
         Info<< "content: " << item() << nl;
     }
diff --git a/applications/test/tmp/Test-tmp.C b/applications/test/tmp/Test-tmp.C
index 366fcb10998..52f1fdac2f1 100644
--- a/applications/test/tmp/Test-tmp.C
+++ b/applications/test/tmp/Test-tmp.C
@@ -32,18 +32,26 @@ struct myScalarField : public scalarField
 template<class T>
 void printInfo(const tmp<T>& item, const bool verbose = false)
 {
-    Info<< "tmp valid:" << Switch::name(item.valid())
+    Info<< "tmp good:" << Switch::name(item.good())
         << " pointer:" << Switch::name(item.is_pointer())
-        << " addr: " << name(item.get())
+        << " addr: " << Foam::name(item.get())
         << " movable:" << Switch(item.movable());
-
-    if (item.valid())
+    if (item)
     {
         Info<< " refCount:" << item->count();
     }
-    Info<< nl;
 
-    if (verbose && item.valid())
+    Info<< " move-constructible:"
+        << std::is_move_constructible<tmp<T>>::value
+        << " move-assignable:"
+        << std::is_move_assignable<tmp<T>>::value
+        << " nothrow:"
+        << std::is_nothrow_move_assignable<tmp<T>>::value
+        << " trivially:"
+        << std::is_trivially_move_assignable<tmp<T>>::value
+        << nl;
+
+    if (verbose && item)
     {
         Info<< "content: " << item() << nl;
     }
diff --git a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
index 94372dab7ba..e225a30981c 100644
--- a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
+++ b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
@@ -128,7 +128,7 @@ public:
         bool active() const noexcept
         {
             // Same as refPtr::movable()
-            return (this->is_pointer() && this->valid());
+            return (this->is_pointer() && this->good());
         }
 
         //- Commit adapted content changes (no-op for const adaptor)
@@ -253,13 +253,13 @@ public:
         bool active() const noexcept
         {
             // Same as refPtr::movable()
-            return (this->is_pointer() && this->valid());
+            return (this->is_pointer() && this->good());
         }
 
         //- Commit adapted content changes back to original input (as required)
         void commit()
         {
-            if (this->active() && orig_.valid())
+            if (this->active() && orig_.good())
             {
                 const auto& stored = this->cref();
                 auto& input = orig_.ref();
diff --git a/src/OpenFOAM/memory/autoPtr/autoPtr.H b/src/OpenFOAM/memory/autoPtr/autoPtr.H
index af002bc84ad..9b78fe9279f 100644
--- a/src/OpenFOAM/memory/autoPtr/autoPtr.H
+++ b/src/OpenFOAM/memory/autoPtr/autoPtr.H
@@ -143,7 +143,7 @@ public:
     // Query
 
         //- True if the managed pointer is non-null
-        bool valid() const noexcept { return bool(ptr_); }
+        bool good() const noexcept { return bool(ptr_); }
 
 
     // Access
@@ -165,6 +165,7 @@ public:
     // Edit
 
         //- Release ownership and return the pointer.
+        //  \remark Method naming consistent with std::unique_ptr
         inline T* release() noexcept;
 
         //- Same as \c release().
@@ -175,6 +176,7 @@ public:
         //  \remark Method naming consistent with Foam::tmp
         void clear() noexcept { reset(nullptr); }
 
+
         //- Delete managed object and set to new given pointer
         //  \remark Same as move assign, but better for code documentation
         inline void reset(autoPtr<T>&& other) noexcept;
@@ -224,7 +226,7 @@ public:
 
     // Casting
 
-        //- True if pointer/reference is non-null. Same as valid()
+        //- True if pointer/reference is non-null. Same as good()
         explicit operator bool() const noexcept { return bool(ptr_); }
 
         //- Cast to pointer type
@@ -267,6 +269,9 @@ public:
 
     // Housekeeping
 
+        //- Identical to good(), or bool operator
+        bool valid() const noexcept { return bool(ptr_); }
+
         //- Deprecated(2020-07) True if the managed pointer is null
         //
         //  \deprecated(2020-07) - use bool operator
@@ -285,6 +290,8 @@ public:
 };
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 // Global Functions
 
 //- Specializes the Swap algorithm for autoPtr.
diff --git a/src/OpenFOAM/memory/refPtr/refPtr.H b/src/OpenFOAM/memory/refPtr/refPtr.H
index b78b5b0d8da..4469d09a875 100644
--- a/src/OpenFOAM/memory/refPtr/refPtr.H
+++ b/src/OpenFOAM/memory/refPtr/refPtr.H
@@ -151,8 +151,8 @@ public:
 
     // Query
 
-        //- True for non-null pointer/reference
-        bool valid() const noexcept { return bool(ptr_); }
+        //- True if pointer/reference is non-null.
+        bool good() const noexcept { return bool(ptr_); }
 
         //- If the stored/referenced content is const
         bool is_const() const noexcept { return type_ == CREF; }
@@ -187,20 +187,27 @@ public:
         //  Fatal for a null managed pointer.
         inline T& constCast() const;
 
+        //- Return a shallow copy as a wrapped reference, preserving the
+        //- const/non-const status.
+        inline refPtr<T> shallowClone() const noexcept;
+
 
     // Edit
 
         //- Release ownership and return the pointer.
         //- A no-op for reference objects (returns nullptr).
+        //  \remark Method naming consistent with std::unique_ptr
         inline T* release() noexcept;
 
         //- Return managed pointer for reuse, or clone() the object reference.
+        //  \remark Method naming consistent with Foam::tmp
         inline T* ptr() const;
 
         //- If object pointer points to valid object:
         //- delete object and set pointer to nullptr
         inline void clear() const noexcept;
 
+
         //- Clear existing and transfer ownership.
         inline void reset(refPtr<T>&& other) noexcept;
 
@@ -213,6 +220,10 @@ public:
         //- Clear existing and transfer ownership from unique_ptr
         void reset(std::unique_ptr<T>&& other) { reset(other.release()); }
 
+
+        //- Clear existing and set (const) reference from other
+        inline void cref(const refPtr<T>& other) noexcept;
+
         //- Clear existing and set (const) reference
         inline void cref(const T& obj) noexcept;
 
@@ -220,6 +231,7 @@ public:
         //  The pointer can be null, which is handled like a clear().
         inline void cref(const T* p) noexcept;
 
+
         //- Clear existing and set (non-const) reference
         inline void ref(T& obj) noexcept;
 
@@ -227,6 +239,7 @@ public:
         //  The pointer can be null, which is handled like a clear().
         inline void ref(T* p) noexcept;
 
+
         //- Swaps the managed object with other.
         inline void swap(refPtr<T>& other) noexcept;
 
@@ -252,11 +265,17 @@ public:
         //- Return const reference to the object - same as cref() method.
         const T& operator()() const { return cref(); }
 
+
+    // Casting
+
+        //- True if pointer/reference is non-null. Same as good()
+        explicit operator bool() const noexcept { return bool(ptr_); }
+
         //- Cast to underlying data type, using the cref() method.
         operator const T&() const { return cref(); }
 
-        //- True if pointer/reference is non-null. Same as valid()
-        explicit operator bool() const noexcept { return bool(ptr_); }
+
+    // Assignment
 
         //- Transfer ownership of the managed pointer.
         //  Fatal for a null managed pointer or if the object is const.
@@ -278,6 +297,9 @@ public:
 
     // Housekeeping
 
+        //- Identical to good(), or bool operator
+        bool valid() const noexcept { return bool(ptr_); }
+
         //- Deprecated(2020-07) True if a null managed pointer
         //
         //  \deprecated(2020-07) - use bool operator
@@ -286,6 +308,8 @@ public:
 };
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 // Global Functions
 
 //- Specialized Swap algorithm for refPtr.
diff --git a/src/OpenFOAM/memory/refPtr/refPtrI.H b/src/OpenFOAM/memory/refPtr/refPtrI.H
index 0664701b180..ff5ce5ee8f4 100644
--- a/src/OpenFOAM/memory/refPtr/refPtrI.H
+++ b/src/OpenFOAM/memory/refPtr/refPtrI.H
@@ -167,6 +167,8 @@ inline Foam::refPtr<T>::refPtr(const refPtr<T>& rhs, bool reuse)
 }
 
 
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
 template<class T>
 inline Foam::refPtr<T>::~refPtr()
 {
@@ -200,7 +202,7 @@ inline const T& Foam::refPtr<T>::cref() const
 template<class T>
 inline T& Foam::refPtr<T>::ref() const
 {
-    if (type_ == CREF)
+    if (is_const())
     {
         FatalErrorInFunction
             << "Attempted non-const reference to const object: "
@@ -225,6 +227,21 @@ inline T& Foam::refPtr<T>::constCast() const
 }
 
 
+template<class T>
+inline Foam::refPtr<T> Foam::refPtr<T>::shallowClone() const noexcept
+{
+    refPtr<T> dup;
+
+    if (ptr_)
+    {
+        dup.ptr_ = ptr_;
+        dup.type_ = (is_const() ? CREF : REF);
+    }
+
+    return dup;
+}
+
+
 template<class T>
 inline T* Foam::refPtr<T>::release() noexcept
 {
@@ -299,6 +316,20 @@ inline void Foam::refPtr<T>::reset(refPtr<T>&& other) noexcept
 }
 
 
+template<class T>
+inline void Foam::refPtr<T>::cref(const refPtr<T>& other) noexcept
+{
+    if (&other == this)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clear();
+    ptr_ = other.ptr_;
+    type_ = (ptr_ ? CREF : PTR);
+}
+
+
 template<class T>
 inline void Foam::refPtr<T>::cref(const T& obj) noexcept
 {
@@ -368,7 +399,7 @@ inline const T& Foam::refPtr<T>::operator*() const
 template<class T>
 inline T& Foam::refPtr<T>::operator*()
 {
-    if (type_ == CREF)
+    if (is_const())
     {
         FatalErrorInFunction
             << "Attempt to cast const object to non-const: "
@@ -403,7 +434,7 @@ inline const T* Foam::refPtr<T>::operator->() const
 template<class T>
 inline T* Foam::refPtr<T>::operator->()
 {
-    if (type_ == CREF)
+    if (is_const())
     {
         FatalErrorInFunction
             << "Attempt to cast const object to non-const: "
diff --git a/src/OpenFOAM/memory/tmp/tmp.H b/src/OpenFOAM/memory/tmp/tmp.H
index ccd2efc6242..c24f5260fbb 100644
--- a/src/OpenFOAM/memory/tmp/tmp.H
+++ b/src/OpenFOAM/memory/tmp/tmp.H
@@ -166,8 +166,8 @@ public:
 
     // Query
 
-        //- True if pointer/reference is non-null
-        bool valid() const noexcept { return bool(ptr_); }
+        //- True if pointer/reference is non-null.
+        bool good() const noexcept { return bool(ptr_); }
 
         //- If the stored/referenced content is const
         bool is_const() const noexcept { return type_ == CREF; }
@@ -175,9 +175,6 @@ public:
         //- True if this is a managed pointer (not a reference)
         bool is_pointer() const noexcept { return type_ == PTR; }
 
-        //- Identical to is_pointer()
-        bool isTmp() const noexcept { return type_ == PTR; }
-
         //- True if this is a non-null managed pointer with a unique ref-count
         inline bool movable() const noexcept;
 
@@ -215,12 +212,17 @@ public:
         //- delete object and set pointer to nullptr
         inline void clear() const noexcept;
 
+
         //- Clear existing and transfer ownership.
         inline void reset(tmp<T>&& other) noexcept;
 
         //- Delete managed temporary object and set to new given pointer
         inline void reset(T* p = nullptr) noexcept;
 
+
+        //- Clear existing and set (const) reference from other
+        inline void cref(const tmp<T>& other) noexcept;
+
         //- Clear existing and set (const) reference
         inline void cref(const T& obj) noexcept;
 
@@ -228,6 +230,7 @@ public:
         //  The pointer can be null, which is handled like a clear().
         inline void cref(const T* p) noexcept;
 
+
         //- Clear existing and set to (non-const) reference
         inline void ref(T& obj) noexcept;
 
@@ -235,12 +238,17 @@ public:
         //  The pointer can be null, which is handled like a clear().
         inline void ref(T* p) noexcept;
 
+
         //- Swaps the managed object with other.
         inline void swap(tmp<T>& other) noexcept;
 
 
     // Member Operators
 
+        // Note: no 'operator*()' types since there are large chunks
+        // of code that use tmp\<Field\> and Field interchangeable
+        // Eg, \code (a * b) - and the '*' would be misinterpreted
+
         //- Dereferences (const) pointer to the managed object.
         //  Fatal for a null managed pointer.
         inline const T* operator->() const;
@@ -252,11 +260,17 @@ public:
         //- Return const reference to the object - same as cref() method.
         const T& operator()() const { return cref(); }
 
+
+    // Casting
+
+        //- True if pointer/reference is non-null. Same as good()
+        explicit operator bool() const noexcept { return bool(ptr_); }
+
         //- Cast to underlying data type, using the cref() method.
         operator const T&() const { return cref(); }
 
-        //- True if pointer/reference is non-null. Same as valid()
-        explicit operator bool() const noexcept { return bool(ptr_); }
+
+    // Assignment
 
         //- Transfer ownership of the managed pointer.
         //  Fatal for a null managed pointer or if the object is const.
@@ -275,6 +289,12 @@ public:
 
     // Housekeeping
 
+        //- Identical to good(), or bool operator
+        bool valid() const noexcept { return bool(ptr_); }
+
+        //- Identical to is_pointer()
+        bool isTmp() const noexcept { return type_ == PTR; }
+
         //- Deprecated(2020-07) True if a null managed pointer
         //
         //  \deprecated(2020-07) - use bool operator
@@ -283,6 +303,8 @@ public:
 };
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 // Global Functions
 
 //- Specialized Swap algorithm for tmp.
diff --git a/src/OpenFOAM/memory/tmp/tmpI.H b/src/OpenFOAM/memory/tmp/tmpI.H
index b58eb7df37e..d378e2a612f 100644
--- a/src/OpenFOAM/memory/tmp/tmpI.H
+++ b/src/OpenFOAM/memory/tmp/tmpI.H
@@ -191,6 +191,8 @@ inline Foam::tmp<T>::tmp(const tmp<T>& rhs, bool reuse)
 }
 
 
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
 template<class T>
 inline Foam::tmp<T>::~tmp()
 {
@@ -224,7 +226,7 @@ inline const T& Foam::tmp<T>::cref() const
 template<class T>
 inline T& Foam::tmp<T>::ref() const
 {
-    if (type_ == CREF)
+    if (is_const())
     {
         FatalErrorInFunction
             << "Attempted non-const reference to const object: "
@@ -325,6 +327,20 @@ inline void Foam::tmp<T>::reset(tmp<T>&& other) noexcept
 }
 
 
+template<class T>
+inline void Foam::tmp<T>::cref(const tmp<T>& other) noexcept
+{
+    if (&other == this)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clear();
+    ptr_ = other.ptr_;
+    type_ = (ptr_ ? CREF : PTR);
+}
+
+
 template<class T>
 inline void Foam::tmp<T>::cref(const T& obj) noexcept
 {
@@ -395,7 +411,7 @@ inline const T* Foam::tmp<T>::operator->() const
 template<class T>
 inline T* Foam::tmp<T>::operator->()
 {
-    if (type_ == CREF)
+    if (is_const())
     {
         FatalErrorInFunction
             << "Attempt to cast const object to non-const: "
-- 
GitLab