SpECTRE Documentation Coverage Report
Current view: top level - Parallel/Printf - Printf.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 53.8 % 13 7
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines Parallel::printf for writing to stdout
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <cstddef>
      10              : #include <cstdio>
      11              : #include <iomanip>
      12              : #include <limits>
      13              : #include <sstream>
      14              : #include <string>
      15              : #include <type_traits>
      16              : #include <utility>
      17              : #include <vector>
      18              : 
      19              : #include "Utilities/ErrorHandling/FloatingPointExceptions.hpp"
      20              : #include "Utilities/Requires.hpp"
      21              : #include "Utilities/TypeTraits/IsStreamable.hpp"
      22              : 
      23              : /// \cond
      24              : namespace PUP {
      25              : class er;
      26              : }  // namespace PUP
      27              : /// \endcond
      28              : 
      29              : #include "Parallel/Printf/Printf.decl.h"
      30              : 
      31              : namespace Parallel {
      32              : namespace detail {
      33              : /*!
      34              :  * Fundamentals and pointers are already printable so there is no conversion
      35              :  * to a std::string necessary.
      36              :  */
      37              : template <typename T,
      38              :           Requires<std::is_fundamental<std::decay_t<
      39              :                        std::remove_pointer_t<std::decay_t<T>>>>::value or
      40              :                    std::is_pointer<T>::value or
      41              :                    std::is_pointer<std::decay_t<T>>::value> = nullptr>
      42              : inline constexpr T stream_object_to_string(T&& t) {
      43              :   return t;
      44              : }
      45              : 
      46              : /*!
      47              :  * Stream an object of type `T` into a std::stringstream and return it as a
      48              :  * std::string so that it is printable by calling `.c_str()` on it.
      49              :  * We need a 2-phase call so that the std::string doesn't go out of scope before
      50              :  * the C-style string is passed to printf.
      51              :  */
      52              : template <typename T,
      53              :           Requires<std::is_class<std::decay_t<T>>::value or
      54              :                    std::is_enum<std::decay_t<T>>::value> = nullptr>
      55              : inline std::string stream_object_to_string(T&& t) {
      56              :   using ::operator<<;
      57              :   static_assert(tt::is_streamable<std::stringstream, T>::value,
      58              :                 "Cannot stream type and therefore it cannot be printed. Please "
      59              :                 "define a stream operator for the type.");
      60              :   std::stringstream ss;
      61              :   ss << std::setprecision(std::numeric_limits<double>::digits10 + 4)
      62              :      << std::scientific << t;
      63              :   return ss.str();
      64              : }
      65              : 
      66              : /*!
      67              :  * Fundamentals are already printable, so nothing to do.
      68              :  */
      69              : template <typename T,
      70              :           Requires<std::is_fundamental<std::decay_t<
      71              :               std::remove_pointer_t<std::decay_t<T>>>>::value> = nullptr>
      72              : inline constexpr T get_printable_type(T&& t) {
      73              :   return t;
      74              : }
      75              : 
      76              : /*!
      77              :  * Get the pointer of the std::string so it can be passed to CkPrintf which
      78              :  * only works on fundamentals
      79              :  */
      80              : inline const typename std::string::value_type* get_printable_type(
      81              :     const std::string& t) {
      82              :   return t.c_str();
      83              : }
      84              : 
      85              : void send_message(bool error, const std::vector<char>& message);
      86              : void send_message_to_file(const std::string& file,
      87              :                           const std::vector<char>& message);
      88              : 
      89              : template <typename... Ts>
      90              : inline std::vector<char> allocate_message(const char* const format, Ts&&... t) {
      91              : #pragma GCC diagnostic push
      92              : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
      93              : #pragma GCC diagnostic ignored "-Wformat-security"
      94              :   // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
      95              :   const auto length = static_cast<size_t>(snprintf(nullptr, 0, format, t...));
      96              :   std::vector<char> message(length + 1);  // +1 for the null byte
      97              :   // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
      98              :   snprintf(message.data(), message.size(), format, t...);
      99              : #pragma GCC diagnostic pop
     100              :   return message;
     101              : }
     102              : 
     103              : template <typename... Args>
     104              : inline std::vector<char> format_message(const std::string& format,
     105              :                                         Args&&... args) {
     106              :   const ScopedFpeState disable_fpes(false);
     107              :   return allocate_message(
     108              :       format.c_str(),
     109              :       get_printable_type(stream_object_to_string(std::forward<Args>(args)))...);
     110              : }
     111              : }  // namespace detail
     112              : 
     113              : /*!
     114              :  * \ingroup ParallelGroup
     115              :  * \brief Print an atomic message to stdout with C printf usage.
     116              :  *
     117              :  * Similar to Python, you can print any object that's streamable by passing it
     118              :  * in as an argument and using the formatter "%s". For example,
     119              :  * \code
     120              :  * std::vector<double> a{0.8, 73, 9.8};
     121              :  * Parallel::printf("%s\n", a);
     122              :  * \endcode
     123              :  */
     124              : template <typename... Args>
     125            1 : inline void printf(const std::string& format, Args&&... args) {
     126              :   detail::send_message(
     127              :       false, detail::format_message(format, std::forward<Args>(args)...));
     128              : }
     129              : 
     130              : /*!
     131              :  * \ingroup ParallelGroup
     132              :  * \brief Print an atomic message to stderr with C printf usage.
     133              :  *
     134              :  * See Parallel::printf for details.
     135              :  */
     136              : template <typename... Args>
     137            1 : inline void printf_error(const std::string& format, Args&&... args) {
     138              :   detail::send_message(
     139              :       true, detail::format_message(format, std::forward<Args>(args)...));
     140              : }
     141              : 
     142              : /*!
     143              :  * \ingroup ParallelGroup
     144              :  * \brief Print an atomic message to a file with C printf usage.
     145              :  *
     146              :  * See Parallel::printf for details.
     147              :  */
     148              : template <typename... Args>
     149            1 : inline void fprintf(const std::string& file, const std::string& format,
     150              :                     Args&&... args) {
     151              :   detail::send_message_to_file(
     152              :       file, detail::format_message(format, std::forward<Args>(args)...));
     153              : }
     154              : 
     155              : /// Chare outputting all Parallel::printf results.
     156            1 : class PrinterChare : public CBase_PrinterChare {
     157              :  public:
     158            0 :   PrinterChare() = default;
     159            0 :   explicit PrinterChare(CkMigrateMessage* /*msg*/) {}
     160              : 
     161              :   /// Prints a message to stdout or stderr.
     162            1 :   static void print(bool error, const std::vector<char>& message);
     163              : 
     164              :   /// Prints a message to a file.
     165            1 :   static void print_to_file(const std::string& file,
     166              :                             const std::vector<char>& message);
     167              : 
     168            0 :   static void register_with_charm();
     169              : 
     170            0 :   void pup(PUP::er& /*p*/) override {}
     171              : };
     172              : 
     173              : // Charm readonly variables set in Main.
     174              : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     175            0 : extern CProxy_PrinterChare printer_chare;
     176              : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     177            0 : extern bool printer_chare_is_set;
     178              : }  // namespace Parallel
        

Generated by: LCOV version 2.0-1