LCOV - code coverage report
Current view: top level - EnergyPlus - IOFiles.hh (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 78.9 % 209 165
Test Date: 2025-07-17 05:04:31 Functions: 64.5 % 2545 1642

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : #ifndef IOFiles_hh_INCLUDED
      49              : #define IOFiles_hh_INCLUDED
      50              : 
      51              : // C++ Headers
      52              : #include <array>
      53              : #include <cassert>
      54              : #include <fstream>
      55              : #include <iostream>
      56              : #include <limits>
      57              : #include <ostream>
      58              : #include <vector>
      59              : 
      60              : // EnergyPlus Headers
      61              : #include <EnergyPlus/EnergyPlus.hh>
      62              : #include <EnergyPlus/FileSystem.hh>
      63              : 
      64              : // Third Party Headers
      65              : #include <fmt/compile.h>
      66              : #include <fmt/format.h>
      67              : #include <fmt/os.h>
      68              : #include <fmt/ostream.h>
      69              : #include <fmt/printf.h>
      70              : #include <fmt/ranges.h>
      71              : #include <nlohmann/json.hpp>
      72              : 
      73              : namespace {
      74              : struct DoubleWrapper
      75              : {
      76              :     // this cannot be marked explicit
      77              :     // we need the implicit conversion for it to work
      78              :     // clang-format off
      79     16862367 :     DoubleWrapper(double val) : value(val) {};
      80              :     // clang-format on
      81     16862367 :     operator double() const
      82              :     {
      83     16862367 :         return value;
      84              :     };
      85              :     DoubleWrapper &operator=(const double &other)
      86              :     {
      87              :         value = other;
      88              :         return *this;
      89              :     }
      90              : 
      91              : private:
      92              :     double value;
      93              : };
      94              : } // namespace
      95              : 
      96              : namespace fmt {
      97              : template <> struct formatter<DoubleWrapper>
      98              : {
      99              : private:
     100              :     fmt::detail::dynamic_format_specs<char> specs_;
     101              :     const char *format_str_;
     102              :     fmt::memory_buffer buffer = fmt::memory_buffer();
     103              : 
     104              :     struct null_handler : detail::error_handler
     105              :     {
     106     16862367 :         void on_align(align_t)
     107              :         {
     108     16862367 :         }
     109            0 :         void on_sign(sign_t)
     110              :         {
     111            0 :         }
     112      2506894 :         void on_hash()
     113              :         {
     114      2506894 :         }
     115              :     };
     116              : 
     117      2999985 :     static constexpr bool should_be_fixed_output(const double value)
     118              :     {
     119      2999985 :         return (value >= 0.099999999999999995 || value <= -0.099999999999999995) || (value == 0.0) || (value == -0.0);
     120              :     }
     121              : 
     122              :     static constexpr bool fixed_will_fit(const double value, const int places)
     123              :     {
     124              :         if (value < 1.0 && value > -1.0) {
     125              :             return true;
     126              :         } else {
     127              :             return static_cast<int>(std::log10(std::abs(value))) < places;
     128              :         }
     129              :     }
     130              : 
     131       202263 :     static std::string &zero_pad_exponent(std::string &str)
     132              :     {
     133              :         // if necessary, pad the exponent with a 0 to match the old formatting from Objexx
     134       202263 :         if (str.size() > 3) {
     135       202263 :             if (!std::isdigit(str[str.size() - 3])) {
     136              :                 // wants a 0 inserted
     137       202263 :                 str.insert(str.size() - 2, "0");
     138              :             }
     139              :         }
     140       202263 :         return str;
     141              :     }
     142              : 
     143     16862367 :     std::string_view spec_builder()
     144              :     {
     145     16862367 :         buffer.clear();
     146     16862367 :         buffer.push_back('{');
     147     16862367 :         buffer.push_back(':');
     148              :         //    [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
     149              : 
     150              :         //    [[fill]align]
     151     16862367 :         switch (specs_.align) {
     152            0 :         case align_t::left:
     153            0 :             if (specs_.fill.size()) {
     154            0 :                 buffer.append(specs_.fill);
     155              :             }
     156            0 :             buffer.push_back('<');
     157            0 :             break;
     158            0 :         case align_t::right:
     159            0 :             if (specs_.fill.size()) {
     160            0 :                 buffer.append(specs_.fill);
     161              :             }
     162            0 :             buffer.push_back('>');
     163            0 :             break;
     164            0 :         case align_t::center:
     165            0 :             if (specs_.fill.size()) {
     166            0 :                 buffer.append(specs_.fill);
     167              :             }
     168            0 :             buffer.push_back('^');
     169            0 :             break;
     170     16862367 :         case align_t::none:
     171              :         case align_t::numeric:
     172     16862367 :             break;
     173            0 :         default:
     174            0 :             throw fmt::format_error("Bad alignment");
     175              :         }
     176              : 
     177              :         //    [sign]
     178     16862367 :         switch (specs_.sign) {
     179            0 :         case sign_t::plus:
     180            0 :             buffer.push_back('+');
     181            0 :             break;
     182            0 :         case sign_t::minus:
     183            0 :             buffer.push_back('-');
     184            0 :             break;
     185            0 :         case sign_t::space:
     186            0 :             buffer.push_back(' ');
     187            0 :             break;
     188     16862367 :         case sign_t::none:
     189     16862367 :             break;
     190            0 :         default:
     191            0 :             throw fmt::format_error("Bad sign");
     192              :         }
     193              : 
     194              :         //    [alt]
     195     16862367 :         if (specs_.alt) {
     196      2506894 :             buffer.push_back('#');
     197              :         }
     198              : 
     199              :         //    [width]
     200     16862367 :         if (specs_.width >= 0) {
     201     16862367 :             if (specs_.fill[0] == '0') {
     202            0 :                 buffer.push_back('0');
     203              :             }
     204     16862367 :             auto fmt_int = fmt::format_int(specs_.width);
     205     16862367 :             buffer.append(fmt_int.data(), fmt_int.data() + fmt_int.size());
     206              :         }
     207              : 
     208              :         //    [precision]
     209     16862367 :         if (specs_.precision >= 0) {
     210     16861414 :             buffer.push_back('.');
     211              : 
     212     16861414 :             auto fmt_int = fmt::format_int(specs_.precision);
     213     16861414 :             buffer.append(fmt_int.data(), fmt_int.data() + fmt_int.size());
     214              :         }
     215              : 
     216              :         //    [locale]
     217     16862367 :         if (specs_.localized) {
     218            0 :             buffer.push_back('L');
     219              :         }
     220              : 
     221              :         //    [type]
     222     16862367 :         buffer.push_back(specs_.type);
     223              : 
     224     16862367 :         buffer.push_back('}');
     225              : 
     226     16862367 :         return {buffer.data(), buffer.size()};
     227              :     }
     228              : 
     229     16862367 :     template <typename Context> void handle_specs(Context &ctx)
     230              :     {
     231     16862367 :         detail::handle_dynamic_spec<detail::width_checker>(specs_.width, specs_.width_ref, ctx);
     232     16862367 :         detail::handle_dynamic_spec<detail::precision_checker>(specs_.precision, specs_.precision_ref, ctx);
     233     16862367 :     }
     234              : 
     235              : public:
     236     16862367 :     template <typename ParseContext> constexpr auto parse(ParseContext &ctx)
     237              :     {
     238     16862367 :         auto begin = ctx.begin(), end = ctx.end();
     239     16862367 :         format_str_ = begin;
     240     16862367 :         if (begin == end) {
     241          621 :             return begin;
     242              :         }
     243              :         using handler_type = fmt::detail::dynamic_specs_handler<ParseContext>;
     244     16861746 :         auto it = fmt::detail::parse_format_specs(begin, end, handler_type(specs_, ctx));
     245     16861746 :         return it;
     246              :     }
     247              : 
     248     16862367 :     template <typename FormatContext> auto format(const DoubleWrapper &doubleWrapper, FormatContext &ctx)
     249              :     {
     250      3794148 :         const auto next_float = [](const double value) {
     251      3794148 :             if (std::signbit(value)) {
     252        85414 :                 if (value == -0.0) {
     253            0 :                     return value;
     254              :                 } else {
     255        85414 :                     return std::nextafter(value, std::numeric_limits<decltype(value)>::lowest());
     256              :                 }
     257              :             } else {
     258      3708734 :                 if (value == 0.0) {
     259            0 :                     return value;
     260              :                 } else {
     261      3708734 :                     return std::nextafter(value, std::numeric_limits<decltype(value)>::max());
     262              :                 }
     263              :             }
     264              :         };
     265              : 
     266     16862367 :         double val = doubleWrapper;
     267              : 
     268     16862367 :         handle_specs(ctx);
     269     16862367 :         detail::specs_checker<null_handler> checker(null_handler(), detail::mapped_type_constant<double, FormatContext>::value);
     270     16862367 :         checker.on_align(specs_.align);
     271     16862367 :         if (specs_.sign != sign::none) {
     272            0 :             checker.on_sign(specs_.sign);
     273              :         }
     274     16862367 :         if (specs_.alt) {
     275      2506894 :             checker.on_hash();
     276              :         }
     277     16862367 :         if (specs_.precision >= 0) {
     278     16861414 :             checker.end_precision();
     279              :         }
     280              : 
     281     16862367 :         if (specs_.type == 'R') { // matches RoundSigDigits() behavior
     282              :             // push the value up a tad to get the same rounding behavior as Objexx
     283      1686608 :             const auto fixed_output = should_be_fixed_output(val);
     284              : 
     285      1686608 :             if (fixed_output) {
     286      1573700 :                 specs_.type = 'F';
     287              : 
     288      1573700 :                 if (val > 100000.0) {
     289         3969 :                     const auto digits10 = static_cast<int>(std::log10(val));
     290              :                     // we cannot represent this val to the required precision, truncate the floating
     291              :                     // point portion
     292         3969 :                     if (digits10 + specs_.precision >= std::numeric_limits<decltype(val)>::max_digits10) {
     293            3 :                         specs_.precision = 0;
     294            3 :                         spec_builder();
     295              :                         // add '.' to match old RoundSigDigits
     296            3 :                         buffer.push_back('.');
     297            3 :                         std::string_view fmt_buffer(buffer.data(), buffer.size());
     298            6 :                         return fmt::format_to(ctx.out(), fmt_buffer, val);
     299              :                     } else {
     300        11898 :                         return fmt::format_to(ctx.out(), spec_builder(), val);
     301              :                     }
     302              :                 } else {
     303      1569731 :                     if (val == 0.0 || val == -0.0) {
     304      1027953 :                         return fmt::format_to(ctx.out(), spec_builder(), 0.0);
     305              :                     } else {
     306              :                         // nudge up to next rounded val
     307      3681240 :                         return fmt::format_to(ctx.out(), spec_builder(), next_float(next_float(next_float(val))));
     308              :                     }
     309              :                 }
     310              :             } else {
     311       112908 :                 specs_.type = 'E';
     312       112908 :                 auto str = fmt::format(spec_builder(), next_float(val));
     313       225816 :                 return fmt::format_to(ctx.out(), "{}", zero_pad_exponent(str));
     314       112908 :             }
     315     15175759 :         } else if (specs_.type == 'T') { // matches TrimSigDigits behavior
     316      1313377 :             const auto fixed_output = should_be_fixed_output(val);
     317              : 
     318      1313377 :             if (fixed_output) {
     319      1224022 :                 const auto magnitude = std::pow(10, specs_.precision);
     320      1224022 :                 const auto adjusted = (val * magnitude) + 0.0001;
     321      1224022 :                 const auto truncated = std::trunc(adjusted) / magnitude;
     322      1224022 :                 specs_.type = 'F';
     323      3672066 :                 return fmt::format_to(ctx.out(), spec_builder(), truncated);
     324              :             } else {
     325        89355 :                 specs_.type = 'E';
     326        89355 :                 specs_.precision += 2;
     327              : 
     328              :                 // write the `E` formatted float to a std::string
     329        89355 :                 auto str = fmt::format(spec_builder(), val);
     330        89355 :                 str = zero_pad_exponent(str);
     331              : 
     332              :                 // Erase last 2 numbers to truncate the value
     333       178710 :                 const auto E_itr = std::find(begin(str), end(str), 'E');
     334        89355 :                 if (E_itr != str.end()) {
     335       178710 :                     str.erase(std::prev(E_itr, 2), E_itr);
     336              :                 }
     337              : 
     338       178710 :                 return fmt::format_to(ctx.out(), "{}", str);
     339        89355 :             }
     340              :         }
     341     41587146 :         return fmt::format_to(ctx.out(), spec_builder(), val);
     342              :     }
     343              : };
     344              : } // namespace fmt
     345              : 
     346              : namespace EnergyPlus {
     347              : 
     348              : // Forward declarations
     349              : struct EnergyPlusData;
     350              : 
     351              : enum class FormatSyntax
     352              : {
     353              :     Invalid = -1,
     354              :     Fortran,
     355              :     FMT,
     356              :     Printf,
     357              :     Num
     358              : };
     359              : 
     360              : inline constexpr bool is_fortran_syntax(const std::string_view format_str)
     361              : {
     362              :     bool within_fmt_str = false;
     363              :     for (auto const c : format_str) {
     364              :         switch (c) {
     365              :         case '{':
     366              :             within_fmt_str = true;
     367              :             break;
     368              :         case '}':
     369              :             within_fmt_str = false;
     370              :             break;
     371              :         case 'R':
     372              :         case 'T':
     373              :             if (within_fmt_str) {
     374              :                 return true;
     375              :             } else {
     376              :                 break;
     377              :             }
     378              :         default:
     379              :             break;
     380              :         }
     381              :     }
     382              :     return false;
     383              : }
     384              : 
     385              : class InputOutputFile;
     386              : template <FormatSyntax formatSyntax = FormatSyntax::Fortran, typename... Args>
     387              : void print(InputOutputFile &outputFile, std::string_view format_str, Args &&...args);
     388              : 
     389              : inline constexpr FormatSyntax check_syntax(const std::string_view format_str)
     390              : {
     391              :     if (is_fortran_syntax(format_str)) {
     392              :         return FormatSyntax::Fortran;
     393              :     } else {
     394              :         return FormatSyntax::FMT;
     395              :     }
     396              : }
     397              : 
     398              : class InputFile
     399              : {
     400              : public:
     401              :     template <typename Type> struct ReadResult
     402              :     {
     403      2906139 :         ReadResult(Type data_, bool eof_, bool good_) : data{std::move(data_)}, eof{eof_}, good{good_}
     404              :         {
     405      2906139 :         }
     406              : 
     407              :         // Update the current eof/good state from the incoming value
     408              :         // but only update the `data` member if the state is good
     409              :         // The idea is to keep consistency with the operator>> that was used
     410              :         // from gio
     411      2227012 :         void update(ReadResult &&other)
     412              :         {
     413      2227012 :             eof = other.eof;
     414      2227012 :             good = other.good;
     415      2227012 :             if (good) {
     416      2227012 :                 data = std::move(other.data);
     417              :             }
     418      2227012 :         }
     419              : 
     420              :         Type data;
     421              :         bool eof;
     422              :         bool good;
     423              :     };
     424              : 
     425              :     void close();
     426              : 
     427              :     // This is different from istream::good(), which is false if EOF is true while there were no errors (happens when no EOL at end of file)
     428              :     // this operate like `operator bool(istream& is)` <=> `!is.bad() && !is.fail()`
     429              :     bool good() const noexcept;
     430              : 
     431              :     bool is_open() const noexcept;
     432              : 
     433              :     void backspace() noexcept;
     434              : 
     435              :     std::string error_state_to_string() const;
     436              : 
     437              :     // opens the file if it is not currently open and returns
     438              :     // a reference back to itself
     439              :     InputFile &ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file = true);
     440              :     std::istream::iostate rdstate() const noexcept;
     441              : 
     442              :     fs::path filePath;
     443              :     void open(bool = false, bool = true);
     444              :     std::fstream::pos_type position() const noexcept;
     445              : 
     446         1209 :     void rewind() noexcept
     447              :     {
     448         1209 :         if (is) {
     449         1209 :             is->clear(); // clear potentially failbit and badbit (seekg would only clear eofbit)
     450         1209 :             is->seekg(0, std::ios::beg);
     451              :         }
     452         1209 :     }
     453              : 
     454              :     ReadResult<std::string> readLine() noexcept;
     455              : 
     456         6111 :     template <typename T> ReadResult<T> read() noexcept
     457              :     {
     458         6111 :         if (is) {
     459              :             T result;
     460         6111 :             *is >> result;
     461              :             // Use operator bool, see ReadResult::good() docstring
     462         6111 :             return ReadResult<T>{result, is->eof(), bool(is)};
     463              :         } else {
     464            0 :             return ReadResult<T>{T{}, true, false};
     465              :         }
     466              :     }
     467              : 
     468              :     std::string readFile();
     469              : 
     470              :     nlohmann::json readJSON();
     471              : 
     472              :     explicit InputFile(fs::path FilePath);
     473              : 
     474              : private:
     475              :     std::uintmax_t file_size{};
     476              :     std::unique_ptr<std::istream> is;
     477              :     friend class IOFiles;
     478              : };
     479              : 
     480              : class InputOutputFile
     481              : {
     482              : public:
     483              :     fs::path filePath;
     484              :     bool defaultToStdOut = false;
     485              : 
     486              :     void close();
     487              :     void del();
     488              :     bool good() const;
     489              : 
     490              :     // opens the file if it is not currently open and returns
     491              :     // a reference back to itself
     492              :     InputOutputFile &ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file = true);
     493              : 
     494              :     void open(const bool forAppend = false, bool output_to_file = true);
     495              :     std::fstream::pos_type position() const noexcept;
     496              :     std::vector<std::string> getLines();
     497              :     void open_as_stringstream();
     498              :     std::string get_output();
     499              :     void flush();
     500              :     explicit InputOutputFile(fs::path FilePath, const bool DefaultToStdOut = false);
     501              : 
     502              : private:
     503              :     std::unique_ptr<std::iostream> os;
     504              :     bool print_to_dev_null = false;
     505              :     template <FormatSyntax, typename... Args> friend void print(InputOutputFile &outputFile, std::string_view format_str, Args &&...args);
     506              :     friend class IOFiles;
     507              : };
     508              : 
     509              : template <typename FileType> struct IOFilePath
     510              : {
     511              :     fs::path filePath;
     512         1408 :     FileType open(EnergyPlusData &state, const std::string &caller, bool output_to_file = true)
     513              :     {
     514         1408 :         FileType file{filePath};
     515         1408 :         file.ensure_open(state, caller, output_to_file);
     516         1408 :         return file;
     517            0 :     }
     518         2840 :     FileType try_open(bool output_to_file = true)
     519              :     {
     520         2840 :         FileType file{filePath};
     521         2840 :         file.open(false, output_to_file);
     522         2840 :         return file;
     523            0 :     }
     524              : };
     525              : 
     526              : using InputOutputFilePath = IOFilePath<InputOutputFile>;
     527              : using InputFilePath = IOFilePath<InputFile>;
     528              : 
     529              : struct JsonOutputFilePaths
     530              : {
     531              :     fs::path outputJsonFilePath;
     532              :     fs::path outputTSHvacJsonFilePath;
     533              :     fs::path outputTSZoneJsonFilePath;
     534              :     fs::path outputTSJsonFilePath;
     535              :     fs::path outputYRJsonFilePath;
     536              :     fs::path outputMNJsonFilePath;
     537              :     fs::path outputDYJsonFilePath;
     538              :     fs::path outputHRJsonFilePath;
     539              :     fs::path outputSMJsonFilePath;
     540              :     fs::path outputCborFilePath;
     541              :     fs::path outputTSHvacCborFilePath;
     542              :     fs::path outputTSZoneCborFilePath;
     543              :     fs::path outputTSCborFilePath;
     544              :     fs::path outputYRCborFilePath;
     545              :     fs::path outputMNCborFilePath;
     546              :     fs::path outputDYCborFilePath;
     547              :     fs::path outputHRCborFilePath;
     548              :     fs::path outputSMCborFilePath;
     549              :     fs::path outputMsgPackFilePath;
     550              :     fs::path outputTSHvacMsgPackFilePath;
     551              :     fs::path outputTSZoneMsgPackFilePath;
     552              :     fs::path outputTSMsgPackFilePath;
     553              :     fs::path outputYRMsgPackFilePath;
     554              :     fs::path outputMNMsgPackFilePath;
     555              :     fs::path outputDYMsgPackFilePath;
     556              :     fs::path outputHRMsgPackFilePath;
     557              :     fs::path outputSMMsgPackFilePath;
     558              : };
     559              : 
     560              : class IOFiles
     561              : {
     562              : public:
     563              :     struct OutputControl
     564              :     {
     565          803 :         OutputControl() = default;
     566              : 
     567              :         void getInput(EnergyPlusData &state);
     568              :         bool writeTabular(EnergyPlusData &state);
     569              : 
     570              :         bool csv = false;
     571              :         bool mtr = true;
     572              :         bool eso = true;
     573              :         bool eio = true;
     574              :         bool audit = true;
     575              :         bool spsz = true;
     576              :         bool zsz = true;
     577              :         bool ssz = true;
     578              :         bool dxf = true;
     579              :         bool bnd = true;
     580              :         bool rdd = true;
     581              :         bool mdd = true;
     582              :         bool mtd = true;
     583              :         bool end = true;
     584              :         bool shd = true;
     585              :         bool dfs = true;
     586              :         bool glhe = true;
     587              :         bool delightin = true;
     588              :         bool delighteldmp = true;
     589              :         bool delightdfdmp = true;
     590              :         bool edd = true;
     591              :         bool dbg = true;
     592              :         bool perflog = true;
     593              :         bool sln = true;
     594              :         bool sci = true;
     595              :         bool wrl = true;
     596              :         bool screen = true;
     597              :         bool tarcog = true;
     598              :         bool extshd = true;
     599              :         bool json = true;
     600              :         bool tabular = true;
     601              :         bool sqlite = true;
     602              :     };
     603              : 
     604              :     OutputControl outputControl;
     605              : 
     606              :     InputOutputFile audit{"eplusout.audit"};
     607              :     InputOutputFile eio{"eplusout.eio"};
     608              :     InputOutputFile eso{"eplusout.eso"}; // (hourly data only)
     609              : 
     610              :     InputOutputFile zsz{""};
     611              :     fs::path outputZszCsvFilePath{"epluszsz.csv"};
     612              :     fs::path outputZszTabFilePath{"epluszsz.tab"};
     613              :     fs::path outputZszTxtFilePath{"epluszsz.txt"};
     614              : 
     615              :     InputOutputFile spsz{""};
     616              :     fs::path outputSpszCsvFilePath{"eplusspsz.csv"};
     617              :     fs::path outputSpszTabFilePath{"eplusspsz.tab"};
     618              :     fs::path outputSpszTxtFilePath{"eplusspsz.txt"};
     619              : 
     620              :     InputOutputFile ssz{""};
     621              :     fs::path outputSszCsvFilePath{"eplusssz.csv"};
     622              :     fs::path outputSszTabFilePath{"eplusssz.tab"};
     623              :     fs::path outputSszTxtFilePath{"eplusssz.txt"};
     624              : 
     625              :     InputOutputFile map{""};
     626              :     fs::path outputMapCsvFilePath{"eplusmap.csv"};
     627              :     fs::path outputMapTabFilePath{"eplusmap.tab"};
     628              :     fs::path outputMapTxtFilePath{"eplusmap.txt"};
     629              : 
     630              :     InputOutputFile mtr{"eplusout.mtr"};
     631              :     InputOutputFile bnd{"eplusout.bnd"};
     632              :     InputOutputFile rdd{"eplusout.rdd"};
     633              :     InputOutputFile mdd{"eplusout.mdd"};
     634              : 
     635              :     InputOutputFile debug{"eplusout.dbg"};
     636              : 
     637              :     InputOutputFile dfs{"eplusout.dfs"};
     638              : 
     639              :     InputOutputFilePath sln{"eplusout.sln"};
     640              :     InputOutputFilePath dxf{"eplusout.dxf"};
     641              :     InputOutputFilePath sci{"eplusout.sci"};
     642              :     InputOutputFilePath wrl{"eplusout.wrl"};
     643              : 
     644              :     InputOutputFilePath delightIn{"eplusout.delightin"};
     645              : 
     646              :     InputOutputFile mtd{"eplusout.mtd"};
     647              :     InputOutputFile edd{"eplusout.edd", true}; // write to stdout if no file never opened
     648              :     InputOutputFile shade{"eplusshading.csv"};
     649              : 
     650              :     InputOutputFile csv{"eplusout.csv"};
     651              :     InputOutputFile mtr_csv{"eplusmtr.csv"};
     652              : 
     653              :     InputOutputFilePath screenCsv{"eplusscreen.csv"};
     654              :     InputOutputFilePath endFile{"eplusout.end"};
     655              : 
     656              :     InputFilePath iniFile{"EnergyPlus.ini"};
     657              : 
     658              :     InputFilePath outputDelightEldmpFilePath{"eplusout.delighteldmp"};
     659              :     InputFilePath outputDelightDfdmpFilePath{"eplusout.delightdfdmp"};
     660              : 
     661              :     // for transient uses of weather files
     662              :     // also, keeper of the currently set input weather file name
     663              :     InputFilePath inputWeatherFilePath{""};
     664              : 
     665              :     // for the persistent weather simulation, using the EPW
     666              :     // uses the file name set in `inputWeatherFilePath`
     667              :     InputFile inputWeatherFile{""};
     668              : 
     669              :     InputFilePath TempFullFilePath{""};
     670              :     InputFilePath inStatFilePath{""};
     671              : 
     672              :     fs::path outputErrFilePath{"eplusout.err"};
     673              :     std::unique_ptr<std::ostream> err_stream;
     674              : 
     675              :     JsonOutputFilePaths json; // Internal streams used for json outputs
     676              : 
     677              :     void flushAll(); // For RunningEnergyPlusViaAPI only
     678              : };
     679              : 
     680              : class SharedFileHandle
     681              : {
     682              :     std::shared_ptr<InputOutputFile> file;
     683         3322 :     InputOutputFile *ptr()
     684              :     {
     685         3322 :         if (!file) {
     686            9 :             file = std::make_shared<InputOutputFile>("");
     687              :         }
     688              : 
     689         3322 :         return file.get();
     690              :     }
     691              : 
     692              : public:
     693         3295 :     InputOutputFile &operator*()
     694              :     {
     695         3295 :         return *ptr();
     696              :     }
     697              : 
     698           27 :     InputOutputFile *operator->()
     699              :     {
     700           27 :         return ptr();
     701              :     }
     702              : };
     703              : 
     704      6829067 : template <typename... Args> void vprint(std::ostream &os, std::string_view format_str, const Args &...args)
     705              : {
     706              :     //    assert(os.good());
     707     13658134 :     auto buffer = fmt::memory_buffer();
     708              :     try {
     709      6829067 :         fmt::format_to(std::back_inserter(buffer), format_str, args...);
     710            0 :     } catch (const fmt::format_error &) {
     711            0 :         throw EnergyPlus::FatalError(fmt::format("Error with format, '{}', passed {} args", format_str, sizeof...(Args)));
     712              :     }
     713      6829067 :     os.write(buffer.data(), buffer.size());
     714      6829067 : }
     715              : 
     716     21553015 : template <typename... Args> std::string vprint(std::string_view format_str, const Args &...args)
     717              : {
     718     43106030 :     auto buffer = fmt::memory_buffer();
     719              :     try {
     720     21553036 :         fmt::format_to(std::back_inserter(buffer), format_str, args...);
     721           42 :     } catch (const fmt::format_error &) {
     722           42 :         throw EnergyPlus::FatalError(fmt::format("Error with format, '{}', passed {} args", format_str, sizeof...(Args)));
     723              :     }
     724     43105988 :     return fmt::to_string(buffer);
     725     21553015 : }
     726              : 
     727              : // Uses lib {fmt} (which has been accepted for C++20)
     728              : // Formatting syntax guide is here: https://fmt.dev/latest/syntax.html
     729              : // The syntax is similar to printf, but uses {} to indicate parameters to be formatted
     730              : // you must escape any {} that you want with {}, like `{{}}`
     731              : //
     732              : // Defines a custom formatting type 'R' (round_ which chooses between `E` and `G` depending
     733              : // on the value being printed.
     734              : // This is necessary for parity with the old "RoundSigDigits" utility function
     735              : //
     736              : // Defines a custom formatting type 'T' that that truncates the value
     737              : // to match the behavior of TrimSigDigits utility function
     738              : //
     739              : 
     740              : namespace {
     741      6829067 :     template <typename... Args> void print_fortran_syntax(std::ostream &os, std::string_view format_str, const Args &...args)
     742              :     {
     743      6829067 :         EnergyPlus::vprint<std::conditional_t<std::is_same_v<double, Args>, DoubleWrapper, Args>...>(os, format_str, args...);
     744      6829067 :     }
     745              : 
     746     21553015 :     template <typename... Args> std::string format_fortran_syntax(std::string_view format_str, const Args &...args)
     747              :     {
     748     21553015 :         return EnergyPlus::vprint<std::conditional_t<std::is_same_v<double, Args>, DoubleWrapper, Args>...>(format_str, args...);
     749              :     }
     750              : } // namespace
     751              : 
     752              : template <FormatSyntax formatSyntax = FormatSyntax::Fortran, typename... Args>
     753              : void print(std::ostream &os, std::string_view format_str, Args &&...args)
     754              : {
     755              :     if constexpr (formatSyntax == FormatSyntax::Fortran) {
     756              :         print_fortran_syntax(os, format_str, args...);
     757              :     } else if constexpr (formatSyntax == FormatSyntax::FMT) {
     758              :         fmt::print(os, format_str, std::forward<Args>(args)...);
     759              :     } else {
     760              :         static_assert(!(formatSyntax == FormatSyntax::Fortran || formatSyntax == FormatSyntax::FMT), "Invalid FormatSyntax selection");
     761              :     }
     762              : }
     763              : 
     764     23752300 : template <FormatSyntax formatSyntax, typename... Args> void print(InputOutputFile &outputFile, std::string_view format_str, Args &&...args)
     765              : {
     766     71256900 :     auto *outputStream = [&]() -> std::ostream * {
     767     23752300 :         if (outputFile.os) {
     768     23752300 :             return outputFile.os.get();
     769              :         } else {
     770            0 :             if (outputFile.defaultToStdOut) {
     771            0 :                 return &std::cout;
     772              :             } else {
     773            0 :                 assert(outputFile.os);
     774            0 :                 return nullptr;
     775              :             }
     776              :         }
     777     23752300 :     }();
     778              :     if constexpr (formatSyntax == FormatSyntax::Fortran) {
     779      6829067 :         print_fortran_syntax(*outputStream, format_str, args...);
     780              :     } else if constexpr (formatSyntax == FormatSyntax::FMT) {
     781     16923233 :         fmt::print(*outputStream, format_str, std::forward<Args>(args)...);
     782              :     } else {
     783              :         static_assert(!(formatSyntax == FormatSyntax::Fortran || formatSyntax == FormatSyntax::FMT), "Invalid FormatSyntax selection");
     784              :     }
     785     23752300 : }
     786              : 
     787     23534042 : template <FormatSyntax formatSyntax = FormatSyntax::Fortran, typename... Args> std::string format(std::string_view format_str, Args &&...args)
     788              : {
     789              :     if constexpr (formatSyntax == FormatSyntax::Fortran) {
     790     21553015 :         return format_fortran_syntax(format_str, args...);
     791              :     } else if constexpr (formatSyntax == FormatSyntax::FMT) {
     792      3962054 :         return fmt::format(format_str, std::forward<Args>(args)...);
     793              :     } else if constexpr (formatSyntax == FormatSyntax::Printf) {
     794              :         return fmt::sprintf(format_str, std::forward<Args>(args)...);
     795              :     }
     796              : }
     797              : 
     798              : } // namespace EnergyPlus
     799              : 
     800              : // extern template the most commonly used format function calls
     801              : // to save on compilation time. They will be explicitly instantiated
     802              : // in IOFiles.cc
     803              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int>(std::string_view, int &&);
     804              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const char *const &>(std::string_view, const char *const &);
     805              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string &>(std::string_view, int &, std::string &);
     806              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, std::string &, double &>(
     807              :     std::string_view, std::string &, std::string &, std::string &, double &);
     808              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &>(std::string_view,
     809              :                                                                                                             const std::string_view &);
     810              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &, std::string &>(std::string_view,
     811              :                                                                                                                            const std::string_view &,
     812              :                                                                                                                            std::string &);
     813              : extern template std::string
     814              : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, double &>(std::string_view, std::string &, double &, double &);
     815              : extern template std::string
     816              : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, int &>(std::string_view, std::string &, std::string &, int &);
     817              : extern template std::string
     818              : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &, double &>(std::string_view, double &, double &, double &);
     819              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, std::string &>(std::string_view, double &, std::string &);
     820              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &>(std::string_view, std::string &);
     821              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &, int &>(std::string_view, const int &, int &);
     822              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double>(std::string_view, double &&);
     823              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &>(std::string_view, int &, int &);
     824              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const double &>(std::string_view, const double &);
     825              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, int &>(std::string_view, std::string &, int &);
     826              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, double &>(std::string_view,
     827              :                                                                                                                           std::string &,
     828              :                                                                                                                           std::string &,
     829              :                                                                                                                           double &);
     830              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, std::string &, double &>(
     831              :     std::string_view, std::string &, double &, std::string &, double &);
     832              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &>(std::string_view, const int &);
     833              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, const std::string &, std::string &>(std::string_view,
     834              :                                                                                                                              int &,
     835              :                                                                                                                              const std::string &,
     836              :                                                                                                                              std::string &);
     837              : extern template std::string
     838              : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, const std::string &>(std::string_view, int &, int &, const std::string &);
     839              : extern template std::string
     840              : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, std::string_view &>(std::string_view, int &, int &, std::string_view &);
     841              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string_view &, std::string &>(std::string_view,
     842              :                                                                                                                             int &,
     843              :                                                                                                                             std::string_view &,
     844              :                                                                                                                             std::string &);
     845              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &>(std::string_view, double &, double &);
     846              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &>(std::string_view, int &);
     847              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &>(std::string_view, std::string &, double &);
     848              : extern template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &>(std::string_view, double &);
     849              : 
     850              : #endif
        

Generated by: LCOV version 2.0-1