SpECTRE Documentation Coverage Report
Current view: top level - Parallel/Printf - Printf.hpp Hit Total Coverage
Commit: 965048f86d23c819715b3af1ca3f880c8145d4bb Lines: 7 13 53.8 %
Date: 2024-05-16 17:00:40
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 1.14