From cd798164131099ba9fba54fd4b810c40ff337bfd Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Thu, 22 Aug 2024 10:51:58 -0700 Subject: [PATCH] IOFormatSaver Add a class that can be used to save and restore IO stream format in a RAII way. Below is an example. auto& os = amrex::OutStream(); auto old_fill = os.fill(); auto old_flags = os.flags(); auto old_precision = os.precision(); auto old_width = os.width(); { IOFormatSaver iofmtsaver(os); os << std::setfill('x'); os << std::left; os << std::setprecision(4); os << std::setw(111); } AMREX_ALWAYS_ASSERT(old_fill == os.fill()); AMREX_ALWAYS_ASSERT(old_flags == os.flags()); AMREX_ALWAYS_ASSERT(old_precision == os.precision()); AMREX_ALWAYS_ASSERT(old_width == os.width()); --- Src/Base/AMReX_IOFormat.H | 51 +++++++++++++++++++++++++++++++++ Src/Base/AMReX_TinyProfiler.cpp | 10 +++++-- Src/Base/AMReX_VisMF.cpp | 8 ++---- Src/Base/CMakeLists.txt | 1 + Src/Base/Make.package | 1 + 5 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 Src/Base/AMReX_IOFormat.H diff --git a/Src/Base/AMReX_IOFormat.H b/Src/Base/AMReX_IOFormat.H new file mode 100644 index 0000000000..e9a5597cb0 --- /dev/null +++ b/Src/Base/AMReX_IOFormat.H @@ -0,0 +1,51 @@ +#ifndef AMREX_IO_FORMAT_H_ +#define AMREX_IO_FORMAT_H_ + +#include + +namespace amrex { + +/* + * \brief I/O stream format saver + * + * This class can be used to save and restore I/O stream format in a RAII + * way. It handles fill, fmtflag, precision, and width. + */ +template +class IOFormatSaver +{ +public: + using BasicIos = std::basic_ios; + + explicit IOFormatSaver (BasicIos& ios) + : m_ios(&ios), + m_fill(ios.fill()), + m_flags(ios.flags()), + m_precision(ios.precision()), + m_width(ios.width()) + {} + + ~IOFormatSaver () + { + m_ios->fill(m_fill); + m_ios->flags(m_flags); + m_ios->precision(m_precision); + m_ios->width(m_width); + } + + IOFormatSaver (IOFormatSaver const&) = delete; + IOFormatSaver (IOFormatSaver &&) noexcept = delete; + IOFormatSaver& operator= (IOFormatSaver const&) = delete; + IOFormatSaver& operator= (IOFormatSaver &&) noexcept = delete; + +private: + BasicIos* m_ios; + CharT m_fill; + typename BasicIos::fmtflags m_flags; + std::streamsize m_precision; + std::streamsize m_width; +}; + +} + +#endif diff --git a/Src/Base/AMReX_TinyProfiler.cpp b/Src/Base/AMReX_TinyProfiler.cpp index db92274578..4360cf7671 100644 --- a/Src/Base/AMReX_TinyProfiler.cpp +++ b/Src/Base/AMReX_TinyProfiler.cpp @@ -10,6 +10,7 @@ #include #endif #include +#include #ifdef AMREX_USE_OMP #include @@ -386,7 +387,6 @@ TinyProfiler::Finalize (bool bFlushing) noexcept std::ofstream ofs; std::ostream* os = nullptr; - std::streamsize oldprec = 0; if (ParallelDescriptor::IOProcessor()) { if (output_file.empty()) { os = &(amrex::OutStream()); @@ -399,6 +399,8 @@ TinyProfiler::Finalize (bool bFlushing) noexcept } } + IOFormatSaver iofmtsaver(amrex::OutStream()); + if (os) { os->precision(4); @@ -438,8 +440,6 @@ TinyProfiler::Finalize (bool bFlushing) noexcept } } } - - if(os) { os->precision(oldprec); } } void @@ -593,6 +593,8 @@ TinyProfiler::PrintStats (std::map& regstats, double dt_max, if (ParallelDescriptor::IOProcessor() && os) { + IOFormatSaver iofmtsaver(*os); + *os << std::setfill(' ') << std::setprecision(4); int wt = 9; @@ -876,6 +878,8 @@ TinyProfiler::PrintMemStats (std::map& memstats, if (allstatsstr.size() == 1 || !os) { return; } + IOFormatSaver iofmtsaver(*os); + int lenhline = 0; for (auto i : maxlen) { lenhline += i; diff --git a/Src/Base/AMReX_VisMF.cpp b/Src/Base/AMReX_VisMF.cpp index 2b0ac6716d..f5f1430d59 100644 --- a/Src/Base/AMReX_VisMF.cpp +++ b/Src/Base/AMReX_VisMF.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -277,9 +278,9 @@ operator<< (std::ostream &os, // Up the precision for the Reals in m_min and m_max. // Force it to be written in scientific notation to match fParallel code. // - std::ios::fmtflags oflags = os.flags(); + IOFormatSaver iofmtsaver(os); os.setf(std::ios::floatfield, std::ios::scientific); - int oldPrec = static_cast(os.precision(16)); + os.precision(17); os << hd.m_vers << '\n'; os << int(hd.m_how) << '\n'; @@ -327,9 +328,6 @@ operator<< (std::ostream &os, } } - os.flags(oflags); - os.precision(oldPrec); - if( ! os.good()) { amrex::Error("Write of VisMF::Header failed"); } diff --git a/Src/Base/CMakeLists.txt b/Src/Base/CMakeLists.txt index 0436ad032e..1ee0b23612 100644 --- a/Src/Base/CMakeLists.txt +++ b/Src/Base/CMakeLists.txt @@ -97,6 +97,7 @@ foreach(D IN LISTS AMReX_SPACEDIM) AMReX_Print.H AMReX_IntConv.H AMReX_IntConv.cpp + AMReX_IOFormat.H # Index space ------------------------------------------------------------- AMReX_Box.H AMReX_Box.cpp diff --git a/Src/Base/Make.package b/Src/Base/Make.package index b009ebf7d6..a8c1d0faaa 100644 --- a/Src/Base/Make.package +++ b/Src/Base/Make.package @@ -121,6 +121,7 @@ C$(AMREX_BASE)_headers += AMReX_ParReduce.H # C${AMREX_BASE}_headers += AMReX_ANSIEscCode.H AMReX_FabConv.H AMReX_FPC.H AMReX_Print.H AMReX_IntConv.H AMReX_VectorIO.H C${AMREX_BASE}_sources += AMReX_FabConv.cpp AMReX_FPC.cpp AMReX_IntConv.cpp AMReX_VectorIO.cpp +C${AMREX_BASE}_headers += AMReX_IOFormat.H # # Index space.