ENH: handle 'void' type in IOobject::typeHeaderOk

- can be used in most places where checkType=false is used

ENH: add non-const get() method to HashPtrTable

- allows checking and modification (symmetric with PtrList methods)

STYLE: improve annotations in fileOperations headers
This commit is contained in:
Mark Olesen
2025-08-25 15:09:31 +02:00
parent f3c97d41bd
commit 2446f3f0c7
33 changed files with 180 additions and 106 deletions

View File

@ -1,3 +1,3 @@
Test-HashPtrTable.C
Test-HashPtrTable.cxx
EXE = $(FOAM_USER_APPBIN)/Test-HashPtrTable

View File

@ -1,3 +1,3 @@
Test-HashTable2.C
Test-HashTable2.cxx
EXE = $(FOAM_USER_APPBIN)/Test-HashTable2

View File

@ -1,3 +1,3 @@
Test-HashTable3.C
Test-HashTable3.cxx
EXE = $(FOAM_USER_APPBIN)/Test-HashTable3

View File

@ -1,3 +1,3 @@
Test-IOobjectList.C
Test-IOobjectList.cxx
EXE = $(FOAM_USER_APPBIN)/Test-IOobjectList

View File

@ -1,3 +1,3 @@
Test-PtrList.C
Test-PtrList.cxx
EXE = $(FOAM_USER_APPBIN)/Test-PtrList

View File

@ -149,6 +149,10 @@ public:
//- if the key does not exist in the table.
inline const T* get(const Key& key) const;
//- Return pointer associated with given entry or a nullptr
//- if the key does not exist in the table.
inline T* get(const Key& key);
// Edit
@ -234,7 +238,9 @@ public:
inline bool emplace(const Key& key, Args&&... args);
//- Emplace set an entry, overwriting any existing entries.
// \return Reference to the new element.
// \param key - the location to set
// \param args arguments to forward to the constructor of the element
// \return reference to the new element.
template<class... Args>
inline T& emplace_set(const Key& key, Args&&... args);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -57,6 +57,19 @@ inline const T* Foam::HashPtrTable<T, Key, Hash>::get(const Key& key) const
}
template<class T, class Key, class Hash>
inline T* Foam::HashPtrTable<T, Key, Hash>::get(const Key& key)
{
// Like lookup() with a nullptr + const_cast
iterator iter(this->find(key));
if (iter.good())
{
return iter.val();
}
return nullptr;
}
template<class T, class Key, class Hash>
template<class... Args>
inline bool Foam::HashPtrTable<T, Key, Hash>::emplace

View File

@ -537,14 +537,15 @@ public:
//- True if headerClassName() is non-empty (after reading)
inline bool hasHeaderClass() const noexcept;
//- Check if headerClassName() equals the expected type.
//- Always true if the expected type is empty.
inline bool isHeaderClass(const word& expectedType) const;
//- Check if headerClassName() equals Type::typeName
//- Always true for a \c void type.
template<class Type>
inline bool isHeaderClass() const;
//- Same as isHeaderClass()
template<class Type>
bool isHeaderClassName() const { return isHeaderClass<Type>(); }
// Meta-data
@ -611,20 +612,18 @@ public:
fileName objectRelPath() const;
//- Redirect to fileHandler filePath, searching locally.
// When search is false, simply use the current instance,
// otherwise search previous instances.
fileName localFilePath
(
const word& typeName,
//! False: use current instance; True: search previous instances
const bool search=true
) const;
//- Redirect to fileHandler filePath, searching up if in parallel.
// When search is false, simply use the current instance,
// otherwise search previous instances.
fileName globalFilePath
(
const word& typeName,
//! False: use current instance; True: search previous instances
const bool search=true
) const;
@ -645,17 +644,29 @@ public:
bool readHeader(dictionary& headerDict, Istream& is);
//- Read header (respects is_globalIOobject trait) and check its info.
//- A \c void type suppresses trait and type-name checks.
template<class Type>
bool typeHeaderOk
(
//! Check headerClassName against the type-name
const bool checkType = true,
[[maybe_unused]] const bool checkType = true,
//! Also search previous instances if not found at current instance
const bool search = true,
//! Report any check-type failures
const bool verbose = true
);
//- Forwards to single-parameter version with the specified search type.
//- A \c void type suppresses trait and type-name checks.
template<class Type, bool Searching>
bool typeHeaderOk
(
//! Check headerClassName against the type-name
const bool checkType = true,
//! Report any check-type failures
const bool verbose = true
);
//- Call localFilePath or globalFilePath for given type
//- depending on its is_globalIOobject trait.
template<class Type>
@ -718,19 +729,16 @@ public:
//- Copy assignment, copies all values (except the registry)
void operator=(const IOobject& io);
// Housekeeping
//- Same as isHeaderClass()
template<class Type>
bool isHeaderClassName() const { return isHeaderClass<Type>(); }
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Specialization for \c void always returns true (no headerClassName check).
template<>
inline bool IOobject::isHeaderClass<void>() const
{
return true;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -261,10 +261,23 @@ inline bool Foam::IOobject::hasHeaderClass() const noexcept
}
inline bool Foam::IOobject::isHeaderClass(const word& expectedType) const
{
return (expectedType.empty() || (expectedType == headerClassName_));
}
template<class Type>
inline bool Foam::IOobject::isHeaderClass() const
{
return (Type::typeName == headerClassName_);
if constexpr (std::is_void_v<Type>)
{
return true;
}
else
{
return (Type::typeName == headerClassName_);
}
}

View File

@ -215,17 +215,13 @@ bool Foam::IOobject::readAndCheckHeader
ok = handler.readHeader(*this, fName, typeName);
UPstream::parRun(oldParRun);
if
(
ok && checkType
&& !typeName.empty() && headerClassName_ != typeName
)
if (ok && checkType && !isHeaderClass(typeName))
{
ok = false;
if (verbose)
{
WarningInFunction
<< "Unexpected class name \"" << headerClassName_
<< "Unexpected class name \"" << headerClassName()
<< "\" expected \"" << typeName
<< "\" when reading " << fName << endl;
}
@ -251,17 +247,13 @@ bool Foam::IOobject::readAndCheckHeader
);
ok = handler.readHeader(*this, fName, typeName);
if
(
ok && checkType
&& !typeName.empty() && headerClassName_ != typeName
)
if (ok && checkType && !isHeaderClass(typeName))
{
ok = false;
if (verbose)
{
WarningInFunction
<< "Unexpected class name \"" << headerClassName_
<< "Unexpected class name \"" << headerClassName()
<< "\" expected \"" << typeName
<< "\" when reading " << fName << endl;
}

View File

@ -42,14 +42,35 @@ bool Foam::IOobject::typeHeaderOk
const bool verbose
)
{
return readAndCheckHeader
(
is_globalIOobject<Type>::value,
Type::typeName,
checkType,
search,
verbose
);
if constexpr (std::is_void_v<Type>)
{
return readAndCheckHeader
(
false, // isGlobal (false)
word::null, // typeName (n/a)
false, // checkType (false)
search,
verbose
);
}
else
{
return readAndCheckHeader
(
is_globalIOobject<Type>::value,
Type::typeName,
checkType,
search,
verbose
);
}
}
template<class Type, bool Searching>
bool Foam::IOobject::typeHeaderOk(const bool checkType, const bool verbose)
{
return typeHeaderOk<Type>(checkType, Searching, verbose);
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenFOAM Foundation
Copyright (C) 2019-2023 OpenCFD Ltd.
Copyright (C) 2019-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -32,7 +32,7 @@ Description
taking an Istream or ISstream. Aborts at any attempt to read from it.
Note
The inheritance from an empty IStringStream is solely for convenience
The inheritance from an empty ICharStream is solely for convenience
of implementation and should not be relied upon.
SourceFiles
@ -43,7 +43,8 @@ SourceFiles
#ifndef Foam_dummyISstream_H
#define Foam_dummyISstream_H
#include "StringStream.H"
#include "autoPtr.H"
#include "SpanStream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -56,7 +57,7 @@ namespace Foam
class dummyISstream
:
public IStringStream
public ICharStream
{
public:
@ -69,6 +70,15 @@ public:
virtual ~dummyISstream() = default;
// Factory Methods
//- Return a dummyISstream
static autoPtr<ISstream> New()
{
return autoPtr<ISstream>(new dummyISstream());
}
// Member Functions
// Stream-state

View File

@ -147,7 +147,7 @@ public:
virtual fileName objectPath
(
const IOobject& io,
const word& typeName
const word& typeName //!< currently unused
) const;
//- Writes a regIOobject (so header, contents and divider).

View File

@ -327,7 +327,7 @@ Foam::fileOperations::dummyFileOperation::readStream
) const
{
NotImplemented;
return autoPtr<ISstream>(new dummyISstream());
return dummyISstream::New();
}
@ -351,7 +351,7 @@ Foam::fileOperations::dummyFileOperation::NewIFstream
) const
{
NotImplemented;
return autoPtr<ISstream>(new dummyISstream());
return dummyISstream::New();
}

View File

@ -203,18 +203,21 @@ public:
// (reg)IOobject functionality
//- Search for an object. checkGlobal
//- Search for an object
virtual fileName filePath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
//! The wanted object typeName [optional, likely unused]
const word& typeName,
const bool search
) const;
//- Search for a directory. checkGlobal
//- Search for a directory
virtual fileName dirPath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const bool search
@ -234,7 +237,7 @@ public:
(
IOobject&,
const fileName&,
const word& typeName
const word& typeName //!< currently unused
) const;
//- Reads header for regIOobject and returns an ISstream
@ -243,7 +246,7 @@ public:
(
regIOobject&,
const fileName&,
const word& typeName,
const word& typeName, //!< currently unused
const bool readOnProc = true
) const;
@ -253,7 +256,7 @@ public:
regIOobject&,
const bool masterOnly,
const IOstreamOption::streamFormat format,
const word& typeName
const word& typeName //!< forwards to regIOobject
) const;
//- Generate an ISstream that reads a file

View File

@ -28,7 +28,6 @@ License
#include "fileOperation.H"
#include "objectRegistry.H"
#include "labelIOList.H"
#include "registerSwitch.H"
#include "stringOps.H"
#include "Time.H"
@ -728,7 +727,7 @@ bool Foam::fileOperation::exists(IOobject& io) const
(
isFile(objPath)
// object with local scope
&& io.typeHeaderOk<labelIOList>(false)
&& io.typeHeaderOk<regIOobject>(false)
);
}
@ -750,7 +749,7 @@ bool Foam::fileOperation::exists(IOobject& io) const
(
isFile(originalPath)
// object with local scope
&& io.typeHeaderOk<labelIOList>(false)
&& io.typeHeaderOk<regIOobject>(false)
);
}
}

View File

@ -684,27 +684,28 @@ public:
// (reg)IOobject functionality
//- Generate disk file name for object. Opposite of filePath.
// Optional wanted typeName.
virtual fileName objectPath
(
const IOobject& io,
//! The wanted object typeName [optional, likely unused]
const word& typeName
) const;
//- Search for an object. checkGlobal : also check undecomposed case
// Optional wanted typeName.
//- Search for an object
virtual fileName filePath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject&,
//! The wanted object typeName [optional, likely unused]
const word& typeName,
const bool search = true
) const = 0;
//- Search for a directory. checkGlobal : also check undecomposed
// case
//- Search for a directory
virtual fileName dirPath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const bool search = true
@ -724,7 +725,7 @@ public:
(
IOobject&,
const fileName&,
const word& typeName
const word& typeName //!< frequently unused?
) const = 0;
//- Reads header for regIOobject and returns an ISstream
@ -733,7 +734,7 @@ public:
(
regIOobject&,
const fileName&,
const word& typeName,
const word& typeName, //!< frequently unused?
const bool readOnProc = true
) const = 0;
@ -742,7 +743,9 @@ public:
(
regIOobject&,
const bool masterOnly,
//! The format for parallel send/recv
const IOstreamOption::streamFormat format,
//! forwards to regIOobject
const word& typeName
) const = 0;

View File

@ -586,7 +586,7 @@ Foam::fileOperations::masterUncollatedFileOperation::read
}
else
{
isPtr.reset(new dummyISstream());
return dummyISstream::New();
}
}

View File

@ -411,20 +411,20 @@ protected:
//- Search (locally!) for object; return info on how it was found.
// Does not do any parallel communication.
// checkGlobal : also check undecomposed case
// isFile : true:check for file false:check for directory
// searchType : how was found
// processorsDir : name of processor directory
// instance : instance
virtual fileName filePathInfo
(
//! also check undecomposed case
const bool checkGlobal,
//! True (check for file), False (check for directory)
const bool isFile,
const IOobject& io,
const dirIndexList& pDirs,
const bool search,
//! [out] how was found
pathType& searchType,
//! [out] name of processor directory
word& processorsDir,
//! [out] instance
word& instance
) const;
@ -623,19 +623,20 @@ public:
// (reg)IOobject functinality
//- Search for an object. checkGlobal : also check undecomposed case
//- Search for an object
virtual fileName filePath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const word& typeName,
const word& typeName, //!< currently unused
const bool search
) const;
//- Search for a directory. checkGlobal : also check undecomposed
// case
//- Search for a directory
virtual fileName dirPath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const bool search
@ -655,7 +656,7 @@ public:
(
IOobject&,
const fileName&,
const word& typeName
const word& typeName //!< currently unused
) const;
//- Reads header for regIOobject and returns an ISstream
@ -664,7 +665,7 @@ public:
(
regIOobject&,
const fileName&,
const word& typeName,
const word& typeName, //!< currently unused
const bool readOnProc = true
) const;
@ -673,7 +674,9 @@ public:
(
regIOobject&,
const bool masterOnly,
//! The format for parallel send/recv
const IOstreamOption::streamFormat format,
//! forwards to regIOobject
const word& typeName
) const;

View File

@ -621,7 +621,7 @@ Foam::fileOperations::uncollatedFileOperation::readStream
{
if (!readOnProc)
{
return autoPtr<ISstream>(new dummyISstream());
return dummyISstream::New();
}
if (fName.empty())

View File

@ -243,19 +243,20 @@ public:
// (reg)IOobject functionality
//- Search for an object. checkGlobal : also check undecomposed case
//- Search for an object
virtual fileName filePath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const word& typeName,
const word& typeName, //!< currently unused
const bool search
) const;
//- Search for a directory. checkGlobal : also check undecomposed
// case
//- Search for a directory
virtual fileName dirPath
(
//! also check undecomposed case
const bool checkGlobal,
const IOobject& io,
const bool search
@ -275,16 +276,16 @@ public:
(
IOobject&,
const fileName&,
const word& typeName
const word& typeName //!< currently only for debug info
) const;
//- Reads header for regIOobject and returns an ISstream
// to read the contents.
//- to read the contents.
virtual autoPtr<ISstream> readStream
(
regIOobject&,
const fileName&,
const word& typeName,
const word& typeName, //!< currently unused
const bool readOnProc = true
) const;
@ -293,7 +294,9 @@ public:
(
regIOobject&,
const bool masterOnly,
//! The format for parallel send/recv
const IOstreamOption::streamFormat format,
//! forwards to regIOobject
const word& typeName
) const;

View File

@ -28,8 +28,8 @@ Description
\*---------------------------------------------------------------------------*/
#ifndef cellZoneMesh_H
#define cellZoneMesh_H
#ifndef Foam_cellZoneMesh_H
#define Foam_cellZoneMesh_H
#include "ZoneMesh.H"
#include "cellZone.H"

View File

@ -27,12 +27,12 @@ Typedef
Foam::cellZoneMesh
Description
A ZoneMesh with the type cellZone
A ZoneMesh with cellZone content on a polyMesh
\*---------------------------------------------------------------------------*/
#ifndef cellZoneMeshFwd_H
#define cellZoneMeshFwd_H
#ifndef Foam_cellZoneMeshFwd_H
#define Foam_cellZoneMeshFwd_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -28,8 +28,8 @@ Description
\*---------------------------------------------------------------------------*/
#ifndef faceZoneMesh_H
#define faceZoneMesh_H
#ifndef Foam_faceZoneMesh_H
#define Foam_faceZoneMesh_H
#include "ZoneMesh.H"
#include "faceZone.H"

View File

@ -27,12 +27,12 @@ Typedef
Foam::faceZoneMesh
Description
A ZoneMesh with the type faceZone
A ZoneMesh with faceZone content on a polyMesh
\*---------------------------------------------------------------------------*/
#ifndef faceZoneMeshFwd_H
#define faceZoneMeshFwd_H
#ifndef Foam_faceZoneMeshFwd_H
#define Foam_faceZoneMeshFwd_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -28,8 +28,8 @@ Description
\*---------------------------------------------------------------------------*/
#ifndef pointZoneMesh_H
#define pointZoneMesh_H
#ifndef Foam_pointZoneMesh_H
#define Foam_pointZoneMesh_H
#include "ZoneMesh.H"
#include "pointZone.H"

View File

@ -27,12 +27,12 @@ Typedef
Foam::pointZoneMesh
Description
A ZoneMesh with the type pointZone
A ZoneMesh with pointZone content on a polyMesh
\*---------------------------------------------------------------------------*/
#ifndef pointZoneMeshFwd_H
#define pointZoneMeshFwd_H
#ifndef Foam_pointZoneMeshFwd_H
#define Foam_pointZoneMeshFwd_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -195,7 +195,7 @@ void Foam::fieldToCell::applyToSet
<< "Cannot read field " << fieldName_
<< " from time " << mesh().time().timeName() << endl;
}
else if ("volScalarField" == fieldObject.headerClassName())
else if (fieldObject.isHeaderClass("volScalarField"))
{
// Note: cannot use volScalarField::typeName since that would
// introduce linkage problems (finiteVolume needs meshTools)
@ -209,7 +209,7 @@ void Foam::fieldToCell::applyToSet
applyToSet(action, internalVals, set);
}
else if ("volVectorField" == fieldObject.headerClassName())
else if (fieldObject.isHeaderClass("volVectorField"))
{
// Note: cannot use volVectorField::typeName since that would
// introduce linkage problems (finiteVolume needs meshTools)