mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'modifiable-memory-streams' into 'develop'
Improve handling and sizing behaviour of memory streams See merge request Development/openfoam!755
This commit is contained in:
@ -183,12 +183,25 @@ int main(int argc, char *argv[])
|
||||
printInfo(obuf);
|
||||
|
||||
// Overwrite at some position
|
||||
obuf.stdStream().rdbuf()->pubseekpos(0.60 * obuf.size());
|
||||
obuf << "<" << nl << "OVERWRITE" << nl;
|
||||
if (auto i = obuf.view().find("item5"); i != std::string::npos)
|
||||
{
|
||||
// obuf.seek(0.60 * obuf.size());
|
||||
obuf.seek(i);
|
||||
obuf << "<OVERWRITE>" << nl;
|
||||
}
|
||||
|
||||
Info<<"after overwrite" << nl;
|
||||
printInfo(obuf);
|
||||
|
||||
// Truncate
|
||||
{
|
||||
constexpr float fraction = 0.90;
|
||||
Info<<"truncated at " << (100*fraction) << "% ["
|
||||
<< int(fraction*obuf.size()) << " chars]" << nl;
|
||||
obuf.seek(fraction*obuf.size());
|
||||
printInfo(obuf);
|
||||
}
|
||||
|
||||
Info<< "transfer contents to a List or ICharStream" << nl;
|
||||
|
||||
// Reclaim data storage from OCharStream -> ICharStream
|
||||
|
||||
3
applications/test/OCharStream2/Make/files
Normal file
3
applications/test/OCharStream2/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-OCharStream2.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-OCharStream2
|
||||
2
applications/test/OCharStream2/Make/options
Normal file
2
applications/test/OCharStream2/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
||||
473
applications/test/OCharStream2/Test-OCharStream2.cxx
Normal file
473
applications/test/OCharStream2/Test-OCharStream2.cxx
Normal file
@ -0,0 +1,473 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Description
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "SpanStream.H"
|
||||
#include "wordList.H"
|
||||
#include "IOstreams.H"
|
||||
#include "argList.H"
|
||||
|
||||
#include <charconv>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
Ostream& printString(Ostream& os, const char* first, const char* last)
|
||||
{
|
||||
os << '"';
|
||||
for (; first != last; (void)++first)
|
||||
{
|
||||
os << *first;
|
||||
}
|
||||
os << '"';
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
Ostream& printView(Ostream& os, const char* first, const char* last)
|
||||
{
|
||||
char buf[4];
|
||||
os << label(last-first) << '(';
|
||||
|
||||
for (; first != last; (void)++first)
|
||||
{
|
||||
const char c = *first;
|
||||
|
||||
if (isprint(c))
|
||||
{
|
||||
os << c;
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
os << "\\t";
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
os << "\\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
::snprintf(buf, 4, "%02X", c);
|
||||
os << "\\x" << buf;
|
||||
}
|
||||
}
|
||||
os << ')';
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
Ostream& printView(Ostream& os, std::string_view s)
|
||||
{
|
||||
return printView(os, s.begin(), s.end());
|
||||
}
|
||||
|
||||
|
||||
Ostream& printView(Ostream& os, const UList<char>& list)
|
||||
{
|
||||
return printView(os, list.begin(), list.end());
|
||||
}
|
||||
|
||||
|
||||
Ostream& writeList(Ostream& os, const UList<char>& list)
|
||||
{
|
||||
return printView(os, list);
|
||||
}
|
||||
|
||||
|
||||
Ostream& toString(Ostream& os, const UList<char>& list)
|
||||
{
|
||||
return printString(os, list.begin(), list.end());
|
||||
}
|
||||
|
||||
|
||||
Ostream& toString(Ostream& os, std::string_view s)
|
||||
{
|
||||
return printString(os, s.begin(), s.end());
|
||||
}
|
||||
|
||||
|
||||
template<class BufType>
|
||||
void printInfo(const BufType& buf)
|
||||
{
|
||||
Info<< nl << "=========================" << endl;
|
||||
buf.print(Info);
|
||||
Info<< "addr: " << Foam::name(buf.view().data()) << nl;
|
||||
toString(Info, buf.view());
|
||||
Info<< nl << "=========================" << endl;
|
||||
}
|
||||
|
||||
|
||||
// Return a left-padded integer as "word"
|
||||
template<class IntType>
|
||||
std::string leftpadded(IntType val, char fillch = ' ')
|
||||
{
|
||||
std::string buf;
|
||||
buf.resize((std::numeric_limits<IntType>::digits10+1), fillch);
|
||||
|
||||
auto first = (buf.data());
|
||||
auto last = (buf.data() + buf.size());
|
||||
|
||||
auto result = std::to_chars(first, last, val);
|
||||
|
||||
if (result.ec == std::errc{})
|
||||
{
|
||||
auto* iter = result.ptr;
|
||||
int count = std::distance(iter, last);
|
||||
|
||||
std::cout << "did not fill: " << count << " chars\n";
|
||||
|
||||
// With two spaces before comments
|
||||
if (count > 0) { *iter++ = ' '; --count; }
|
||||
if (count > 0) { *iter++ = ' '; --count; }
|
||||
for (char c = (count >= 2 ? '/' : ' '); count > 0; --count)
|
||||
{
|
||||
*iter++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
template<class IntType>
|
||||
void leftpad(std::ostream& os, IntType val, char fillch = ' ')
|
||||
{
|
||||
// set fill char and width
|
||||
os.setf(std::ios_base::left, std::ios_base::adjustfield);
|
||||
fillch = os.fill(fillch);
|
||||
os.width(std::numeric_limits<IntType>::digits10+1);
|
||||
os << val;
|
||||
// restore fill char
|
||||
os.fill(fillch);
|
||||
}
|
||||
|
||||
|
||||
template<class IntType>
|
||||
void rightpad(std::ostream& os, IntType val, char fillch = ' ')
|
||||
{
|
||||
// set fill char and width
|
||||
os.setf(std::ios_base::right, std::ios_base::adjustfield);
|
||||
fillch = os.fill(fillch);
|
||||
os.width(std::numeric_limits<IntType>::digits10+1);
|
||||
os << val;
|
||||
// restore fill char
|
||||
os.fill(fillch);
|
||||
}
|
||||
|
||||
|
||||
// Left-padded value with trailing comment slashes
|
||||
template<class IntType>
|
||||
void leftpad(ocharstream& os, IntType val)
|
||||
{
|
||||
const auto beg = os.tellp();
|
||||
os << val;
|
||||
int count = (std::numeric_limits<IntType>::digits10+1) - (os.tellp() - beg);
|
||||
|
||||
// With two spaces before comments
|
||||
if (count > 0) { os << ' '; --count; }
|
||||
if (count > 0) { os << ' '; --count; }
|
||||
for (const char c = (count >= 2 ? '/' : ' '); count > 0; --count)
|
||||
{
|
||||
os << c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noBanner();
|
||||
argList::noParallel();
|
||||
argList::addBoolOption("fake-zerosize", "Fake overwriting with zero data");
|
||||
argList::addBoolOption("dict-format", "Format as dictionary entry");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
const bool optFakeZerosize = args.found("fake-zerosize");
|
||||
const bool isDictFormat = args.found("dict-format");
|
||||
|
||||
// const constexpr int width = (std::numeric_limits<label>::digits10+1);
|
||||
|
||||
// experiment with to_chars instead of streaming
|
||||
{
|
||||
// Some value
|
||||
label val(1234);
|
||||
|
||||
auto fixed = leftpadded(val);
|
||||
Info<< "leftpadded " << val << " : " << fixed << nl;
|
||||
}
|
||||
|
||||
ocharstream labelbuf;
|
||||
labelbuf.reserve_exact(32);
|
||||
|
||||
// Some value
|
||||
labelbuf.rewind();
|
||||
rightpad(labelbuf, label(10));
|
||||
|
||||
printInfo(labelbuf);
|
||||
|
||||
OCharStream obuf;
|
||||
obuf.reserve_exact(48);
|
||||
|
||||
printInfo(obuf);
|
||||
|
||||
obuf.push_back('>');
|
||||
obuf.append(" string_view ");
|
||||
obuf.push_back('<');
|
||||
printInfo(obuf);
|
||||
|
||||
obuf.pop_back(8);
|
||||
printInfo(obuf);
|
||||
|
||||
obuf.pop_back(100);
|
||||
printInfo(obuf);
|
||||
|
||||
|
||||
// Fill with some content
|
||||
for (int i = 0; i < 26; ++i)
|
||||
{
|
||||
obuf<< char('A' + i);
|
||||
}
|
||||
|
||||
// Change letter 'O' to '_'
|
||||
if (auto i = obuf.view().find('O'); i != std::string::npos)
|
||||
{
|
||||
obuf.overwrite(i, '_');
|
||||
}
|
||||
|
||||
// append and push_back some content
|
||||
obuf.append(5, '<');
|
||||
obuf.push_back('#');
|
||||
obuf.append(5, '>');
|
||||
|
||||
printInfo(obuf);
|
||||
|
||||
obuf.pop_back(8);
|
||||
printInfo(obuf);
|
||||
|
||||
// Slightly silly test
|
||||
{
|
||||
const auto list = obuf.list();
|
||||
Info<< "list content:" << list << nl;
|
||||
Info<< "view content:" << nl << list.view() << nl;
|
||||
}
|
||||
|
||||
obuf.overwrite(4, labelbuf.view());
|
||||
printInfo(obuf);
|
||||
|
||||
obuf.overwrite(20, "####");
|
||||
printInfo(obuf);
|
||||
|
||||
Info<< "operation Ignored..." << nl;
|
||||
obuf.overwrite(45, "????");
|
||||
printInfo(obuf);
|
||||
|
||||
// Update with new value
|
||||
{
|
||||
labelbuf.rewind();
|
||||
rightpad(labelbuf, label(200), '.');
|
||||
obuf.overwrite(4, labelbuf.view());
|
||||
|
||||
printInfo(obuf);
|
||||
}
|
||||
|
||||
// With yet another value (non-fixed width)
|
||||
{
|
||||
labelbuf.rewind();
|
||||
labelbuf << label(15);
|
||||
obuf.overwrite(4, labelbuf.view());
|
||||
|
||||
printInfo(obuf);
|
||||
}
|
||||
|
||||
// Slightly harder test
|
||||
{
|
||||
std::string chars(26, '?');
|
||||
|
||||
for (int i = 0; i < 26; ++i)
|
||||
{
|
||||
chars[i] = char('A' + i);
|
||||
}
|
||||
|
||||
auto& os = obuf;
|
||||
os.rewind();
|
||||
|
||||
const word procName("processor0");
|
||||
|
||||
// Write as primitiveEntry or commented content
|
||||
// // constexpr bool isDictFormat = true;
|
||||
|
||||
// if constexpr (isDictFormat)
|
||||
if (isDictFormat)
|
||||
{
|
||||
// Like writeKeyword() with compoundToken
|
||||
os << nl << procName << ' ' << word("List<char>") << nl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Human-readable comments
|
||||
os << nl << "// " << procName << nl;
|
||||
}
|
||||
|
||||
// This is the code we want to have, but assume we don't know
|
||||
// the size or data beforehand.
|
||||
//
|
||||
// if (str && len > 0)
|
||||
// {
|
||||
// // Special treatment for char data (binary I/O only)
|
||||
// const auto oldFmt = os.format(IOstreamOption::BINARY);
|
||||
//
|
||||
// os << label(len) << nl;
|
||||
// os.write(str, len);
|
||||
// os << nl;
|
||||
//
|
||||
// os.format(oldFmt);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// os << label(0) << nl;
|
||||
// }
|
||||
|
||||
// Position before writing the label
|
||||
const auto labelBegin = os.tellp();
|
||||
|
||||
// Replace: os << label(len) << nl;
|
||||
// with a fixed-length version
|
||||
{
|
||||
labelbuf.rewind();
|
||||
rightpad(labelbuf, 0);
|
||||
|
||||
os.append(labelbuf.view());
|
||||
os << nl;
|
||||
}
|
||||
|
||||
constexpr bool testUnknown = true;
|
||||
|
||||
label dataCount = 0;
|
||||
|
||||
if constexpr (testUnknown)
|
||||
{
|
||||
// Pretend we don't know the number of characters a priori
|
||||
|
||||
const auto oldFmt = os.format(IOstreamOption::BINARY);
|
||||
|
||||
const auto lineNumber = os.lineNumber();
|
||||
|
||||
// count is unknown but irrelevant for serial
|
||||
os.beginRawWrite(0);
|
||||
|
||||
// Position before raw binary data
|
||||
const auto dataBegin = os.tellp();
|
||||
|
||||
// Some type of output, streaming etc
|
||||
os.writeRaw(chars.data(), chars.size());
|
||||
|
||||
// How many chars of binary data written?
|
||||
dataCount = (os.tellp() - dataBegin);
|
||||
|
||||
os.endRawWrite();
|
||||
os.lineNumber() = lineNumber;
|
||||
os << nl;
|
||||
|
||||
os.format(oldFmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we had all data collected a priori
|
||||
|
||||
dataCount = chars.size();
|
||||
|
||||
const auto oldFmt = os.format(IOstreamOption::BINARY);
|
||||
|
||||
if (dataCount > 0)
|
||||
{
|
||||
os.write(chars.data(), chars.size());
|
||||
os << nl;
|
||||
}
|
||||
os.format(oldFmt);
|
||||
}
|
||||
|
||||
if (optFakeZerosize)
|
||||
{
|
||||
dataCount = 0; // fake zero-size
|
||||
}
|
||||
|
||||
printInfo(os);
|
||||
|
||||
// Update the data count with the correct value
|
||||
|
||||
if (dataCount > 0)
|
||||
{
|
||||
labelbuf.rewind();
|
||||
leftpad(labelbuf, label(dataCount));
|
||||
|
||||
os.overwrite(labelBegin, labelbuf.view());
|
||||
}
|
||||
else
|
||||
{
|
||||
os.seek(int64_t(labelBegin)-1);
|
||||
|
||||
// if constexpr (isDictFormat)
|
||||
if (isDictFormat)
|
||||
{
|
||||
os << ' ' << label(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
os << nl << label(0) << nl;
|
||||
}
|
||||
}
|
||||
|
||||
// if constexpr (isDictFormat)
|
||||
if (isDictFormat)
|
||||
{
|
||||
os.endEntry();
|
||||
}
|
||||
|
||||
printInfo(os);
|
||||
|
||||
Info<< "view: " << os.view(4, 8) << nl;
|
||||
Info<< "view: " << os.view(32) << nl;
|
||||
// Ignores out-of-range
|
||||
Info<< "view: " << os.view(1000) << nl;
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/test/parallel-file-write1/Make/files
Normal file
3
applications/test/parallel-file-write1/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-parallel-file-write1.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-parallel-file-write1
|
||||
2
applications/test/parallel-file-write1/Make/options
Normal file
2
applications/test/parallel-file-write1/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
||||
@ -0,0 +1,260 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 Mark Olesen
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
Test-parallel-file-write1
|
||||
|
||||
Description
|
||||
Simple test of writing with MPI/IO
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "Switch.H"
|
||||
#include "UPstreamFile.H"
|
||||
#include "SpanStream.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
template<class IntType>
|
||||
void zeropadded(std::ostream& os, IntType val, char fillch = '0')
|
||||
{
|
||||
// set fill char and width
|
||||
os.setf(std::ios_base::right, std::ios_base::adjustfield);
|
||||
fillch = os.fill(fillch);
|
||||
os.width(std::numeric_limits<IntType>::digits10+1);
|
||||
os << val;
|
||||
// restore fill char
|
||||
os.fill(fillch);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noCheckProcessorDirectories();
|
||||
argList::addVerboseOption();
|
||||
argList::addBoolOption("master-footer", "Write footer from master");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
if (!UPstream::parRun())
|
||||
{
|
||||
Info<< "###############" << nl
|
||||
<< "Not running in parallel. Stopping now" << nl
|
||||
<< "###############" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const bool optMasterFooter = args.found("master-footer");
|
||||
|
||||
Info<< nl << "Write master-footer: " << Switch::name(optMasterFooter)
|
||||
<< nl << nl;
|
||||
|
||||
Info<< "Create time (without controlDict)\n" << endl;
|
||||
|
||||
auto runTimePtr = Time::New();
|
||||
auto& runTime = runTimePtr();
|
||||
|
||||
const auto myProc = UPstream::myProcNo();
|
||||
const auto nProcs = UPstream::nProcs();
|
||||
|
||||
// Some content
|
||||
OCharStream charset;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
charset<< char('A' + i);
|
||||
}
|
||||
|
||||
// Header/footer buffers - these can be separate or bundled into
|
||||
// the first/last blocks
|
||||
|
||||
OCharStream header;
|
||||
OCharStream footer;
|
||||
|
||||
// Content buffer
|
||||
OCharStream os(IOstream::BINARY);
|
||||
|
||||
{
|
||||
const auto v = charset.view();
|
||||
|
||||
os << nl;
|
||||
os.beginBlock(word("rank" + Foam::name(myProc)));
|
||||
|
||||
for (int repeat = 0; repeat <= myProc; ++repeat)
|
||||
{
|
||||
os << indent << word("entry" + Foam::name(repeat))
|
||||
<< ' ' << word("List<char>");
|
||||
// os << nl;
|
||||
os << ' ';
|
||||
os << label(v.size());
|
||||
os.write(v.data(), v.size());
|
||||
// os << nl;
|
||||
os.endEntry();
|
||||
}
|
||||
|
||||
os.endBlock();
|
||||
}
|
||||
|
||||
// Bundle the footer into the last block
|
||||
if (!optMasterFooter && (myProc == nProcs-1))
|
||||
{
|
||||
IOobject::writeEndDivider(os);
|
||||
}
|
||||
|
||||
|
||||
// All content now exists - commit to disk
|
||||
const std::string_view blockData(os.view());
|
||||
const int64_t blockSize(blockData.size());
|
||||
|
||||
// Collect sizes
|
||||
const List<int64_t> sizes
|
||||
(
|
||||
UPstream::allGatherValues(blockSize, UPstream::worldComm)
|
||||
);
|
||||
|
||||
|
||||
// Format header with size information
|
||||
if (UPstream::master())
|
||||
{
|
||||
header
|
||||
<< "Simple MPI/IO test with " << nProcs << " ranks" << nl << nl;
|
||||
|
||||
ocharstream labelbuf;
|
||||
labelbuf.reserve_exact(32);
|
||||
|
||||
// Position before writing a label
|
||||
auto labelBegin = header.tellp();
|
||||
|
||||
header.beginBlock("meta");
|
||||
{
|
||||
header << indent << word("data.start") << ' ';
|
||||
|
||||
labelBegin = header.tellp();
|
||||
|
||||
// Add the start value (placeholder)
|
||||
{
|
||||
labelbuf.rewind();
|
||||
zeropadded(labelbuf, label(0));
|
||||
header.append(labelbuf.view());
|
||||
}
|
||||
|
||||
header.endEntry();
|
||||
|
||||
header << indent << word("data.sizes") << nl;
|
||||
sizes.writeList(header); // flatOutput
|
||||
header.endEntry();
|
||||
}
|
||||
header.endBlock();
|
||||
|
||||
header << nl;
|
||||
IOobject::writeDivider(header);
|
||||
|
||||
// Now update with the correct size
|
||||
{
|
||||
labelbuf.rewind();
|
||||
zeropadded(labelbuf, label(header.view().size()));
|
||||
header.overwrite(labelBegin, labelbuf.view());
|
||||
}
|
||||
|
||||
// Bundled the footer into the last block or from master?
|
||||
if (optMasterFooter)
|
||||
{
|
||||
IOobject::writeEndDivider(footer);
|
||||
}
|
||||
}
|
||||
|
||||
// With additional header/footer
|
||||
int64_t headerSize(header.view().size());
|
||||
int64_t footerSize(footer.view().size());
|
||||
|
||||
Pstream::broadcast(headerSize);
|
||||
if (optMasterFooter)
|
||||
{
|
||||
Pstream::broadcast(footerSize);
|
||||
}
|
||||
|
||||
|
||||
int64_t totalSize(headerSize);
|
||||
for (int i = 0; i < myProc; ++i)
|
||||
{
|
||||
totalSize += sizes[i];
|
||||
}
|
||||
|
||||
const int64_t blockOffset(totalSize);
|
||||
|
||||
for (int i = myProc; i < nProcs; ++i)
|
||||
{
|
||||
totalSize += sizes[i];
|
||||
}
|
||||
const int64_t footerOffset(totalSize);
|
||||
totalSize += footerSize;
|
||||
|
||||
|
||||
Pout<< "write size=" << label(blockSize)
|
||||
<< " at=" << label(blockOffset) << " total=" << label(totalSize) << nl;
|
||||
|
||||
{
|
||||
UPstream::File file;
|
||||
|
||||
bool ok = file.open_write
|
||||
(
|
||||
UPstream::worldComm,
|
||||
runTime.globalPath()/"mpiio-test1.txt",
|
||||
IOstreamOption::ATOMIC
|
||||
);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
Info<< "writing: " << file.name() << nl;
|
||||
|
||||
if (UPstream::master())
|
||||
{
|
||||
// A no-op for empty buffer
|
||||
ok = file.write_at(0, header.view());
|
||||
}
|
||||
|
||||
ok = file.write_at_all(blockOffset, blockData);
|
||||
|
||||
if (UPstream::master())
|
||||
{
|
||||
// A no-op for empty buffer
|
||||
ok = file.write_at(footerOffset, footer.view());
|
||||
}
|
||||
}
|
||||
|
||||
file.set_size(totalSize);
|
||||
file.close();
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -91,19 +91,14 @@ class DynamicList
|
||||
template<class ListType>
|
||||
inline void doAssignDynList(const ListType& list);
|
||||
|
||||
//- Alter the size of the underlying storage
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doCapacity(const bool nocopy, const label len);
|
||||
//- Alter the size of the underlying storage,
|
||||
//- retaining the first count elements.
|
||||
inline void doCapacity_copy(label count, const label len);
|
||||
|
||||
//- Reserve allocation space for at least this size.
|
||||
//- Reserve allocation space for at least this size,
|
||||
//- retaining the first count elements.
|
||||
// Never shrinks the allocated size, use setCapacity() for that.
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doReserve(const bool nocopy, const label len);
|
||||
|
||||
//- Reserve allocation space for at least this size.
|
||||
// Never shrinks the allocated size, use setCapacity() for that.
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doResize(const bool nocopy, const label len);
|
||||
inline void doReserve_copy(label count, const label len);
|
||||
|
||||
//- Read List from Istream between '(' and ')' delimiters.
|
||||
//- The size is not known a priori.
|
||||
@ -232,6 +227,10 @@ public:
|
||||
//- Alter addressable size and fill \em new entries with constant value
|
||||
inline void resize(const label len, const T& val);
|
||||
|
||||
//- Alter addressable size, retaining the first count contents.
|
||||
// \note Only uses a limited number of internal checks.
|
||||
void resize_copy(label count, const label len);
|
||||
|
||||
//- Alter addressable size and set val for \em all addressed entries
|
||||
inline void resize_fill(const label len, const T& val);
|
||||
|
||||
|
||||
@ -54,9 +54,9 @@ inline void Foam::DynamicList<T, SizeMin>::doAssignDynList
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicList<T, SizeMin>::doCapacity
|
||||
inline void Foam::DynamicList<T, SizeMin>::doCapacity_copy
|
||||
(
|
||||
const bool nocopy,
|
||||
label count,
|
||||
const label newCapacity
|
||||
)
|
||||
{
|
||||
@ -68,16 +68,22 @@ inline void Foam::DynamicList<T, SizeMin>::doCapacity
|
||||
// Addressable length, possibly truncated by new capacity
|
||||
const label currLen = Foam::min(List<T>::size(), newCapacity);
|
||||
|
||||
// The count truncated by the new addressable range
|
||||
if (count > currLen)
|
||||
{
|
||||
count = currLen;
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
if (nocopy)
|
||||
if (count > 0)
|
||||
{
|
||||
List<T>::resize_nocopy(newCapacity);
|
||||
List<T>::resize_copy(count, newCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<T>::resize_copy(currLen, newCapacity);
|
||||
List<T>::resize_nocopy(newCapacity);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -86,9 +92,9 @@ inline void Foam::DynamicList<T, SizeMin>::doCapacity
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicList<T, SizeMin>::doReserve
|
||||
inline void Foam::DynamicList<T, SizeMin>::doReserve_copy
|
||||
(
|
||||
const bool nocopy,
|
||||
label count,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
@ -97,20 +103,27 @@ inline void Foam::DynamicList<T, SizeMin>::doReserve
|
||||
// Preserve addressed size
|
||||
const label currLen = List<T>::size();
|
||||
|
||||
// The count truncated by the addressable range
|
||||
if (count > currLen)
|
||||
{
|
||||
count = currLen;
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
// Increase capacity (eg, doubling)
|
||||
// - this may need better handling for when lists become very large
|
||||
capacity_ =
|
||||
Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
|
||||
|
||||
if (nocopy)
|
||||
if (count > 0)
|
||||
{
|
||||
List<T>::resize_nocopy(capacity_);
|
||||
List<T>::resize_copy(count, capacity_);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<T>::resize_copy(currLen, capacity_);
|
||||
List<T>::resize_nocopy(capacity_);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -119,18 +132,6 @@ inline void Foam::DynamicList<T, SizeMin>::doReserve
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicList<T, SizeMin>::doResize
|
||||
(
|
||||
const bool nocopy,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(nocopy, len);
|
||||
List<T>::setAddressableSize(len);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, int SizeMin>
|
||||
@ -323,7 +324,8 @@ inline void Foam::DynamicList<T, SizeMin>::setCapacity
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doCapacity(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
doCapacity_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
@ -333,7 +335,8 @@ inline void Foam::DynamicList<T, SizeMin>::setCapacity_nocopy
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doCapacity(true, len); // nocopy = true
|
||||
// Preserve 0 content
|
||||
doCapacity_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
@ -343,7 +346,8 @@ inline void Foam::DynamicList<T, SizeMin>::reserve
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
doReserve_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
@ -353,7 +357,8 @@ inline void Foam::DynamicList<T, SizeMin>::reserve_nocopy
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(true, len); // nocopy = true
|
||||
// Preserve 0 content
|
||||
doReserve_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
@ -371,9 +376,12 @@ inline void Foam::DynamicList<T, SizeMin>::reserve_exact
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
// Exact length
|
||||
capacity_ = len;
|
||||
|
||||
// if (!nocopy)
|
||||
{
|
||||
List<T>::resize_copy(currLen, len);
|
||||
List<T>::resize_copy(currLen, capacity_);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -388,7 +396,21 @@ inline void Foam::DynamicList<T, SizeMin>::resize
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doResize(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
resize_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicList<T, SizeMin>::resize_copy
|
||||
(
|
||||
label count,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
// Preserve count elements
|
||||
doReserve_copy(count, len);
|
||||
List<T>::setAddressableSize(len);
|
||||
}
|
||||
|
||||
|
||||
@ -399,7 +421,7 @@ inline void Foam::DynamicList<T, SizeMin>::resize_fill
|
||||
const T& val
|
||||
)
|
||||
{
|
||||
this->doResize(true, len); // nocopy = true
|
||||
resize_nocopy(len);
|
||||
UList<T>::operator=(val);
|
||||
}
|
||||
|
||||
@ -410,7 +432,8 @@ inline void Foam::DynamicList<T, SizeMin>::resize_nocopy
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doResize(true, len); // nocopy = true
|
||||
// Preserve 0 content
|
||||
resize_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
@ -422,6 +445,8 @@ inline void Foam::DynamicList<T, SizeMin>::resize
|
||||
)
|
||||
{
|
||||
const label oldLen = List<T>::size();
|
||||
|
||||
// Preserve all content
|
||||
resize(len);
|
||||
|
||||
// Fill newly exposed with constant value
|
||||
@ -445,6 +470,9 @@ inline void Foam::DynamicList<T, SizeMin>::clear() noexcept
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicList<T, SizeMin>::clearStorage()
|
||||
{
|
||||
// Extra safety...?
|
||||
if (!List<T>::cdata() && List<T>::empty()) capacity_ = 0;
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
List<T>::clear();
|
||||
@ -515,7 +543,7 @@ inline void Foam::DynamicList<T, SizeMin>::swap
|
||||
UList<T>::swap(other);
|
||||
|
||||
// Swap capacity
|
||||
std::swap(this->capacity_, other.capacity_);
|
||||
std::swap(capacity_, other.capacity_);
|
||||
}
|
||||
|
||||
|
||||
@ -537,7 +565,7 @@ template<int AnySizeMin>
|
||||
inline void
|
||||
Foam::DynamicList<T, SizeMin>::transfer
|
||||
(
|
||||
DynamicList<T, AnySizeMin>& list
|
||||
DynamicList<T, AnySizeMin>& other
|
||||
)
|
||||
{
|
||||
if
|
||||
@ -545,7 +573,7 @@ Foam::DynamicList<T, SizeMin>::transfer
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const List<T>*>(this)
|
||||
== static_cast<const List<T>*>(&list)
|
||||
== static_cast<const List<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
@ -554,10 +582,11 @@ Foam::DynamicList<T, SizeMin>::transfer
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
List<T>::transfer(static_cast<List<T>&>(list));
|
||||
List<T>::transfer(static_cast<List<T>&>(other));
|
||||
|
||||
capacity_ = list.capacity();
|
||||
list.setCapacity_unsafe(0); // All contents moved
|
||||
// Update capacity information
|
||||
capacity_ = other.capacity();
|
||||
other.setCapacity_unsafe(0); // All contents moved
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -28,27 +28,38 @@ License
|
||||
|
||||
#include "List.H"
|
||||
#include "FixedList.H"
|
||||
#include "PtrList.H"
|
||||
#include "UPtrList.H"
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
// Only a limited number of internal size checks.
|
||||
// Caller knows what they are doing.
|
||||
template<class T>
|
||||
void Foam::List<T>::resize_copy(const label count, const label len)
|
||||
void Foam::List<T>::resize_copy(label count, const label len)
|
||||
{
|
||||
// Only a limited number of internal size checks.
|
||||
// Caller knows what they are doing.
|
||||
|
||||
if (FOAM_LIKELY(len > 0))
|
||||
if (this->size_ == len)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
else if (FOAM_LIKELY(len > 0))
|
||||
{
|
||||
// With sign-check to avoid spurious -Walloc-size-larger-than
|
||||
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_;
|
||||
const label oldLen = this->size_;
|
||||
|
||||
if (overlap > 0)
|
||||
if (count > len)
|
||||
{
|
||||
count = len; // The count truncated by the new length
|
||||
}
|
||||
|
||||
// Extra safety, probably not necessary:
|
||||
// if (count > oldLen)
|
||||
// {
|
||||
// count = oldLen; // The count truncated by the old length
|
||||
// }
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
// Recover overlapping content when resizing
|
||||
|
||||
@ -58,7 +69,7 @@ void Foam::List<T>::resize_copy(const label count, const label len)
|
||||
// Can dispatch with
|
||||
// - std::execution::par_unseq
|
||||
// - std::execution::unseq
|
||||
std::move(old, (old + overlap), this->v_);
|
||||
std::move(old, (old + count), this->v_);
|
||||
|
||||
ListPolicy::deallocate(old, oldLen);
|
||||
}
|
||||
@ -91,8 +102,6 @@ void Foam::List<T>::resize_copy(const label count, const label len)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const label len)
|
||||
:
|
||||
UList<T>(nullptr, len)
|
||||
{
|
||||
if (FOAM_UNLIKELY(len < 0))
|
||||
{
|
||||
@ -103,15 +112,14 @@ Foam::List<T>::List(const label len)
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
doAlloc();
|
||||
// resize_nocopy()
|
||||
doAlloc(len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const label len, const T& val)
|
||||
:
|
||||
UList<T>(nullptr, len)
|
||||
{
|
||||
if (FOAM_UNLIKELY(len < 0))
|
||||
{
|
||||
@ -122,7 +130,8 @@ Foam::List<T>::List(const label len, const T& val)
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
doAlloc();
|
||||
// resize_fill()
|
||||
doAlloc(len);
|
||||
UList<T>::operator=(val);
|
||||
}
|
||||
}
|
||||
@ -130,8 +139,6 @@ Foam::List<T>::List(const label len, const T& val)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const label len, Foam::zero)
|
||||
:
|
||||
UList<T>(nullptr, len)
|
||||
{
|
||||
if (FOAM_UNLIKELY(len < 0))
|
||||
{
|
||||
@ -142,7 +149,8 @@ Foam::List<T>::List(const label len, Foam::zero)
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
doAlloc();
|
||||
// resize_fill()
|
||||
doAlloc(len);
|
||||
UList<T>::operator=(Foam::zero{});
|
||||
}
|
||||
}
|
||||
@ -177,12 +185,10 @@ Foam::List<T>::List(Foam::one, Foam::zero)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const UList<T>& list)
|
||||
:
|
||||
UList<T>(nullptr, list.size_)
|
||||
{
|
||||
if (this->size_ > 0)
|
||||
if (!list.empty())
|
||||
{
|
||||
doAlloc();
|
||||
doAlloc(list.size());
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
}
|
||||
@ -190,12 +196,10 @@ Foam::List<T>::List(const UList<T>& list)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const List<T>& list)
|
||||
:
|
||||
UList<T>(nullptr, list.size_)
|
||||
{
|
||||
if (this->size_ > 0)
|
||||
if (!list.empty())
|
||||
{
|
||||
doAlloc();
|
||||
doAlloc(list.size());
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
}
|
||||
@ -203,19 +207,18 @@ Foam::List<T>::List(const List<T>& list)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(List<T>& list, bool reuse)
|
||||
:
|
||||
UList<T>(nullptr, list.size_)
|
||||
{
|
||||
if (reuse)
|
||||
{
|
||||
// Steal content
|
||||
this->v_ = list.v_;
|
||||
this->size_ = list.size_;
|
||||
list.v_ = nullptr;
|
||||
list.size_ = 0;
|
||||
}
|
||||
else if (this->size_ > 0)
|
||||
else if (!list.empty())
|
||||
{
|
||||
doAlloc();
|
||||
doAlloc(list.size());
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
}
|
||||
@ -223,11 +226,12 @@ Foam::List<T>::List(List<T>& list, bool reuse)
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const UList<T>& list, const labelUList& indices)
|
||||
:
|
||||
UList<T>(nullptr, indices.size())
|
||||
{
|
||||
doAlloc();
|
||||
if (!indices.empty())
|
||||
{
|
||||
doAlloc(indices.size());
|
||||
copyList(list, indices); // <- deepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -238,11 +242,12 @@ Foam::List<T>::List
|
||||
const UList<T>& list,
|
||||
const FixedList<label,N>& indices
|
||||
)
|
||||
:
|
||||
UList<T>(nullptr, indices.size())
|
||||
{
|
||||
doAlloc();
|
||||
// if (!FixedList::empty()) is always true
|
||||
{
|
||||
doAlloc(indices.size());
|
||||
copyList(list, indices); // <- deepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -255,24 +260,23 @@ Foam::List<T>::List(const FixedList<T, N>& list)
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(const PtrList<T>& list)
|
||||
:
|
||||
UList<T>(nullptr, list.size())
|
||||
Foam::List<T>::List(const UPtrList<T>& list)
|
||||
{
|
||||
doAlloc();
|
||||
if (!list.empty())
|
||||
{
|
||||
doAlloc(list.size());
|
||||
copyList(list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
template<class Addr>
|
||||
Foam::List<T>::List(const IndirectListBase<T, Addr>& list)
|
||||
:
|
||||
UList<T>(nullptr, list.size())
|
||||
{
|
||||
if (this->size_ > 0)
|
||||
if (!list.empty())
|
||||
{
|
||||
doAlloc();
|
||||
doAlloc(list.size());
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
}
|
||||
@ -285,21 +289,9 @@ Foam::List<T>::List(std::initializer_list<T> list)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
Foam::List<T>::List(List<T>&& list) noexcept
|
||||
:
|
||||
UList<T>(list.data(), list.size())
|
||||
{
|
||||
list.size_ = 0;
|
||||
list.v_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
template<int SizeMin>
|
||||
Foam::List<T>::List(DynamicList<T, SizeMin>&& list)
|
||||
:
|
||||
UList<T>()
|
||||
{
|
||||
transfer(list);
|
||||
}
|
||||
@ -327,7 +319,7 @@ void Foam::List<T>::resize(const label len, const T& val)
|
||||
return;
|
||||
}
|
||||
|
||||
this->resize_copy(oldLen, len);
|
||||
resize_copy(oldLen, len);
|
||||
|
||||
// Fill trailing part with new values
|
||||
if (oldLen < this->size_)
|
||||
@ -368,7 +360,7 @@ void Foam::List<T>::transfer(DynamicList<T, SizeMin>& list)
|
||||
// Shrink the allocated space to the number of elements used
|
||||
list.shrink_to_fit();
|
||||
transfer(static_cast<List<T>&>(list));
|
||||
list.clearStorage(); // Deletion, capacity=0 etc.
|
||||
list.setCapacity_unsafe(0); // All contents moved
|
||||
}
|
||||
|
||||
|
||||
@ -382,9 +374,9 @@ void Foam::List<T>::operator=(const UList<T>& list)
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
reAlloc(list.size_);
|
||||
resize_nocopy(list.size());
|
||||
|
||||
if (this->size_ > 0)
|
||||
if (!list.empty())
|
||||
{
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
@ -399,9 +391,9 @@ void Foam::List<T>::operator=(const List<T>& list)
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
reAlloc(list.size_);
|
||||
resize_nocopy(list.size());
|
||||
|
||||
if (this->size_ > 0)
|
||||
if (!list.empty())
|
||||
{
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
@ -412,7 +404,7 @@ template<class T>
|
||||
template<unsigned N>
|
||||
void Foam::List<T>::operator=(const FixedList<T, N>& list)
|
||||
{
|
||||
reAlloc(list.size());
|
||||
resize_nocopy(list.size());
|
||||
|
||||
std::copy(list.begin(), list.end(), this->v_);
|
||||
}
|
||||
@ -422,7 +414,7 @@ template<class T>
|
||||
template<class Addr>
|
||||
void Foam::List<T>::operator=(const IndirectListBase<T, Addr>& list)
|
||||
{
|
||||
reAlloc(list.size());
|
||||
resize_nocopy(list.size());
|
||||
UList<T>::deepCopy(list);
|
||||
}
|
||||
|
||||
@ -430,8 +422,7 @@ void Foam::List<T>::operator=(const IndirectListBase<T, Addr>& list)
|
||||
template<class T>
|
||||
void Foam::List<T>::operator=(std::initializer_list<T> list)
|
||||
{
|
||||
reAlloc(list.size());
|
||||
|
||||
resize_nocopy(list.size());
|
||||
std::copy(list.begin(), list.end(), this->v_);
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ template<class T> class List;
|
||||
template<class T, unsigned N> class FixedList;
|
||||
template<class T, int SizeMin> class DynamicList;
|
||||
|
||||
template<class T> class PtrList;
|
||||
template<class T> class UPtrList;
|
||||
|
||||
template<class T> Istream& operator>>(Istream& is, List<T>& list);
|
||||
|
||||
@ -77,12 +77,8 @@ class List
|
||||
{
|
||||
// Private Member Functions
|
||||
|
||||
//- Allocate list storage
|
||||
inline void doAlloc();
|
||||
|
||||
//- Reallocate list storage to the given size
|
||||
// Discards old storage (if any). Does not copy old contents
|
||||
inline void reAlloc(const label len);
|
||||
//- Allocate list storage. Assumes there is no existing content
|
||||
inline void doAlloc(const label len);
|
||||
|
||||
//- Copy all list contents. Uses operator[] on the input list
|
||||
template<class ListType>
|
||||
@ -98,8 +94,8 @@ class List
|
||||
template<class InputIterator>
|
||||
inline List
|
||||
(
|
||||
InputIterator firstIter,
|
||||
InputIterator lastIter, // (unused)
|
||||
InputIterator input,
|
||||
InputIterator inputEnd, // (unused)
|
||||
const label len
|
||||
);
|
||||
|
||||
@ -111,17 +107,7 @@ class List
|
||||
// Methods as per DynamicList to simplify code maintenance
|
||||
|
||||
//- Stub method for internal naming as per DynamicList
|
||||
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);
|
||||
void setCapacity_nocopy(label len) { resize_nocopy(len); }
|
||||
|
||||
|
||||
public:
|
||||
@ -185,8 +171,8 @@ public:
|
||||
template<unsigned N>
|
||||
explicit List(const FixedList<T, N>& list);
|
||||
|
||||
//- Construct as copy of PtrList<T>
|
||||
explicit List(const PtrList<T>& list);
|
||||
//- Construct as copy of UPtrList<T> content
|
||||
explicit List(const UPtrList<T>& list);
|
||||
|
||||
//- Construct as copy of IndirectList contents
|
||||
template<class Addr>
|
||||
@ -196,7 +182,7 @@ public:
|
||||
List(std::initializer_list<T> list);
|
||||
|
||||
//- Move construct from List
|
||||
List(List<T>&& list) noexcept;
|
||||
inline List(List<T>&& list) noexcept;
|
||||
|
||||
//- Move construct from DynamicList
|
||||
template<int SizeMin>
|
||||
@ -227,6 +213,10 @@ public:
|
||||
//- Adjust allocated size of list and set val for \em new elements
|
||||
void resize(const label len, const T& val);
|
||||
|
||||
//- Change allocated size of list, retaining the first count elements.
|
||||
// \note Only uses a limited number of internal checks.
|
||||
void resize_copy(label count, const label len);
|
||||
|
||||
//- Adjust allocated size of list and set val for \em all elements
|
||||
inline void resize_fill(const label len, const T& val);
|
||||
|
||||
@ -234,14 +224,9 @@ public:
|
||||
// retaining old content.
|
||||
// If no reallocation is required, the contents remain untouched.
|
||||
// Otherwise the contents will be uninitialized.
|
||||
// Shorthand for \c resize(0, len)
|
||||
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); }
|
||||
|
||||
|
||||
// Edit
|
||||
|
||||
@ -404,6 +389,12 @@ public:
|
||||
//- Same as push_uniq()
|
||||
FOAM_DEPRECATED_FOR(2022-10, "push_uniq()")
|
||||
label appendUniq(const T& val) { return this->push_uniq(val); }
|
||||
|
||||
//- Alias for resize()
|
||||
void setSize(label n) { this->resize(n); }
|
||||
|
||||
//- Alias for resize()
|
||||
void setSize(label n, const T& val) { this->resize(n, val); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -29,24 +29,13 @@ License
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
inline void Foam::List<T>::doAlloc()
|
||||
inline void Foam::List<T>::doAlloc(const label len)
|
||||
{
|
||||
if (this->size_ > 0)
|
||||
if (len > 0)
|
||||
{
|
||||
// With sign-check to avoid spurious -Walloc-size-larger-than
|
||||
this->v_ = ListPolicy::allocate<T>(this->size_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Foam::List<T>::reAlloc(const label len)
|
||||
{
|
||||
if (this->size_ != len)
|
||||
{
|
||||
clear();
|
||||
this->v_ = ListPolicy::allocate<T>(len);
|
||||
this->size_ = len;
|
||||
doAlloc();
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,23 +84,24 @@ template<class T>
|
||||
template<class InputIterator>
|
||||
inline Foam::List<T>::List
|
||||
(
|
||||
InputIterator firstIter,
|
||||
InputIterator lastIter, // (unused)
|
||||
InputIterator input,
|
||||
InputIterator inputEnd, // (unused)
|
||||
const label len
|
||||
)
|
||||
:
|
||||
UList<T>(nullptr, len)
|
||||
{
|
||||
if (len > 0)
|
||||
{
|
||||
doAlloc();
|
||||
doAlloc(len);
|
||||
|
||||
// Like std::copy() or std::copy_n()
|
||||
// but without any requirements on the iterator category
|
||||
|
||||
for (label i = 0; i < len; (void)++i, (void)++firstIter)
|
||||
auto iter = this->v_;
|
||||
const auto endIter = (iter + len);
|
||||
|
||||
for (; iter != endIter; (void)++iter, (void)++input)
|
||||
{
|
||||
this->v_[i] = *firstIter;
|
||||
*iter = *input;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,6 +114,17 @@ inline constexpr Foam::List<T>::List() noexcept
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::List<T>::List(List<T>&& list) noexcept
|
||||
:
|
||||
UList<T>(list.data(), list.size())
|
||||
{
|
||||
// Stole content
|
||||
list.size_ = 0;
|
||||
list.v_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::autoPtr<Foam::List<T>> Foam::List<T>::clone() const
|
||||
{
|
||||
@ -158,7 +159,7 @@ inline void Foam::List<T>::resize(const label len)
|
||||
{
|
||||
if (this->size_ != len)
|
||||
{
|
||||
this->resize_copy(this->size_, len);
|
||||
resize_copy(this->size_, len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +167,7 @@ inline void Foam::List<T>::resize(const label len)
|
||||
template<class T>
|
||||
inline void Foam::List<T>::resize_fill(const label len, const T& val)
|
||||
{
|
||||
this->reAlloc(len);
|
||||
resize_nocopy(len);
|
||||
UList<T>::operator=(val);
|
||||
}
|
||||
|
||||
@ -174,7 +175,12 @@ inline void Foam::List<T>::resize_fill(const label len, const T& val)
|
||||
template<class T>
|
||||
inline void Foam::List<T>::resize_nocopy(const label len)
|
||||
{
|
||||
this->reAlloc(len);
|
||||
// Same as resize_copy(0, len);
|
||||
if (this->size_ != len)
|
||||
{
|
||||
clear();
|
||||
doAlloc(len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -628,6 +628,15 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
//- Return a string_view of the charList. Content is non-modifiable.
|
||||
template<class TypeT = T>
|
||||
std::enable_if_t
|
||||
<std::is_same_v<char, std::remove_cv_t<TypeT>>, std::string_view>
|
||||
inline view() const
|
||||
{
|
||||
return std::string_view(v_, size_);
|
||||
}
|
||||
|
||||
|
||||
// Hashing
|
||||
|
||||
|
||||
@ -275,9 +275,11 @@ const std::istream& Foam::IFstream::stdStream() const
|
||||
|
||||
void Foam::IFstream::rewind()
|
||||
{
|
||||
Istream::rewind(); // Drop any putback
|
||||
lineNumber_ = 1; // Reset line number
|
||||
|
||||
if (IOstreamOption::COMPRESSED == ifstreamPointer::whichCompression())
|
||||
{
|
||||
lineNumber_ = 1; // Reset line number
|
||||
ifstreamPointer::reopen_gz(this->name());
|
||||
setState(ifstreamPointer::get()->rdstate());
|
||||
}
|
||||
|
||||
@ -218,6 +218,12 @@ char Foam::Istream::readEndList(const char* funcName)
|
||||
}
|
||||
|
||||
|
||||
void Foam::Istream::rewind()
|
||||
{
|
||||
putBackClear(); // Drop any putback
|
||||
}
|
||||
|
||||
|
||||
Foam::Istream& Foam::Istream::operator()() const
|
||||
{
|
||||
if (!good())
|
||||
|
||||
@ -175,7 +175,8 @@ public:
|
||||
//- operation.
|
||||
virtual Istream& readRaw(char* data, std::streamsize count) = 0;
|
||||
|
||||
//- Rewind the stream so that it may be read again
|
||||
//- Rewind the stream so that it may be read again.
|
||||
// The base implementation clears any putback.
|
||||
virtual void rewind() = 0;
|
||||
|
||||
|
||||
|
||||
@ -563,6 +563,8 @@ Foam::label Foam::UIPstreamBase::remaining() const noexcept
|
||||
|
||||
void Foam::UIPstreamBase::rewind()
|
||||
{
|
||||
Istream::rewind(); // Drop any putback
|
||||
|
||||
recvBufPos_ = 0; // Assume the entire buffer is for us to read from
|
||||
setOpened();
|
||||
setGood();
|
||||
|
||||
267
src/OpenFOAM/db/IOstreams/Pstreams/UPstreamFile.H
Normal file
267
src/OpenFOAM/db/IOstreams/Pstreams/UPstreamFile.H
Normal file
@ -0,0 +1,267 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 Mark Olesen
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::UPstream::File
|
||||
|
||||
Description
|
||||
An opaque wrapper for MPI_File methods
|
||||
without any \c <mpi.h> header dependency.
|
||||
|
||||
Note
|
||||
Not included as part of UPstream.H - only include locally as required
|
||||
|
||||
SourceFiles
|
||||
UPstreamFile.txx
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef Foam_UPstreamFile_H
|
||||
#define Foam_UPstreamFile_H
|
||||
|
||||
#include "fileName.H"
|
||||
#include "UPstream.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class UPstream::File Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class UPstream::File
|
||||
{
|
||||
// Forward Declaration
|
||||
class Impl;
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Implementation wrapper of MPI_File etc
|
||||
std::unique_ptr<Impl> file_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Method Functions
|
||||
|
||||
//- MPI_File_write [non-collective] : write data
|
||||
bool write_data
|
||||
(
|
||||
//! Source buffer
|
||||
const void* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
);
|
||||
|
||||
//- MPI_File_write_at [non-collective] : write data at specified offset
|
||||
bool write_data_at
|
||||
(
|
||||
//! The offset - number of 'view' elements (default: byte)
|
||||
std::streamsize offset,
|
||||
//! Source buffer
|
||||
const void* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
);
|
||||
|
||||
//- MPI_File_write_all [collective] : write data
|
||||
bool write_data_all
|
||||
(
|
||||
//! Source buffer
|
||||
const void* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
);
|
||||
|
||||
//- MPI_File_write_at_all [collective] :
|
||||
//- write data at specified offset
|
||||
bool write_data_at_all
|
||||
(
|
||||
//! The offset - number of 'view' elements (default: byte)
|
||||
std::streamsize offset,
|
||||
//! Source buffer
|
||||
const void* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
File(const File&&) = delete;
|
||||
|
||||
//- Move construct
|
||||
File(File&&) noexcept;
|
||||
|
||||
//- No copy assignment
|
||||
File& operator=(const File&) = delete;
|
||||
|
||||
//- Move assignment
|
||||
File& operator=(File&&) noexcept;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Default construct
|
||||
File();
|
||||
|
||||
//- Destructor. Non-default in header (incomplete types)
|
||||
~File();
|
||||
|
||||
|
||||
// Static Member Functions
|
||||
|
||||
//- True if MPI/IO appears to be supported
|
||||
static bool supported();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Access
|
||||
|
||||
//- The name of the open stream
|
||||
const fileName& name() const;
|
||||
|
||||
//- True if allocated and open has been called
|
||||
bool is_open() const;
|
||||
|
||||
|
||||
// Basics
|
||||
|
||||
//- MPI_File_open [collective] :
|
||||
//- open file in write-only mode, no-append
|
||||
bool open_write
|
||||
(
|
||||
//! The OpenFOAM communicator index
|
||||
const int communicator,
|
||||
//! Full file path (parent directory must exist before calling)
|
||||
const fileName& pathname,
|
||||
//! Simulated atomic file handling
|
||||
IOstreamOption::atomicType = IOstreamOption::NON_ATOMIC
|
||||
);
|
||||
|
||||
//- MPI_File_close [collective]
|
||||
bool close();
|
||||
|
||||
//- Set the (output) file size [collective]
|
||||
bool set_size(std::streamsize num_bytes);
|
||||
|
||||
|
||||
// Writing
|
||||
|
||||
//- MPI_File_write [non-collective] : write data.
|
||||
// A no-op and return true if content is empty
|
||||
inline bool write(std::string_view sv);
|
||||
|
||||
//- MPI_File_write [non-collective] : write data.
|
||||
// A no-op and return true if buffer is nullptr or count is zero
|
||||
template<class Type>
|
||||
inline bool write
|
||||
(
|
||||
//! The content
|
||||
const Type* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count
|
||||
);
|
||||
|
||||
//- MPI_File_write_at [non-collective] : write data at specified offset.
|
||||
// A no-op and return true if content is empty
|
||||
inline bool write_at(std::streamsize offset, std::string_view sv);
|
||||
|
||||
//- MPI_File_write_at [non-collective] : write data at specified offset.
|
||||
// A no-op and return true if buffer is nullptr or count is zero
|
||||
template<class Type>
|
||||
inline bool write_at
|
||||
(
|
||||
//! The offset within the file - number of 'view' elements
|
||||
std::streamsize offset,
|
||||
//! The content
|
||||
const Type* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count
|
||||
);
|
||||
|
||||
//- MPI_File_write_all [collective] : write data
|
||||
inline bool write_all(std::string_view sv);
|
||||
|
||||
//- MPI_File_write_all [collective] : write data
|
||||
template<class Type>
|
||||
inline bool write_all
|
||||
(
|
||||
//! The content
|
||||
const Type* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count
|
||||
);
|
||||
|
||||
//- MPI_File_write_at_all [collective] :
|
||||
//- write data at specified offset
|
||||
inline bool write_at_all
|
||||
(
|
||||
//! The offset within the file - number of 'view' elements
|
||||
std::streamsize offset,
|
||||
//! The content
|
||||
std::string_view sv
|
||||
);
|
||||
|
||||
//- MPI_File_write_at_all [collective] :
|
||||
//- write data at specified offset
|
||||
template<class Type>
|
||||
inline bool write_at_all
|
||||
(
|
||||
//! The offset within the file - number of 'view' elements
|
||||
std::streamsize offset,
|
||||
//! The content
|
||||
const Type* buffer,
|
||||
//! The data count - number of elements
|
||||
std::streamsize count
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "UPstreamFile.txx"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
220
src/OpenFOAM/db/IOstreams/Pstreams/UPstreamFile.txx
Normal file
220
src/OpenFOAM/db/IOstreams/Pstreams/UPstreamFile.txx
Normal file
@ -0,0 +1,220 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 Mark Olesen
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
inline bool Foam::UPstream::File::write
|
||||
(
|
||||
std::string_view sv
|
||||
)
|
||||
{
|
||||
if (sv.empty())
|
||||
{
|
||||
// no-op for no content
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->write_data
|
||||
(
|
||||
sv.data(), sv.size(),
|
||||
UPstream::dataTypes::type_byte
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::UPstream::File::write
|
||||
(
|
||||
const Type* buffer,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
if constexpr (!is_contiguous_v<Type>)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Only contiguous data can be supported!"
|
||||
<< Foam::abort(FatalError);
|
||||
return false;
|
||||
}
|
||||
else if (buffer && count > 1)
|
||||
{
|
||||
// Use element or component type (or byte-wise) for data type
|
||||
return this->write_data
|
||||
(
|
||||
buffer, // The data or cmpt pointer
|
||||
UPstream_dataType<Type>::size(count),
|
||||
UPstream_dataType<Type>::datatype_id
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no-op for no content
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::UPstream::File::write_at
|
||||
(
|
||||
std::streamsize offset,
|
||||
std::string_view sv
|
||||
)
|
||||
{
|
||||
if (sv.empty())
|
||||
{
|
||||
// no-op for no content
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->write_data_at
|
||||
(
|
||||
offset,
|
||||
sv.data(), sv.size(),
|
||||
UPstream::dataTypes::type_byte
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::UPstream::File::write_at
|
||||
(
|
||||
std::streamsize offset,
|
||||
const Type* buffer,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
if constexpr (!is_contiguous_v<Type>)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Only contiguous data can be supported!"
|
||||
<< Foam::abort(FatalError);
|
||||
return false;
|
||||
}
|
||||
else if (buffer && count > 1)
|
||||
{
|
||||
// Use element or component type (or byte-wise) for data type
|
||||
return this->write_data_at
|
||||
(
|
||||
offset,
|
||||
buffer, // The data or cmpt pointer
|
||||
UPstream_dataType<Type>::size(count),
|
||||
UPstream_dataType<Type>::datatype_id
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no-op for no content
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::UPstream::File::write_all
|
||||
(
|
||||
std::string_view sv
|
||||
)
|
||||
{
|
||||
return this->write_data_all
|
||||
(
|
||||
sv.data(), sv.size(),
|
||||
UPstream::dataTypes::type_byte
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::UPstream::File::write_all
|
||||
(
|
||||
const Type* buffer,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
if constexpr (!is_contiguous_v<Type>)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Only contiguous data can be supported!"
|
||||
<< Foam::abort(FatalError);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use element or component type (or byte-wise) for data type
|
||||
return this->write_data_all
|
||||
(
|
||||
buffer, // The data or cmpt pointer
|
||||
UPstream_dataType<Type>::size(count),
|
||||
UPstream_dataType<Type>::datatype_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::UPstream::File::write_at_all
|
||||
(
|
||||
std::streamsize offset,
|
||||
std::string_view sv
|
||||
)
|
||||
{
|
||||
return this->write_data_at_all
|
||||
(
|
||||
offset,
|
||||
sv.data(), sv.size(),
|
||||
UPstream::dataTypes::type_byte
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::UPstream::File::write_at_all
|
||||
(
|
||||
std::streamsize offset,
|
||||
const Type* buffer,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
if constexpr (!is_contiguous_v<Type>)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Only contiguous data can be supported!"
|
||||
<< Foam::abort(FatalError);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use element or component type (or byte-wise) for data type
|
||||
return this->write_data_at_all
|
||||
(
|
||||
offset,
|
||||
buffer, // The data or cmpt pointer
|
||||
UPstream_dataType<Type>::size(count),
|
||||
UPstream_dataType<Type>::datatype_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -1084,6 +1084,7 @@ bool Foam::ISstream::endRawRead()
|
||||
|
||||
void Foam::ISstream::rewind()
|
||||
{
|
||||
Istream::rewind(); // Drop any putback
|
||||
lineNumber_ = 1; // Reset line number
|
||||
|
||||
stdStream().clear(); // Clear the iostate error state flags
|
||||
|
||||
@ -531,7 +531,11 @@ public:
|
||||
virtual bool endRawRead() override { return false; }
|
||||
|
||||
//- Rewind the stream so that it may be read again. Same as seek(0)
|
||||
virtual void rewind() override { ITstream::seek(0); }
|
||||
virtual void rewind() override
|
||||
{
|
||||
Istream::rewind();
|
||||
ITstream::seek(0);
|
||||
}
|
||||
|
||||
|
||||
// Output
|
||||
|
||||
@ -357,6 +357,7 @@ public:
|
||||
//- Rewind the stream, clearing any old errors
|
||||
virtual void rewind() override
|
||||
{
|
||||
Istream::rewind();
|
||||
stream_.rewind();
|
||||
syncState();
|
||||
}
|
||||
|
||||
@ -419,6 +419,7 @@ public:
|
||||
//- Rewind the stream, clearing any old errors
|
||||
virtual void rewind() override
|
||||
{
|
||||
Istream::rewind();
|
||||
stream_.rewind();
|
||||
syncState();
|
||||
}
|
||||
|
||||
@ -31,8 +31,7 @@ Description
|
||||
Similar to OStringStream but with a List for its storage instead of
|
||||
as string to allow reuse of List contents without copying.
|
||||
|
||||
The default initial size is 512-bytes and uses size doubling.
|
||||
After construction can use the reserve() method to adjust this.
|
||||
Internally imposes a 512 byte min-size and uses capacity doubling.
|
||||
|
||||
See Also
|
||||
Foam::ICharStream
|
||||
@ -131,6 +130,25 @@ public:
|
||||
buffer_type::reserve(n);
|
||||
}
|
||||
|
||||
//- Reserve output space for at least this amount.
|
||||
//- Does not apply min-size or capacity doubling etc.
|
||||
void reserve_exact(std::streamsize n)
|
||||
{
|
||||
buffer_type::reserve_exact(n);
|
||||
}
|
||||
|
||||
//- Increase (reserve) space for another \c count entries
|
||||
void extend(std::streamsize count)
|
||||
{
|
||||
buffer_type::extend(count);
|
||||
}
|
||||
|
||||
//- Increase (reserve) space for another \c count entries
|
||||
void extend_exact(std::streamsize count)
|
||||
{
|
||||
buffer_type::extend_exact(count);
|
||||
}
|
||||
|
||||
//- Rewind the stream, clearing any old errors
|
||||
void rewind()
|
||||
{
|
||||
@ -209,6 +227,64 @@ public:
|
||||
|
||||
//- Information about stream
|
||||
void print(Ostream& os) const { debug_info(os); os << '\n'; }
|
||||
|
||||
|
||||
// Extra/Convenience Methods
|
||||
|
||||
//- Append a single character to the end
|
||||
void push_back(char c) { stream_type::put(c); }
|
||||
|
||||
//- Rewind the end by 1 or more elements
|
||||
void pop_back(int n = 1) { buffer_type::pop_back(n); }
|
||||
|
||||
//- Append repeated character content
|
||||
void append(std::streamsize count, char c)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
buffer_type::extend(count);
|
||||
while (count-- > 0)
|
||||
{
|
||||
stream_type::put(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- Append character content - like a plain write()
|
||||
void append(const char* data, std::streamsize count)
|
||||
{
|
||||
if (data && count > 0)
|
||||
{
|
||||
buffer_type::extend(count);
|
||||
write(data, count);
|
||||
}
|
||||
}
|
||||
|
||||
//- Overwrite a single character
|
||||
void overwrite(std::streampos pos, char c)
|
||||
{
|
||||
buffer_type::overwrite(pos, c);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite
|
||||
(
|
||||
std::streampos pos,
|
||||
const char* data,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
buffer_type::overwrite(pos, data, count);
|
||||
}
|
||||
|
||||
//- The output data (start of output characters)
|
||||
const char* cdata_bytes() const { return buffer_type::data_bytes(); }
|
||||
|
||||
//- The output data (start of output characters)
|
||||
char* data_bytes() { return buffer_type::data_bytes(); }
|
||||
|
||||
//- The current number of output characters
|
||||
std::streamsize size_bytes() const { return buffer_type::size_bytes(); }
|
||||
};
|
||||
|
||||
|
||||
@ -287,6 +363,15 @@ public:
|
||||
//- Reserve output space for at least this amount
|
||||
void reserve(std::streamsize n) { stream_.reserve(n); }
|
||||
|
||||
//- Reserve output space for at least this amount.
|
||||
//- Does not apply min-size or capacity doubling etc.
|
||||
void reserve_exact(std::streamsize n) { stream_.reserve_exact(n); }
|
||||
|
||||
//- Increase (reserve) space for another \c n entries
|
||||
void extend(std::streamsize n) { stream_.extend(n); }
|
||||
|
||||
//- Increase (reserve) space for another \c n entries
|
||||
void extend_exact(std::streamsize n) { stream_.extend_exact(n); }
|
||||
|
||||
//- A string_view of buffer contents
|
||||
auto view() const { return stream_.view(); }
|
||||
@ -350,6 +435,56 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Extra/Convenience Methods
|
||||
|
||||
//- Append a single character to the end
|
||||
void push_back(char c) { stream_.push_back(c); }
|
||||
|
||||
//- Rewind the end by 1 or more elements
|
||||
void pop_back(int n = 1) { stream_.pop_back(n); }
|
||||
|
||||
//- Append repeated character content
|
||||
void append(std::streamsize count, char c)
|
||||
{
|
||||
stream_.append(count, c);
|
||||
}
|
||||
|
||||
//- Append character content
|
||||
void append(const char* data, std::streamsize count)
|
||||
{
|
||||
stream_.append(data, count);
|
||||
}
|
||||
|
||||
//- Append character content
|
||||
void append(std::string_view sv)
|
||||
{
|
||||
stream_.append(sv.data(), sv.size());
|
||||
}
|
||||
|
||||
//- Overwrite a single character
|
||||
void overwrite(std::streampos pos, char c)
|
||||
{
|
||||
stream_.overwrite(pos, c);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite
|
||||
(
|
||||
std::streampos pos,
|
||||
const char* data,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
stream_.overwrite(pos, data, count);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite(std::streampos pos, std::string_view sv)
|
||||
{
|
||||
stream_.overwrite(pos, sv.data(), sv.size());
|
||||
}
|
||||
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- Block size was used in OpenFOAM-v2306 and earlier
|
||||
|
||||
@ -226,6 +226,23 @@ public:
|
||||
|
||||
// Extra/Convenience Methods
|
||||
|
||||
//- Overwrite a single character
|
||||
void overwrite(std::streampos pos, char c)
|
||||
{
|
||||
buffer_type::overwrite(pos, c);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite
|
||||
(
|
||||
std::streampos pos,
|
||||
const char* data,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
buffer_type::overwrite(pos, data, count);
|
||||
}
|
||||
|
||||
//- The output data (start of output characters)
|
||||
const char* cdata_bytes() const { return buffer_type::data_bytes(); }
|
||||
|
||||
@ -234,7 +251,6 @@ public:
|
||||
|
||||
//- The current number of output characters
|
||||
std::streamsize size_bytes() const { return buffer_type::size_bytes(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -382,6 +398,47 @@ public:
|
||||
stream_.debug_info(os);
|
||||
os << '\n';
|
||||
}
|
||||
|
||||
|
||||
// Extra/Convenience Methods
|
||||
|
||||
//- Append character content - same as writeRaw()
|
||||
void append(const char* data, std::streamsize count)
|
||||
{
|
||||
if (data && count > 0)
|
||||
{
|
||||
writeRaw(data, count);
|
||||
}
|
||||
}
|
||||
|
||||
//- Append character content - same as writeRaw()
|
||||
void append(std::string_view sv)
|
||||
{
|
||||
append(sv.data(), sv.size());
|
||||
}
|
||||
|
||||
//- Overwrite a single character
|
||||
void overwrite(std::streampos pos, char c)
|
||||
{
|
||||
stream_.overwrite(pos, c);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite
|
||||
(
|
||||
std::streampos pos,
|
||||
const char* data,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
stream_.overwrite(pos, data, count);
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite(std::streampos pos, std::string_view sv)
|
||||
{
|
||||
stream_.overwrite(pos, sv.data(), sv.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -468,6 +468,43 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
//- Decrease the put area by 1 or more elements
|
||||
void pop_back(int n = 1)
|
||||
{
|
||||
for (; (n > 0 && (pbase() < pptr())); --n)
|
||||
{
|
||||
pbump(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//- Overwrite a sub-slice with character content
|
||||
void overwrite
|
||||
(
|
||||
std::streampos pos,
|
||||
const char* data,
|
||||
std::streamsize count
|
||||
)
|
||||
{
|
||||
if (data && (count > 0) && in_range(pos))
|
||||
{
|
||||
// Restrict to intersection with current content
|
||||
if (span_tellp() <= std::streampos(pos+count))
|
||||
{
|
||||
count = (span_tellp() - pos);
|
||||
}
|
||||
std::copy(data, (data+count), (data_bytes()+pos));
|
||||
}
|
||||
}
|
||||
|
||||
//- Overwrite a single character
|
||||
void overwrite(std::streampos pos, char c)
|
||||
{
|
||||
if (c && in_range(pos))
|
||||
{
|
||||
*(data_bytes()+pos) = c;
|
||||
}
|
||||
}
|
||||
|
||||
//- Some information about the output buffer position/capacity
|
||||
void info(Ostream& os) const
|
||||
{
|
||||
@ -500,8 +537,8 @@ protected:
|
||||
{
|
||||
if (c != traits_type::eof())
|
||||
{
|
||||
// Need more space?
|
||||
reserve(1 + span_tellp());
|
||||
// Needed more space?
|
||||
extend(1);
|
||||
|
||||
*(pptr()) = c;
|
||||
pbump(1);
|
||||
@ -513,7 +550,7 @@ protected:
|
||||
virtual std::streamsize xsputn(const char* s, std::streamsize n)
|
||||
{
|
||||
// Enough space so that appends work without problem
|
||||
reserve(n + span_tellp());
|
||||
extend(n);
|
||||
|
||||
std::streamsize count = 0;
|
||||
while (count < n && pptr() < epptr())
|
||||
@ -530,10 +567,14 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Default construct - no initial reserved number of bytes.
|
||||
out_dynamic()
|
||||
{
|
||||
sync_pbuffer();
|
||||
}
|
||||
|
||||
//- Default construct with initial reserved number of bytes.
|
||||
// The value of 512 is a bit arbitrary, but consistent with
|
||||
// std::stringstream
|
||||
out_dynamic(size_t nbytes = 512)
|
||||
out_dynamic(size_t nbytes)
|
||||
:
|
||||
storage_(label(nbytes))
|
||||
{
|
||||
@ -560,40 +601,115 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Increment capacity (if needed) and adjust buffer pointers
|
||||
//- Normal lower capacity limit.
|
||||
// 512 bytes is a bit arbitrary but consistent with std::stringstream
|
||||
static constexpr label min_size() noexcept { return 512; }
|
||||
|
||||
//- The largest storage size
|
||||
static constexpr label max_size() noexcept
|
||||
{
|
||||
return UList<char>::max_size();
|
||||
}
|
||||
|
||||
//- The 1/2 of max_size() - rounded to power-of-two
|
||||
static constexpr label max_size_2() noexcept
|
||||
{
|
||||
return (1+max_size()/2);
|
||||
}
|
||||
|
||||
//- The 1/4 of max_size() - rounded to power-of-two
|
||||
static constexpr label max_size_4() noexcept
|
||||
{
|
||||
return (max_size_2()/2);
|
||||
}
|
||||
|
||||
//- Sync put buffer pointers to agree with list dimensions.
|
||||
// Sets put pointer to the begin (rewind).
|
||||
void sync_pbuffer()
|
||||
{
|
||||
resetp(storage_.data(), storage_.size());
|
||||
}
|
||||
|
||||
//- Increase capacity (if needed) and adjust buffer pointers.
|
||||
//- Applies a min-size and capacity doubling.
|
||||
void reserve(const std::streamsize len)
|
||||
{
|
||||
if (storage_.size() < len)
|
||||
{
|
||||
const auto cur = span_tellp(); // Current location
|
||||
const auto cur = span_tellp(); // Output position
|
||||
|
||||
label newCapacity = 512;
|
||||
label size = min_size();
|
||||
|
||||
if (newCapacity < len)
|
||||
if (size < len)
|
||||
{
|
||||
// Increase capacity (doubling)
|
||||
newCapacity =
|
||||
Foam::max(label(len), label(2*storage_.size()));
|
||||
// ratio=1.5:
|
||||
// Foam::max(label(len), label((storage_.size()/2)*3));
|
||||
// Increase capacity, but grow more slowly at the largest
|
||||
// sizes. Expect a buffer of char to approach max_size()
|
||||
// more commonly than buffers of other data types.
|
||||
|
||||
if (storage_.size() <= max_size_4())
|
||||
{
|
||||
// (0 < capacity <= 0.25) : fast growth (2)
|
||||
size = label(2*storage_.size());
|
||||
}
|
||||
else if (storage_.size() <= max_size_2())
|
||||
{
|
||||
// (0.25 < capacity <= 0.5) : slower growth (1.5)
|
||||
size = label((storage_.size()/2)*3);
|
||||
}
|
||||
else if (storage_.size() <= (max_size_2() + max_size_4()))
|
||||
{
|
||||
// (0.5 < capacity <= 0.75) : very slow growth (1.25)
|
||||
size = label((storage_.size()/4)*5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already very large - use max (or just len?)
|
||||
size = max_size();
|
||||
}
|
||||
|
||||
// Info<<"request:" << len
|
||||
// << " cur cap:" << storage_.size()
|
||||
// << " new cap:" << newCapacity
|
||||
// max(size, len)
|
||||
if (size < len)
|
||||
{
|
||||
size = len;
|
||||
}
|
||||
}
|
||||
|
||||
// std::cerr
|
||||
// <<"request:" << len
|
||||
// << " old cap:" << storage_.size()
|
||||
// << " new cap:" << size
|
||||
// << " pos:" << cur << endl;
|
||||
|
||||
storage_.resize(newCapacity);
|
||||
storage_.resize_copy(cur, size);
|
||||
sync_pbuffer();
|
||||
pbump(cur);
|
||||
}
|
||||
}
|
||||
|
||||
//- Sync put buffer pointers to agree with list dimensions
|
||||
// Sets put pointer to the begin (rewind).
|
||||
void sync_pbuffer()
|
||||
//- Increase capacity for at least this size.
|
||||
//- Does not apply min-size or capacity doubling etc.
|
||||
void reserve_exact(const std::streamsize len)
|
||||
{
|
||||
resetp(storage_.data(), storage_.size());
|
||||
if (storage_.size() < len)
|
||||
{
|
||||
const auto cur = span_tellp(); // Output position
|
||||
|
||||
storage_.resize_copy(cur, len);
|
||||
sync_pbuffer();
|
||||
pbump(cur);
|
||||
}
|
||||
}
|
||||
|
||||
//- Increase (reserve) space for another \c count entries
|
||||
void extend(std::streamsize count)
|
||||
{
|
||||
reserve(span_tellp() + count);
|
||||
}
|
||||
|
||||
//- Increase (reserve) space for another \c count entries
|
||||
void extend_exact(std::streamsize count)
|
||||
{
|
||||
reserve_exact(span_tellp() + count);
|
||||
}
|
||||
|
||||
//- Clear storage
|
||||
|
||||
@ -79,19 +79,14 @@ class DynamicField
|
||||
template<class ListType>
|
||||
inline void doAssignDynList(const ListType& list);
|
||||
|
||||
//- Alter the size of the underlying storage
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doCapacity(const bool nocopy, const label len);
|
||||
//- Alter the size of the underlying storage,
|
||||
//- retaining the first count elements.
|
||||
inline void doCapacity_copy(label count, const label len);
|
||||
|
||||
//- Reserve allocation space for at least this size.
|
||||
//- Reserve allocation space for at least this size,
|
||||
//- retaining the first count elements.
|
||||
// Never shrinks the allocated size, use setCapacity() for that.
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doReserve(const bool nocopy, const label len);
|
||||
|
||||
//- Reserve allocation space for at least this size.
|
||||
// Never shrinks the allocated size, use setCapacity() for that.
|
||||
// The 'nocopy' option will not attempt to recover old content
|
||||
inline void doResize(const bool nocopy, const label len);
|
||||
inline void doReserve_copy(label count, const label len);
|
||||
|
||||
|
||||
public:
|
||||
@ -246,6 +241,10 @@ public:
|
||||
//- Alter addressable size and fill \em new entries with constant value
|
||||
inline void resize(const label len, const T& val);
|
||||
|
||||
//- Alter addressable size, retaining the first count contents.
|
||||
// \note Only uses a limited number of internal checks.
|
||||
inline void resize_copy(label count, const label len);
|
||||
|
||||
//- Alter addressable size and set val for \em all addressed entries
|
||||
inline void resize_fill(const label len, const T& val);
|
||||
|
||||
|
||||
@ -52,9 +52,9 @@ inline void Foam::DynamicField<T, SizeMin>::doAssignDynList
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::doCapacity
|
||||
inline void Foam::DynamicField<T, SizeMin>::doCapacity_copy
|
||||
(
|
||||
const bool nocopy,
|
||||
label count,
|
||||
const label newCapacity
|
||||
)
|
||||
{
|
||||
@ -66,16 +66,22 @@ inline void Foam::DynamicField<T, SizeMin>::doCapacity
|
||||
// Addressable length, possibly truncated by new capacity
|
||||
const label currLen = Foam::min(List<T>::size(), newCapacity);
|
||||
|
||||
// The count truncated by the new addressable range
|
||||
if (count > currLen)
|
||||
{
|
||||
count = currLen;
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
if (nocopy)
|
||||
if (count > 0)
|
||||
{
|
||||
List<T>::resize_nocopy(newCapacity);
|
||||
List<T>::resize_copy(count, newCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<T>::resize_copy(currLen, newCapacity);
|
||||
List<T>::resize_nocopy(newCapacity);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -84,9 +90,9 @@ inline void Foam::DynamicField<T, SizeMin>::doCapacity
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::doReserve
|
||||
inline void Foam::DynamicField<T, SizeMin>::doReserve_copy
|
||||
(
|
||||
const bool nocopy,
|
||||
label count,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
@ -95,6 +101,12 @@ inline void Foam::DynamicField<T, SizeMin>::doReserve
|
||||
// Preserve addressed size
|
||||
const label currLen = List<T>::size();
|
||||
|
||||
// The count truncated by the addressable range
|
||||
if (count > currLen)
|
||||
{
|
||||
count = currLen;
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
@ -102,13 +114,13 @@ inline void Foam::DynamicField<T, SizeMin>::doReserve
|
||||
capacity_ =
|
||||
Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
|
||||
|
||||
if (nocopy)
|
||||
if (count > 0)
|
||||
{
|
||||
List<T>::resize_nocopy(capacity_);
|
||||
List<T>::resize_copy(count, capacity_);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<T>::resize_copy(currLen, capacity_);
|
||||
List<T>::resize_nocopy(capacity_);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -117,18 +129,6 @@ inline void Foam::DynamicField<T, SizeMin>::doReserve
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::doResize
|
||||
(
|
||||
const bool nocopy,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(nocopy, len);
|
||||
List<T>::setAddressableSize(len);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T, int SizeMin>
|
||||
@ -342,7 +342,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
|
||||
)
|
||||
:
|
||||
Field<T>(),
|
||||
capacity_(content.size())
|
||||
capacity_(0)
|
||||
{
|
||||
if (reuse)
|
||||
{
|
||||
@ -352,6 +352,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
|
||||
{
|
||||
Field<T>::operator=(content);
|
||||
}
|
||||
capacity_ = Field<T>::size();
|
||||
}
|
||||
|
||||
|
||||
@ -424,7 +425,8 @@ inline void Foam::DynamicField<T, SizeMin>::setCapacity
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doCapacity(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
doCapacity_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
@ -434,7 +436,8 @@ inline void Foam::DynamicField<T, SizeMin>::setCapacity_nocopy
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doCapacity(true, len); // nocopy = true
|
||||
// Preserve 0 content
|
||||
doCapacity_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
@ -444,7 +447,8 @@ inline void Foam::DynamicField<T, SizeMin>::reserve
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
doReserve_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
@ -454,7 +458,8 @@ inline void Foam::DynamicField<T, SizeMin>::reserve_nocopy
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doReserve(true, len); // nocopy = true
|
||||
// Preserve 0 content
|
||||
doReserve_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
@ -472,9 +477,12 @@ inline void Foam::DynamicField<T, SizeMin>::reserve_exact
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
|
||||
// Exact length
|
||||
capacity_ = len;
|
||||
|
||||
// if (!nocopy)
|
||||
{
|
||||
List<T>::resize_copy(currLen, len);
|
||||
List<T>::resize_copy(currLen, capacity_);
|
||||
}
|
||||
|
||||
capacity_ = List<T>::size();
|
||||
@ -489,17 +497,21 @@ inline void Foam::DynamicField<T, SizeMin>::resize
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doResize(false, len); // nocopy = false
|
||||
// Preserve all content
|
||||
resize_copy(List<T>::size(), len);
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::resize_nocopy
|
||||
inline void Foam::DynamicField<T, SizeMin>::resize_copy
|
||||
(
|
||||
label count,
|
||||
const label len
|
||||
)
|
||||
{
|
||||
this->doResize(true, len); // nocopy = true
|
||||
// Preserve count elements
|
||||
doReserve_copy(count, len);
|
||||
List<T>::setAddressableSize(len);
|
||||
}
|
||||
|
||||
|
||||
@ -510,11 +522,22 @@ inline void Foam::DynamicField<T, SizeMin>::resize_fill
|
||||
const T& val
|
||||
)
|
||||
{
|
||||
this->doResize(true, len); // nocopy = true
|
||||
resize_nocopy(len);
|
||||
UList<T>::operator=(val);
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::resize_nocopy
|
||||
(
|
||||
const label len
|
||||
)
|
||||
{
|
||||
// Preserve 0 content
|
||||
resize_copy(0, len);
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::resize
|
||||
(
|
||||
@ -523,6 +546,8 @@ inline void Foam::DynamicField<T, SizeMin>::resize
|
||||
)
|
||||
{
|
||||
const label oldLen = List<T>::size();
|
||||
|
||||
// Preserve all content
|
||||
resize(len);
|
||||
|
||||
// Fill newly exposed with constant value
|
||||
@ -546,6 +571,11 @@ inline void Foam::DynamicField<T, SizeMin>::clear() noexcept
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::clearStorage()
|
||||
{
|
||||
// Extra safety...?
|
||||
if (!List<T>::cdata() && List<T>::empty()) capacity_ = 0;
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
List<T>::clear();
|
||||
capacity_ = 0;
|
||||
}
|
||||
@ -555,7 +585,6 @@ template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::shrink_to_fit()
|
||||
{
|
||||
const label currLen = List<T>::size();
|
||||
|
||||
if (currLen < capacity_)
|
||||
{
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
@ -570,10 +599,13 @@ inline void
|
||||
Foam::DynamicField<T, SizeMin>::swap(List<T>& other)
|
||||
{
|
||||
if
|
||||
(
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const List<T>*>(this)
|
||||
== static_cast<const List<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
return; // Self-swap is a no-op
|
||||
}
|
||||
@ -597,10 +629,13 @@ inline void Foam::DynamicField<T, SizeMin>::swap
|
||||
) noexcept
|
||||
{
|
||||
if
|
||||
(
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const List<T>*>(this)
|
||||
== static_cast<const List<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
return; // Self-swap is a no-op
|
||||
}
|
||||
@ -621,10 +656,13 @@ inline void Foam::DynamicField<T, SizeMin>::swap
|
||||
) noexcept
|
||||
{
|
||||
if
|
||||
(
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const List<T>*>(this)
|
||||
== static_cast<const List<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
return; // Self-swap is a no-op
|
||||
}
|
||||
@ -633,17 +671,19 @@ inline void Foam::DynamicField<T, SizeMin>::swap
|
||||
UList<T>::swap(other);
|
||||
|
||||
// Swap capacity
|
||||
const label oldCap = this->capacity();
|
||||
const label newCap = other.capacity();
|
||||
|
||||
this->setCapacity_unsafe(newCap);
|
||||
other.setCapacity_unsafe(oldCap);
|
||||
auto old = capacity_;
|
||||
this->setCapacity_unsafe(other.capacity());
|
||||
other.setCapacity_unsafe(old);
|
||||
}
|
||||
|
||||
|
||||
template<class T, int SizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::transfer(List<T>& list)
|
||||
{
|
||||
// No check for self-assignment (different types)
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
Field<T>::transfer(list);
|
||||
capacity_ = Field<T>::size();
|
||||
}
|
||||
@ -653,7 +693,7 @@ template<class T, int SizeMin>
|
||||
template<int AnySizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::transfer
|
||||
(
|
||||
DynamicList<T, AnySizeMin>& list
|
||||
DynamicList<T, AnySizeMin>& other
|
||||
)
|
||||
{
|
||||
if
|
||||
@ -661,19 +701,22 @@ inline void Foam::DynamicField<T, SizeMin>::transfer
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const UList<T>*>(this)
|
||||
== static_cast<const UList<T>*>(&list)
|
||||
== static_cast<const UList<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
Field<T>::transfer(static_cast<List<T>&>(list));
|
||||
// Remove storage
|
||||
this->clearStorage();
|
||||
|
||||
capacity_ = list.capacity();
|
||||
list.setCapacity_unsafe(0); // All contents moved
|
||||
// Swap storage and addressable size
|
||||
UList<T>::swap(other);
|
||||
|
||||
// Update capacity
|
||||
capacity_ = other.capacity();
|
||||
other.setCapacity_unsafe(0);
|
||||
}
|
||||
|
||||
|
||||
@ -681,7 +724,7 @@ template<class T, int SizeMin>
|
||||
template<int AnySizeMin>
|
||||
inline void Foam::DynamicField<T, SizeMin>::transfer
|
||||
(
|
||||
DynamicField<T, AnySizeMin>& list
|
||||
DynamicField<T, AnySizeMin>& other
|
||||
)
|
||||
{
|
||||
if
|
||||
@ -689,19 +732,22 @@ inline void Foam::DynamicField<T, SizeMin>::transfer
|
||||
FOAM_UNLIKELY
|
||||
(
|
||||
static_cast<const UList<T>*>(this)
|
||||
== static_cast<const UList<T>*>(&list)
|
||||
== static_cast<const UList<T>*>(&other)
|
||||
)
|
||||
)
|
||||
{
|
||||
return; // Self-assignment is a no-op
|
||||
}
|
||||
|
||||
// Consistent allocated sizing
|
||||
List<T>::setAddressableSize(capacity_);
|
||||
Field<T>::transfer(static_cast<List<T>&>(list));
|
||||
// Remove storage
|
||||
this->clearStorage();
|
||||
|
||||
capacity_ = list.capacity();
|
||||
list.setCapacity_unsafe(0); // All contents moved
|
||||
// Swap storage and addressable size
|
||||
UList<T>::swap(other);
|
||||
|
||||
// Update capacity
|
||||
capacity_ = other.capacity();
|
||||
other.setCapacity_unsafe(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ UPstreamCommunicator.C
|
||||
UPstreamGatherScatter.C
|
||||
UPstreamReduce.C
|
||||
UPstreamRequest.C
|
||||
UPstreamFile.C
|
||||
UPstreamWindow.C
|
||||
|
||||
UIPstreamRead.C
|
||||
|
||||
170
src/Pstream/dummy/UPstreamFile.C
Normal file
170
src/Pstream/dummy/UPstreamFile.C
Normal file
@ -0,0 +1,170 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 Mark Olesen
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fileName.H"
|
||||
#include "UPstreamFile.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class UPstream::File::Impl Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class UPstream::File::Impl {};
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::supported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UPstream::File::File() {}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UPstream::File::~File()
|
||||
{} // Non-default in header (incomplete types)
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::fileName& Foam::UPstream::File::name() const
|
||||
{
|
||||
return fileName::null;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::is_open() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::close()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Member Functions (Reading) * * * * * * * * * * * //
|
||||
|
||||
#if 0
|
||||
bool Foam::UPstream::File::open_read
|
||||
(
|
||||
const int communicator,
|
||||
const fileName& pathname
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Member Functions (Writing) * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::open_write
|
||||
(
|
||||
const int communicator,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::atomicType
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data
|
||||
(
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data_at
|
||||
(
|
||||
std::streamsize offset,
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data_all
|
||||
(
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data_at_all
|
||||
(
|
||||
std::streamsize offset,
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::set_size(std::streamsize num_bytes)
|
||||
{
|
||||
NotImplemented;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -6,6 +6,7 @@ UPstreamCommunicator.C
|
||||
UPstreamGatherScatter.C
|
||||
UPstreamReduce.C
|
||||
UPstreamRequest.C
|
||||
UPstreamFile.C
|
||||
UPstreamWindow.C
|
||||
|
||||
UIPstreamRead.C
|
||||
|
||||
687
src/Pstream/mpi/UPstreamFile.C
Normal file
687
src/Pstream/mpi/UPstreamFile.C
Normal file
@ -0,0 +1,687 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 Mark Olesen
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fileName.H"
|
||||
#include "UPstreamFile.H"
|
||||
#include "PstreamGlobals.H"
|
||||
#include "OSspecific.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Has _c() version?
|
||||
#undef Foam_UPstream_largeCountFile
|
||||
|
||||
#if defined(OMPI_MAJOR_VERSION)
|
||||
#if (OMPI_MAJOR_VERSION >= 5)
|
||||
#define Foam_UPstream_largeCountFile
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Macros for calling versions with or without '_c'
|
||||
#ifdef Foam_UPstream_largeCountFile
|
||||
#define Foam_mpiCall(Function) Function##_c
|
||||
#else
|
||||
#define Foam_mpiCall(Function) Function
|
||||
#endif
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline bool checkCount(std::streamsize count, const char* what)
|
||||
{
|
||||
#ifndef Foam_UPstream_largeCountFile
|
||||
if (FOAM_UNLIKELY(count > std::streamsize(INT_MAX)))
|
||||
{
|
||||
using namespace Foam;
|
||||
FatalErrorInFunction
|
||||
<< "Write size " << label(count)
|
||||
<< " exceeds INT_MAX bytes for '" << what << "'\n"
|
||||
<< Foam::abort(Foam::FatalError);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End anonymous namespace
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class UPstream::File::Impl Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class UPstream::File::Impl
|
||||
{
|
||||
//- The file-handle
|
||||
MPI_File fh_;
|
||||
|
||||
//- Path of the open file
|
||||
fileName name_;
|
||||
|
||||
//- The current state (open|read|write|closed etc)
|
||||
int state_;
|
||||
|
||||
//- The associated rank when openned
|
||||
int rank_;
|
||||
|
||||
public:
|
||||
|
||||
//- The file states
|
||||
enum states : int { CLOSED = 0, READ, WRITE, ATOMIC_WRITE };
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Default construct
|
||||
Impl()
|
||||
:
|
||||
fh_(MPI_FILE_NULL),
|
||||
state_(CLOSED),
|
||||
rank_(0)
|
||||
{}
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// The file handle
|
||||
const MPI_File& handle() const noexcept { return fh_; }
|
||||
MPI_File& handle() noexcept { return fh_; }
|
||||
|
||||
// Path to the open file
|
||||
const fileName& name() const noexcept { return name_; }
|
||||
fileName& name() noexcept { return name_; }
|
||||
|
||||
// Change the file state, return the old value
|
||||
int state(states val) noexcept
|
||||
{
|
||||
int old(state_);
|
||||
state_ = val;
|
||||
return old;
|
||||
}
|
||||
|
||||
//- Is rank 0 ? (master rank)
|
||||
bool master() const noexcept { return (rank_ == 0); }
|
||||
|
||||
//- Get the associated rank
|
||||
int rank() const noexcept { return rank_; }
|
||||
|
||||
//- Set the associated rank
|
||||
void rank(int val) noexcept { rank_ = val; }
|
||||
|
||||
|
||||
// Checks
|
||||
|
||||
// The file state
|
||||
bool is_open() const noexcept { return state_; }
|
||||
|
||||
// The file read state
|
||||
bool is_read() const noexcept
|
||||
{
|
||||
return (states::READ == state_);
|
||||
}
|
||||
|
||||
// The file write atomic state
|
||||
bool is_atomic() const noexcept
|
||||
{
|
||||
return (states::ATOMIC_WRITE == state_);
|
||||
}
|
||||
|
||||
// The file write state (atomic or non-atomic)
|
||||
bool is_write() const noexcept
|
||||
{
|
||||
return (states::ATOMIC_WRITE == state_ || states::WRITE == state_);
|
||||
}
|
||||
|
||||
//- Assert is_read() or FatalError
|
||||
inline bool checkReadable(const char* what) const
|
||||
{
|
||||
if (FOAM_UNLIKELY(!is_read()))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "File handler not open for reading '" << what << "'\n"
|
||||
<< "name: " << name() << nl
|
||||
<< Foam::exit(Foam::FatalError);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//- Assert is_write() or FatalError
|
||||
inline bool checkWritable(const char* what) const
|
||||
{
|
||||
if (FOAM_UNLIKELY(!is_write()))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "File handler not open for writing'" << what << "'\n"
|
||||
<< "name: " << name() << nl
|
||||
<< Foam::exit(Foam::FatalError);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::supported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UPstream::File::File()
|
||||
:
|
||||
file_(new UPstream::File::Impl)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UPstream::File::~File()
|
||||
{
|
||||
if (FOAM_UNLIKELY(file_ && file_->is_open()))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Exited scope without close()" << nl
|
||||
<< " FIX YOUR CODE!!" << endl;
|
||||
// Do not call close() since we don't know where that collective
|
||||
// should have been called
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::fileName& Foam::UPstream::File::name() const
|
||||
{
|
||||
return (file_ ? file_->name() : fileName::null);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::is_open() const
|
||||
{
|
||||
return bool(file_ && file_->is_open());
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::close()
|
||||
{
|
||||
if (FOAM_UNLIKELY(!file_->is_open()))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Called without an open file handler !" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
MPI_File_close(&(file_->handle()));
|
||||
|
||||
// Atomic rename of file (master only)
|
||||
const fileName& pathname = file_->name();
|
||||
|
||||
if (file_->master() && file_->is_atomic() && !pathname.empty())
|
||||
{
|
||||
std::rename
|
||||
(
|
||||
(pathname + "~tmp~").c_str(),
|
||||
pathname.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
file_->state(Impl::CLOSED);
|
||||
file_->name() = "";
|
||||
file_->rank(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Member Functions (Reading) * * * * * * * * * * * //
|
||||
|
||||
#if 0
|
||||
bool Foam::UPstream::File::open_read
|
||||
(
|
||||
const int communicator,
|
||||
const fileName& pathname
|
||||
)
|
||||
{
|
||||
//Needed? PstreamGlobals::checkCommunicator(communicator, 0);
|
||||
|
||||
if (FOAM_UNLIKELY(file_->is_open()))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Previous use of file handler did not call close()" << nl
|
||||
<< " FIX YOUR CODE!!" << endl;
|
||||
// Do not call close() since we don't know where that collective
|
||||
// should have been called
|
||||
}
|
||||
file_->state(Impl::CLOSED);
|
||||
file_->name() = pathname; // <- set now for external error messages
|
||||
file_->rank(0);
|
||||
|
||||
int returnCode = MPI_File_open
|
||||
(
|
||||
PstreamGlobals::MPICommunicators_[communicator],
|
||||
pathname.c_str(),
|
||||
(MPI_MODE_RDONLY),
|
||||
MPI_INFO_NULL,
|
||||
&(file_->handle())
|
||||
);
|
||||
|
||||
if (FOAM_UNLIKELY(MPI_SUCCESS != returnCode))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Error encounted in MPI_File_open() : "
|
||||
<< pathname << nl
|
||||
<< Foam::exit(Foam::FatalError);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
file_->state(Impl::READ);
|
||||
file_->name() = pathname;
|
||||
file_->rank(UPstream::myProcNo(communicator));
|
||||
|
||||
return true; // ie, is_read()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Non-Collective Reading * * * * * * * * * * * * * //
|
||||
|
||||
#if 0
|
||||
bool Foam::UPstream::File::get_header(DynamicList<char>& content)
|
||||
{
|
||||
std::streamsize headerSize(4096);
|
||||
|
||||
// constexpr const char* const func = "MPI_File_read_at";
|
||||
file_->checkReadable("MPI_File_read_at");
|
||||
|
||||
if (off_t fileLen = Foam::fileSize(this->name()); fileLen >= 0)
|
||||
{
|
||||
std::streamsize size = std::streamsize(fileLen);
|
||||
if (headerSize > size)
|
||||
{
|
||||
headerSize = size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
content.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the first header content:
|
||||
content.resize_nocopy(headerSize);
|
||||
|
||||
int returnCode = Foam_mpiCall(MPI_File_read_at)
|
||||
(
|
||||
file_->handle(),
|
||||
0, // offset
|
||||
content.data(),
|
||||
content.size(),
|
||||
MPI_BYTE,
|
||||
MPI_STATUS_IGNORE
|
||||
);
|
||||
|
||||
// Wrap as ISpanStream headerStream(content);
|
||||
if (MPI_SUCCESS == returnCode)
|
||||
{
|
||||
ISpanStream is(content);
|
||||
dictionary headerDict;
|
||||
|
||||
// Read the regular "FoamFile" header
|
||||
bool ok = io.readHeader(headerDict, is);
|
||||
|
||||
// Probably collated - extract class from "data.class"
|
||||
if
|
||||
(
|
||||
decomposedBlockData::isCollatedType(io)
|
||||
&& headerDict.readIfPresent("data.class", io.headerClassName())
|
||||
)
|
||||
{
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Member Functions (Writing) * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::open_write
|
||||
(
|
||||
const int communicator,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::atomicType atomicType
|
||||
)
|
||||
{
|
||||
//Needed? PstreamGlobals::checkCommunicator(communicator, 0);
|
||||
|
||||
if (FOAM_UNLIKELY(file_->is_open()))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Previous use of file handler did not call close()" << nl
|
||||
<< " FIX YOUR CODE!!" << endl;
|
||||
// Do not call close() since we don't know where that collective
|
||||
// should have been called
|
||||
}
|
||||
file_->state(Impl::CLOSED);
|
||||
file_->name() = pathname; // <- set now for external error messages
|
||||
file_->rank(0);
|
||||
|
||||
const bool atomic = (IOstreamOption::atomicType::ATOMIC == atomicType);
|
||||
|
||||
// When opening new files, remove file variants out of the way.
|
||||
// Eg, opening "file1"
|
||||
// - remove old "file1.gz" (compressed)
|
||||
// - also remove old "file1" if it is a symlink
|
||||
|
||||
const fileName pathname_gz(pathname + ".gz");
|
||||
const fileName pathname_tmp(pathname + "~tmp~");
|
||||
|
||||
// File to open with MPI_File_open
|
||||
const auto& target = (atomic ? pathname_tmp : pathname);
|
||||
|
||||
// Remove old compressed version (if any)
|
||||
if
|
||||
(
|
||||
auto fType = Foam::type(pathname_gz, false);
|
||||
(fType == fileName::SYMLINK || fType == fileName::FILE)
|
||||
)
|
||||
{
|
||||
Foam::rm(pathname_gz);
|
||||
}
|
||||
|
||||
// Avoid writing into symlinked files (non-append mode)
|
||||
if
|
||||
(
|
||||
auto fType = Foam::type(target, false);
|
||||
fType == fileName::SYMLINK
|
||||
)
|
||||
{
|
||||
Foam::rm(target);
|
||||
}
|
||||
|
||||
int returnCode = MPI_File_open
|
||||
(
|
||||
PstreamGlobals::MPICommunicators_[communicator],
|
||||
target.c_str(),
|
||||
(MPI_MODE_CREATE | MPI_MODE_WRONLY),
|
||||
MPI_INFO_NULL,
|
||||
&(file_->handle())
|
||||
);
|
||||
|
||||
if (FOAM_UNLIKELY(MPI_SUCCESS != returnCode))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Error encounted in MPI_File_open() : "
|
||||
<< target << nl
|
||||
<< Foam::exit(Foam::FatalError);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
file_->state(atomic ? Impl::ATOMIC_WRITE : Impl::WRITE);
|
||||
file_->name() = pathname;
|
||||
file_->rank(UPstream::myProcNo(communicator));
|
||||
|
||||
return true; // ie, is_write()
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::set_size(std::streamsize num_bytes)
|
||||
{
|
||||
if (FOAM_UNLIKELY(!file_->is_open()))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Called without an open file handler !" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int returnCode = MPI_File_set_size(file_->handle(), num_bytes);
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Non-Collective Writing * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::write_data
|
||||
(
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
|
||||
// constexpr const char* const func = "MPI_File_write";
|
||||
file_->checkWritable("MPI_File_write");
|
||||
checkCount(count, "MPI_File_write");
|
||||
|
||||
int returnCode = Foam_mpiCall(MPI_File_write)
|
||||
(
|
||||
file_->handle(),
|
||||
data,
|
||||
count,
|
||||
datatype,
|
||||
MPI_STATUS_IGNORE
|
||||
);
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data_at
|
||||
(
|
||||
std::streamsize offset,
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
|
||||
// constexpr const char* const func = "MPI_File_write_at";
|
||||
file_->checkWritable("MPI_File_write_at");
|
||||
checkCount(count, "MPI_File_write_at");
|
||||
|
||||
int returnCode = Foam_mpiCall(MPI_File_write_at)
|
||||
(
|
||||
file_->handle(),
|
||||
offset,
|
||||
data,
|
||||
count,
|
||||
datatype,
|
||||
MPI_STATUS_IGNORE
|
||||
);
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Collective Writing * * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::UPstream::File::write_data_all
|
||||
(
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
|
||||
// constexpr const char* const func = "MPI_File_write_all";
|
||||
file_->checkWritable("MPI_File_write_all");
|
||||
checkCount(count, "MPI_File_write_all");
|
||||
|
||||
int returnCode = Foam_mpiCall(MPI_File_write_all)
|
||||
(
|
||||
file_->handle(),
|
||||
data,
|
||||
count,
|
||||
datatype,
|
||||
MPI_STATUS_IGNORE
|
||||
);
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::UPstream::File::write_data_at_all
|
||||
(
|
||||
std::streamsize offset,
|
||||
const void* data,
|
||||
std::streamsize count,
|
||||
const UPstream::dataTypes dataTypeId
|
||||
)
|
||||
{
|
||||
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
|
||||
// constexpr const char* const func = "MPI_File_write_at_all";
|
||||
file_->checkWritable("MPI_File_write_at_all");
|
||||
checkCount(count, "MPI_File_write_at_all");
|
||||
|
||||
int returnCode = Foam_mpiCall(MPI_File_write_at_all)
|
||||
(
|
||||
file_->handle(),
|
||||
offset,
|
||||
data,
|
||||
count,
|
||||
datatype,
|
||||
MPI_STATUS_IGNORE
|
||||
);
|
||||
|
||||
return (MPI_SUCCESS == returnCode);
|
||||
}
|
||||
|
||||
|
||||
// bool Foam::UPstream::File::write_data_all_begin
|
||||
// (
|
||||
// const void* data,
|
||||
// std::streamsize count,
|
||||
// const UPstream::dataTypes dataTypeId
|
||||
// )
|
||||
// {
|
||||
// MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
//
|
||||
// // constexpr const char* const func = "MPI_File_write_all_begin";
|
||||
// file_->checkWritable("MPI_File_write_all_begin");
|
||||
// checkCount(count, "MPI_File_write_all_begin");
|
||||
//
|
||||
// int returnCode = Foam_mpiCall(MPI_File_write_all_begin)
|
||||
// (
|
||||
// file_->handle(),
|
||||
// data,
|
||||
// count,
|
||||
// datatype,
|
||||
// MPI_STATUS_IGNORE
|
||||
// );
|
||||
//
|
||||
// return (MPI_SUCCESS == returnCode);
|
||||
// }
|
||||
|
||||
|
||||
// bool Foam::UPstream::File::write_data_all_end
|
||||
// (
|
||||
// const void* data
|
||||
// )
|
||||
// {
|
||||
// file_->checkWritable("MPI_File_write_all_end");
|
||||
// int returnCode = Foam_mpiCall(MPI_File_write_all_end)
|
||||
// (
|
||||
// file_->handle(),
|
||||
// data
|
||||
// MPI_STATUS_IGNORE
|
||||
// );
|
||||
//
|
||||
// return (MPI_SUCCESS == returnCode);
|
||||
// }
|
||||
|
||||
|
||||
// bool Foam::UPstream::File::write_data_at_all_begin
|
||||
// (
|
||||
// std::streamsize offset,
|
||||
// const void* data,
|
||||
// std::streamsize count,
|
||||
// const UPstream::dataTypes dataTypeId
|
||||
// )
|
||||
// {
|
||||
// MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
|
||||
//
|
||||
// // constexpr const char* const func = "MPI_File_write_at_all_begin";
|
||||
// file_->checkWritable("MPI_File_write_at_all_begin");
|
||||
// checkCount(count, "MPI_File_write_at_all_begin");
|
||||
//
|
||||
// int returnCode = Foam_mpiCall(MPI_File_write_at_all_begin)
|
||||
// (
|
||||
// file_->handle(),
|
||||
// offset,
|
||||
// data,
|
||||
// count,
|
||||
// datatype,
|
||||
// MPI_STATUS_IGNORE
|
||||
// );
|
||||
//
|
||||
// return (MPI_SUCCESS == returnCode);
|
||||
// }
|
||||
|
||||
|
||||
// bool Foam::UPstream::File::write_data_at_all_end
|
||||
// (
|
||||
// const void* data
|
||||
// )
|
||||
// {
|
||||
// file_->checkWritable("MPI_File_write_at_all_end");
|
||||
//
|
||||
// int returnCode = Foam_mpiCall(MPI_File_write_at_all_end)
|
||||
// (
|
||||
// file_->handle(),
|
||||
// data
|
||||
// MPI_STATUS_IGNORE
|
||||
// );
|
||||
//
|
||||
// return (MPI_SUCCESS == returnCode);
|
||||
// }
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user