Commit be058bec authored by Mark Olesen's avatar Mark Olesen

ENH: support writable reference for tmp (#1775)

- improves flexibility. Can tag a tmp as allowing non-const access to
  the reference and skip additional const_cast in following code. For
  example,

      tmp<volScalarField> tfld(nullptr);
      auto* ptr = getObjectPtr<volScalarField>("field");
      if (ptr)
      {
          tfld.ref(*ptr);
      }
      else
      {
          tfld.reset(volScalarField::New(...));
      }
      auto& fld = tfld.ref();

ENH: renamed tmpNrc to refPtr

- the name 'refPtr' (reference|pointer) should be easier to remember
  than tmpNrc (tmp, but non-ref-counted).

- provide tmpNrc typedef and header for code compatibility

NOTE

- in some places refPtr and tmp can be used instead of a
  std::reference_wrapper for handling external references.

  Unlike std::reference_wrapper, it can be default constructed
  (holding nothing), whereas reference_wrapper may need a dummy
  reference. However, the lifetime extension of references _may_ be
  better with reference_wrapper.
parent 5acb5f35
......@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -27,18 +27,19 @@ Class
Foam::PrecisionAdaptor
Description
Conversion adaptor for Field that either wraps as a tmp reference
or creates the necessary tmp and copies the values on construction
and destruction.
This provides automatic conversion between (scalar) types for use
with linear solvers able to run mixed precision.
Conversion adaptor for Field/List that either wrap the input as a
reference, or creates a temporary pointer and copies the values
on construction/destruction.
This provides, for example, automatic conversion between types
for linear solvers able to run mixed precision.
\*---------------------------------------------------------------------------*/
#ifndef PrecisionAdaptor_H
#define PrecisionAdaptor_H
#include "tmpNrc.H"
#include "refPtr.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -46,22 +47,19 @@ Description
namespace Foam
{
//- A const Field wrapper with possible data conversion
//- A const Field/List wrapper with possible data conversion
template<class Type, class InputType, template<class> class Container = Field>
class ConstPrecisionAdaptor
:
public tmpNrc<Container<Type>>
public refPtr<Container<Type>>
{
// Private Member Functions
//- Copy in field
void copyInput(const Container<InputType>& input)
{
this->clear();
Container<Type>* p = new Container<Type>(input.size());
this->reset(p);
std::copy(input.cbegin(), input.cend(), p->begin());
this->reset(new Container<Type>(input.size()));
std::copy(input.cbegin(), input.cend(), this->ref().begin());
}
//- Construct from tmp Field, copy/move as required
......@@ -71,19 +69,20 @@ class ConstPrecisionAdaptor
{
auto& tinput = reinterpret_cast<tmp<Container<Type>>&>(input);
if (tinput.isTmp())
if (tinput.is_pointer())
{
// Reset to tmp
// Acquire control of the managed pointer
this->reset(tinput.ptr());
}
else
{
// Use const reference
this->cref(tinput.cref());
}
}
else
{
this->copyInput(input());
this->copyInput(input.cref());
}
input.clear();
}
......@@ -100,10 +99,11 @@ public:
//- Construct from Container<InputType>, copying on input as required
ConstPrecisionAdaptor(const Container<InputType>& input)
:
tmpNrc<Container<Type>>()
refPtr<Container<Type>>()
{
if (std::is_same<Type, InputType>::value)
{
// Use const reference directly
this->cref(reinterpret_cast<const FieldType&>(input));
}
else
......@@ -116,7 +116,7 @@ public:
//- Construct from tmp Container, copy/move as required
ConstPrecisionAdaptor(tmp<Container<InputType>>&& input)
:
tmpNrc<Container<Type>>()
refPtr<Container<Type>>()
{
this->moveInput(input);
}
......@@ -125,7 +125,7 @@ public:
//- Construct from tmp Container, copy/move as required
ConstPrecisionAdaptor(const tmp<Container<InputType>>& input)
:
tmpNrc<Container<Type>>()
refPtr<Container<Type>>()
{
this->moveInput(const_cast<tmp<Container<InputType>>&>(input));
}
......@@ -133,6 +133,8 @@ public:
// Member Functions
// May need in the future: using refPtr<Container<Type>>::get;
//- Return the field
static const Container<Type>& get
(
......@@ -154,15 +156,15 @@ public:
};
//- A Field wrapper with possible data conversion
//- A non-const Field/List wrapper with possible data conversion
template<class Type, class InputType, template<class> class Container = Field>
class PrecisionAdaptor
:
public tmpNrc<Container<Type>>
public refPtr<Container<Type>>
{
// Private Data
//- Reference to underlying field
//- Reference to underlying (input) data
Container<InputType>& ref_;
......@@ -171,11 +173,10 @@ class PrecisionAdaptor
//- Copy in field
void copyInput(const Container<InputType>& input, const bool copy)
{
Container<Type>* p = new Container<Type>(input.size());
this->reset(p);
this->reset(new Container<Type>(input.size()));
if (copy)
{
std::copy(input.cbegin(), input.cend(), p->begin());
std::copy(input.cbegin(), input.cend(), this->ref().begin());
}
}
......@@ -191,12 +192,13 @@ public:
//- Construct from Container<InputType>, copying on input if required
PrecisionAdaptor(Container<InputType>& input, const bool copy = true)
:
tmpNrc<Container<Type>>(),
refPtr<Container<Type>>(),
ref_(input)
{
if (std::is_same<Type, InputType>::value)
{
this->cref(reinterpret_cast<const FieldType&>(input));
// Use non-const reference directly
this->ref(reinterpret_cast<FieldType&>(ref_));
}
else
{
......@@ -205,25 +207,16 @@ public:
}
//- Destructor, copying on destroy
//- Destructor, copy back on destroy
~PrecisionAdaptor()
{
if (this->isTmp())
if (this->is_pointer())
{
const FieldType& store = this->cref();
ref_.resize(store.size());
ref_.resize(store.size()); // extra safety
std::copy(store.cbegin(), store.cend(), ref_.begin());
}
}
// Member Functions
//- Allow modification without const-ref check
FieldType& ref()
{
return this->constCast();
}
};
......
......@@ -233,7 +233,7 @@ bool Foam::fileOperation::isFileOrDir(const bool isFile, const fileName& f)
}
Foam::tmpNrc<Foam::fileOperation::dirIndexList>
Foam::refPtr<Foam::fileOperation::dirIndexList>
Foam::fileOperation::lookupAndCacheProcessorsPath
(
const fileName& fName,
......@@ -361,11 +361,12 @@ Foam::fileOperation::lookupAndCacheProcessorsPath
return procsDirs_[procPath];
}
}
return tmpNrc<dirIndexList>(new dirIndexList(0, dirIndex()));
return refPtr<dirIndexList>::New();
}
Foam::tmpNrc<Foam::fileOperation::dirIndexList>
Foam::refPtr<Foam::fileOperation::dirIndexList>
Foam::fileOperation::lookupProcessorsPath(const fileName& fName) const
{
// Use parallel synchronisation
......@@ -531,7 +532,7 @@ Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const
if (proci != -1)
{
// Get all processor directories
tmpNrc<dirIndexList> procDirs(lookupProcessorsPath(fName));
refPtr<dirIndexList> procDirs(lookupProcessorsPath(fName));
forAll(procDirs(), i)
{
const fileName& procDir = procDirs()[i].first();
......@@ -688,7 +689,7 @@ Foam::instantList Foam::fileOperation::findTimes
// Get all processor directories
tmpNrc<dirIndexList> procDirs(lookupProcessorsPath(directory));
refPtr<dirIndexList> procDirs(lookupProcessorsPath(directory));
forAll(procDirs(), i)
{
const fileName& procDir = procDirs()[i].first();
......
......@@ -49,7 +49,7 @@ Description
#include "fileMonitor.H"
#include "labelList.H"
#include "Switch.H"
#include "tmpNrc.H"
#include "refPtr.H"
#include "Enum.H"
#include "Tuple2.H"
......@@ -135,17 +135,18 @@ protected:
//- Helper: check for file (isFile) or directory (!isFile)
static bool isFileOrDir(const bool isFile, const fileName&);
//- Lookup name of processorsDDD using cache. Return empty fileName
// if not found.
tmpNrc<dirIndexList> lookupAndCacheProcessorsPath
//- Lookup name of processorsDDD using cache.
// \return empty fileName if not found.
refPtr<dirIndexList> lookupAndCacheProcessorsPath
(
const fileName&,
const bool syncPar
) const;
//- Lookup name of processorsDDD using cache. Return empty fileName
// if not found. To be called on all processors
virtual tmpNrc<dirIndexList> lookupProcessorsPath
//- Lookup name of processorsDDD using cache.
// \note To be called on all processors
// \return empty fileName if not found.
virtual refPtr<dirIndexList> lookupProcessorsPath
(
const fileName&
) const;
......
......@@ -199,7 +199,7 @@ Foam::fileOperations::masterUncollatedFileOperation::filePathInfo
// 2. Check processors/
if (io.time().processorCase())
{
tmpNrc<dirIndexList> pDirs(lookupProcessorsPath(io.objectPath()));
refPtr<dirIndexList> pDirs(lookupProcessorsPath(io.objectPath()));
forAll(pDirs(), i)
{
const fileName& pDir = pDirs()[i].first();
......@@ -268,7 +268,7 @@ Foam::fileOperations::masterUncollatedFileOperation::filePathInfo
if (newInstancePath.size() && newInstancePath != io.instance())
{
// 1. Try processors equivalent
tmpNrc<dirIndexList> pDirs
refPtr<dirIndexList> pDirs
(
lookupProcessorsPath(io.objectPath())
);
......@@ -1499,7 +1499,7 @@ Foam::fileOperations::masterUncollatedFileOperation::findInstance
// parent directory in case of parallel)
tmpNrc<dirIndexList> pDirs(lookupProcessorsPath(io.objectPath()));
refPtr<dirIndexList> pDirs(lookupProcessorsPath(io.objectPath()));
word foundInstance;
......
......@@ -114,7 +114,7 @@ Foam::fileName Foam::fileOperations::uncollatedFileOperation::filePathInfo
// Check if parallel "procesors" directory
if (io.time().processorCase())
{
tmpNrc<dirIndexList> pDirs
refPtr<dirIndexList> pDirs
(
fileOperation::lookupAndCacheProcessorsPath
(
......@@ -166,7 +166,7 @@ Foam::fileName Foam::fileOperations::uncollatedFileOperation::filePathInfo
}
Foam::tmpNrc<Foam::fileOperation::dirIndexList>
Foam::refPtr<Foam::fileOperation::dirIndexList>
Foam::fileOperations::uncollatedFileOperation::lookupProcessorsPath
(
const fileName& fName
......
......@@ -68,9 +68,10 @@ protected:
const bool search
) const;
//- Lookup name of processorsDDD using cache. Return empty fileName
// if not found. Do not use any parallel synchronisation
virtual tmpNrc<dirIndexList> lookupProcessorsPath
//- Lookup name of processorsDDD using cache.
// \not Do not use any parallel synchronisation
// \return empty fileName if not found.
virtual refPtr<dirIndexList> lookupProcessorsPath
(
const fileName&
) const;
......
......@@ -25,13 +25,13 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::tmpNrc
Foam::refPtr
Description
A class for managing temporary objects without reference counting.
A class for managing references or pointers (no reference counting)
SourceFiles
tmpNrcI.H
refPtrI.H
See also
Foam::autoPtr
......@@ -39,8 +39,8 @@ See also
\*---------------------------------------------------------------------------*/
#ifndef tmpNrc_H
#define tmpNrc_H
#ifndef refPtr_H
#define refPtr_H
#include "tmp.H"
......@@ -50,11 +50,11 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class tmpNrc Declaration
Class refPtr Declaration
\*---------------------------------------------------------------------------*/
template<class T>
class tmpNrc
class refPtr
{
// Private Data
......@@ -62,7 +62,8 @@ class tmpNrc
enum refType
{
PTR, //!< Managing a pointer (not ref-counted)
CREF //!< Using (const) reference to an object
CREF, //!< Using (const) reference to an object
REF //!< Using (non-const) reference to an object
};
//- The managed pointer or address of the object (reference)
......@@ -76,10 +77,10 @@ public:
// STL type definitions
//- Type of object being managed
//- Type of object being managed or referenced
typedef T element_type;
//- Pointer to type of object being managed
//- Pointer to type of object being managed or referenced
typedef T* pointer;
......@@ -89,50 +90,50 @@ public:
// Factory Methods
//- Construct tmpNrc of T with forwarding arguments
//- Construct refPtr of T with forwarding arguments
// \param args list of arguments with which an instance of T
// will be constructed.
//
// \note Similar to std::make_shared, but the overload for
// array types is not disabled.
template<class... Args>
inline static tmpNrc<T> New(Args&&... args);
inline static refPtr<T> New(Args&&... args);
//- Construct tmpNrc from derived type with forwarding arguments
//- Construct refPtr from derived type with forwarding arguments
// \param args list of arguments with which an instance of U
// will be constructed.
//
// \note Similar to New but for derived types
template<class U, class... Args>
inline static tmpNrc<T> NewFrom(Args&&... args);
inline static refPtr<T> NewFrom(Args&&... args);
// Constructors
//- Default construct, no managed pointer.
inline constexpr tmpNrc() noexcept;
inline constexpr refPtr() noexcept;
//- Construct with no managed pointer.
inline constexpr tmpNrc(std::nullptr_t) noexcept;
inline constexpr refPtr(std::nullptr_t) noexcept;
//- Construct, taking ownership of the pointer.
inline explicit tmpNrc(T* p) noexcept;
inline explicit refPtr(T* p) noexcept;
//- Construct for a const reference to an object.
inline tmpNrc(const T& obj) noexcept;
inline refPtr(const T& obj) noexcept;
//- Move construct, transferring ownership.
inline tmpNrc(tmpNrc<T>&& t) noexcept;
inline refPtr(refPtr<T>&& t) noexcept;
//- Copy construct
inline tmpNrc(const tmpNrc<T>& t);
inline refPtr(const refPtr<T>& t);
//- Copy construct. Optionally reusing pointer.
inline tmpNrc(const tmpNrc<T>& t, bool reuse);
inline refPtr(const refPtr<T>& t, bool reuse);
//- Destructor: deletes managed pointer
inline ~tmpNrc();
inline ~refPtr();
// Member Functions
......@@ -148,6 +149,9 @@ public:
//- True for non-null pointer/reference
bool valid() const noexcept { return ptr_; }
//- True if this is a managed pointer (not a reference)
bool is_pointer() const noexcept { return type_ == PTR; }
//- True if this is a managed pointer (not a reference)
bool isTmp() const noexcept { return type_ == PTR; }
......@@ -166,8 +170,8 @@ public:
//- Return const pointer without nullptr checking.
const T* get() const noexcept { return ptr_; }
//- Return the const object reference or a const reference to the
//- contents of a non-null managed pointer.
//- Return const reference to the object or to the contents
//- of a (non-null) managed pointer.
// Fatal for a null managed pointer
inline const T& cref() const;
......@@ -185,8 +189,7 @@ public:
// Edit
//- Return managed pointer for reuse, or clone() the const object
//- reference.
//- Return managed pointer for reuse, or clone() the object reference.
inline T* ptr() const;
//- If object pointer points to valid object:
......@@ -197,19 +200,21 @@ public:
inline void reset(T* p = nullptr) noexcept;
//- Clear existing and transfer ownership.
inline void reset(tmpNrc<T>&& other) noexcept;
inline void reset(refPtr<T>&& other) noexcept;
//- Delete managed temporary object and set to const reference
//- Delete managed temporary object and set to (const) reference
inline void cref(const T& obj) noexcept;
//- Delete managed temporary object and set to (non-const) reference
inline void ref(T& obj) noexcept;
//- Swaps the managed object with other.
inline void swap(tmpNrc<T>& other) noexcept;
inline void swap(refPtr<T>& other) noexcept;
// Member Operators
//- Return const reference to the object.
// Identical to cref() method.
//- Identical to cref() method.
inline const T& operator()() const;
//- Cast to underlying data type, using the cref() method.
......@@ -228,10 +233,10 @@ public:
//- Transfer ownership of the managed pointer.
// Fatal for a null managed pointer or if the object is const.
inline void operator=(const tmpNrc<T>& t);
inline void operator=(const refPtr<T>& t);
//- Clear existing and transfer ownership.
inline void operator=(tmpNrc<T>&& other) noexcept;
inline void operator=(refPtr<T>&& other) noexcept;
//- Take ownership of the pointer.
// Fatal for a null pointer
......@@ -247,10 +252,10 @@ public:
// Global Functions
//- Specializes the Swap algorithm for tmpNrc.
//- Specializes the Swap algorithm for refPtr.
// Swaps the pointers and types of lhs and rhs. Calls \c lhs.swap(rhs)
template<class T>
void Swap(tmpNrc<T>& lhs, tmpNrc<T>& rhs)
void Swap(refPtr<T>& lhs, refPtr<T>& rhs)
{
lhs.swap(rhs);
}
......@@ -262,7 +267,7 @@ void Swap(tmpNrc<T>& lhs, tmpNrc<T>& rhs)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "tmpNrcI.H"
#include "refPtrI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......
......@@ -33,24 +33,24 @@ License
template<class T>
template<class... Args>
inline Foam::tmpNrc<T> Foam::tmpNrc<T>::New(Args&&... args)
inline Foam::refPtr<T> Foam::refPtr<T>::New(Args&&... args)
{
return tmpNrc<T>(new T(std::forward<Args>(args)...));
return refPtr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
template<class U, class... Args>
inline Foam::tmpNrc<T> Foam::tmpNrc<T>::NewFrom(Args&&... args)
inline Foam::refPtr<T> Foam::refPtr<T>::NewFrom(Args&&... args)
{
return tmpNrc<T>(new U(std::forward<Args>(args)...));
return refPtr<T>(new U(std::forward<Args>(args)...));
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T>
inline constexpr Foam::tmpNrc<T>::tmpNrc() noexcept
inline constexpr Foam::refPtr<T>::refPtr() noexcept
:
ptr_(nullptr),
type_(PTR)
......@@ -58,7 +58,7 @@ inline constexpr Foam::tmpNrc<T>::tmpNrc() noexcept
template<class T>
inline constexpr Foam::tmpNrc<T>::tmpNrc(std::nullptr_t) noexcept
inline constexpr Foam::refPtr<T>::refPtr(std::nullptr_t) noexcept
:
ptr_(nullptr),
type_(PTR)
......@@ -66,7 +66,7 @@ inline constexpr Foam::tmpNrc<T>::tmpNrc(std::nullptr_t) noexcept
template<class T>
inline Foam::tmpNrc<T>::tmpNrc(T* p) noexcept
inline Foam::refPtr<T>::refPtr(T* p) noexcept
:
ptr_(p),
type_(PTR)
......@@ -74,7 +74,7 @@ inline Foam::tmpNrc<T>::tmpNrc(T* p) noexcept
template<class T>
inline Foam::tmpNrc<T>::tmpNrc(const T& obj) noexcept
inline Foam::refPtr<T>::refPtr(const T& obj) noexcept
:
ptr_(const_cast<T*>(&obj)),
type_(CREF)
......@@ -82,7 +82,7 @@ inline Foam::tmpNrc<T>::tmpNrc(const T& obj) noexcept
template<class T>
inline Foam::tmpNrc<T>::tmpNrc(tmpNrc<T>&& t) noexcept
inline Foam::refPtr<T>::refPtr(refPtr<T>&& t) noexcept
:
ptr_(t.ptr_),
type_(t.type_)
......@@ -93,7 +93,7 @@ inline Foam::tmpNrc<T>::tmpNrc(tmpNrc<T>&& t) noexcept
template<class T>
inline Foam::tmpNrc<T>::tmpNrc(const tmpNrc<T>& t)
inline Foam::refPtr<T>::refPtr(const refPtr<T>& t)
:
ptr_(t.ptr_),
type_(t.type_)
......@@ -115,7 +115,7 @@ inline Foam::tmpNrc<T>::tmpNrc(const tmpNrc<T>& t)
template<class T>
inline Foam::tmpNrc<T>::tmpNrc(const tmpNrc<T>& t, bool reuse)
inline Foam::refPtr<T>::refPtr(const refPtr<T>& t, bool reuse)
:
ptr_(t.ptr_),
type_(t.type_)
......@@ -144,7 +144,7 @@ inline Foam::tmpNrc<T>::tmpNrc(const tmpNrc<T>& t, bool reuse)
template<clas