LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/base - output.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 66 81 81.5 %
Date: 2026-04-14 10:42:21 Functions: 43 409 10.5 %
Branches: 14 26 53.8 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Output utility classes and functions.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "cvc5_private_library.h"
      14                 :            : 
      15                 :            : #ifndef CVC5__OUTPUT_H
      16                 :            : #define CVC5__OUTPUT_H
      17                 :            : 
      18                 :            : #include <cvc5/cvc5_export.h>
      19                 :            : 
      20                 :            : #include <algorithm>
      21                 :            : #include <cstdio>
      22                 :            : #include <ios>
      23                 :            : #include <iostream>
      24                 :            : #include <set>
      25                 :            : #include <string>
      26                 :            : #include <utility>
      27                 :            : #include <vector>
      28                 :            : 
      29                 :            : namespace cvc5::internal {
      30                 :            : 
      31                 :            : template <class T, class U>
      32                 :          0 : std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p)
      33                 :            : {
      34                 :          0 :   return out << "[" << p.first << "," << p.second << "]";
      35                 :            : }
      36                 :            : 
      37                 :            : /**
      38                 :            :  * A utility class to provide (essentially) a "/dev/null" streambuf.
      39                 :            :  * If debugging support is compiled in, but debugging for
      40                 :            :  * e.g. "parser" is off, then Trace("parser") returns a stream
      41                 :            :  * attached to a null_streambuf instance so that output is directed to
      42                 :            :  * the bit bucket.
      43                 :            :  */
      44                 :            : class null_streambuf : public std::streambuf
      45                 :            : {
      46                 :            :  public:
      47                 :            :   /* Overriding overflow() just ensures that EOF isn't returned on the
      48                 :            :    * stream.  Perhaps this is not so critical, but recommended; this
      49                 :            :    * way the output stream looks like it's functioning, in a non-error
      50                 :            :    * state. */
      51                 :   75064429 :   int overflow(int c) override { return c; }
      52                 :            : }; /* class null_streambuf */
      53                 :            : 
      54                 :            : /** A null stream-buffer singleton */
      55                 :            : extern null_streambuf null_sb;
      56                 :            : /** A null output stream singleton */
      57                 :            : extern std::ostream null_os CVC5_EXPORT;
      58                 :            : 
      59                 :            : class Cvc5ostream
      60                 :            : {
      61                 :            :   static const std::string s_tab CVC5_EXPORT;
      62                 :            :   static const int s_indentIosIndex CVC5_EXPORT;
      63                 :            : 
      64                 :            :   /** The underlying ostream */
      65                 :            :   std::ostream* d_os;
      66                 :            :   /** Are we in the first column? */
      67                 :            :   bool d_firstColumn;
      68                 :            : 
      69                 :            :   /** The endl manipulator (why do we need to keep this?) */
      70                 :            :   std::ostream& (*const d_endl)(std::ostream&);
      71                 :            : 
      72                 :            :   Cvc5ostream(const Cvc5ostream&) = delete;
      73                 :            :   Cvc5ostream& operator=(const Cvc5ostream&) = delete;
      74                 :            : 
      75                 :            :  public:
      76                 :            :   Cvc5ostream() : d_os(nullptr), d_firstColumn(false), d_endl(&std::endl) {}
      77                 :      59161 :   explicit Cvc5ostream(std::ostream* os)
      78                 :      59161 :       : d_os(os), d_firstColumn(true), d_endl(&std::endl)
      79                 :            :   {
      80                 :      59161 :   }
      81                 :            : 
      82                 :         87 :   void reset(std::ostream* os)
      83                 :            :   {
      84                 :         87 :     d_os = os;
      85                 :         87 :     d_firstColumn = (os != nullptr);
      86                 :         87 :   }
      87                 :            : 
      88                 :     235944 :   void pushIndent()
      89                 :            :   {
      90         [ -  + ]:     235944 :     if (d_os != nullptr)
      91                 :            :     {
      92                 :          0 :       ++d_os->iword(s_indentIosIndex);
      93                 :            :     }
      94                 :     235944 :   }
      95                 :     235944 :   void popIndent()
      96                 :            :   {
      97         [ -  + ]:     235944 :     if (d_os != nullptr)
      98                 :            :     {
      99                 :          0 :       long& indent = d_os->iword(s_indentIosIndex);
     100         [ -  - ]:          0 :       if (indent > 0)
     101                 :            :       {
     102                 :          0 :         --indent;
     103                 :            :       }
     104                 :            :     }
     105                 :     235944 :   }
     106                 :            : 
     107                 :            :   Cvc5ostream& flush()
     108                 :            :   {
     109                 :            :     if (d_os != nullptr)
     110                 :            :     {
     111                 :            :       d_os->flush();
     112                 :            :     }
     113                 :            :     return *this;
     114                 :            :   }
     115                 :            : 
     116                 :          0 :   bool isConnected() const { return d_os != nullptr; }
     117         [ -  - ]:          0 :   operator std::ostream&() const { return isConnected() ? *d_os : null_os; }
     118                 :            : 
     119                 :            :   std::ostream* getStreamPointer() const { return d_os; }
     120                 :            : 
     121                 :            :   template <class T>
     122                 :        698 :   Cvc5ostream& operator<<(T const& t)
     123                 :            :   {
     124         [ +  - ]:        698 :     if (d_os != nullptr)
     125                 :            :     {
     126         [ +  + ]:        698 :       if (d_firstColumn)
     127                 :            :       {
     128                 :        178 :         d_firstColumn = false;
     129                 :        178 :         long indent = d_os->iword(s_indentIosIndex);
     130         [ -  + ]:        178 :         for (long i = 0; i < indent; ++i)
     131                 :            :         {
     132                 :          0 :           d_os = &(*d_os << s_tab);
     133                 :            :         }
     134                 :            :       }
     135                 :        698 :       *d_os << t;
     136                 :            :     }
     137                 :        698 :     return *this;
     138                 :            :   }
     139                 :            : 
     140                 :            :   // support manipulators, endl, etc..
     141                 :        172 :   Cvc5ostream& operator<<(std::ostream& (*pf)(std::ostream&))
     142                 :            :   {
     143         [ +  - ]:        172 :     if (d_os != nullptr)
     144                 :            :     {
     145                 :        172 :       d_os = &(*d_os << pf);
     146                 :            : 
     147         [ +  - ]:        172 :       if (pf == d_endl)
     148                 :            :       {
     149                 :        172 :         d_firstColumn = true;
     150                 :            :       }
     151                 :            :     }
     152                 :        172 :     return *this;
     153                 :            :   }
     154                 :            :   Cvc5ostream& operator<<(std::ios& (*pf)(std::ios&))
     155                 :            :   {
     156                 :            :     if (d_os != nullptr)
     157                 :            :     {
     158                 :            :       d_os = &(*d_os << pf);
     159                 :            :     }
     160                 :            :     return *this;
     161                 :            :   }
     162                 :          0 :   Cvc5ostream& operator<<(std::ios_base& (*pf)(std::ios_base&))
     163                 :            :   {
     164         [ -  - ]:          0 :     if (d_os != nullptr)
     165                 :            :     {
     166                 :          0 :       d_os = &(*d_os << pf);
     167                 :            :     }
     168                 :          0 :     return *this;
     169                 :            :   }
     170                 :     471888 :   Cvc5ostream& operator<<(Cvc5ostream& (*pf)(Cvc5ostream&))
     171                 :            :   {
     172                 :     471888 :     return pf(*this);
     173                 :            :   }
     174                 :            : }; /* class Cvc5ostream */
     175                 :            : 
     176                 :     235944 : inline Cvc5ostream& push(Cvc5ostream& stream)
     177                 :            : {
     178                 :     235944 :   stream.pushIndent();
     179                 :     235944 :   return stream;
     180                 :            : }
     181                 :            : 
     182                 :     235944 : inline Cvc5ostream& pop(Cvc5ostream& stream)
     183                 :            : {
     184                 :     235944 :   stream.popIndent();
     185                 :     235944 :   return stream;
     186                 :            : }
     187                 :            : 
     188                 :            : /**
     189                 :            :  * Does nothing; designed for compilation of non-debug/non-trace
     190                 :            :  * builds.  None of these should ever be called in such builds, but we
     191                 :            :  * offer this to the compiler so it doesn't complain.
     192                 :            :  */
     193                 :            : class NullC
     194                 :            : {
     195                 :            :   mutable Cvc5ostream d_null;
     196                 :            : 
     197                 :            :  public:
     198                 :      29540 :   NullC() : d_null(nullptr) {}
     199                 :        564 :   operator bool() const { return false; }
     200                 :12357674524 :   operator Cvc5ostream&() const { return d_null; }
     201                 :          0 :   operator std::ostream&() const { return null_os; }
     202                 :            : }; /* class NullC */
     203                 :            : 
     204                 :            : extern NullC nullStream CVC5_EXPORT;
     205                 :            : 
     206                 :            : /** The warning output class */
     207                 :            : class WarningC
     208                 :            : {
     209                 :            :   std::set<std::pair<std::string, size_t> > d_alreadyWarned;
     210                 :            :   std::ostream* d_os;
     211                 :            : 
     212                 :            :  public:
     213                 :      29540 :   explicit WarningC(std::ostream* os) : d_os(os) {}
     214                 :            : 
     215                 :         81 :   Cvc5ostream operator()() const { return Cvc5ostream(d_os); }
     216                 :            : 
     217                 :        874 :   std::ostream& setStream(std::ostream* os)
     218                 :            :   {
     219                 :        874 :     d_os = os;
     220                 :        874 :     return *d_os;
     221                 :            :   }
     222                 :            :   std::ostream& getStream() const { return *d_os; }
     223                 :            :   std::ostream* getStreamPointer() const { return d_os; }
     224                 :            : 
     225                 :        239 :   bool isOn() const { return d_os != &null_os; }
     226                 :            : 
     227                 :            :   // This function supports the WarningOnce() macro, which allows you
     228                 :            :   // to easily indicate that a warning should be emitted, but only
     229                 :            :   // once for a given run of cvc5.
     230                 :            :   bool warnOnce(const std::string& file, size_t line)
     231                 :            :   {
     232                 :            :     std::pair<std::string, size_t> pr = std::make_pair(file, line);
     233                 :            :     if (d_alreadyWarned.find(pr) != d_alreadyWarned.end())
     234                 :            :     {
     235                 :            :       // signal caller not to warn again
     236                 :            :       return false;
     237                 :            :     }
     238                 :            : 
     239                 :            :     // okay warn this time, but don't do it again
     240                 :            :     d_alreadyWarned.insert(pr);
     241                 :            :     return true;
     242                 :            :   }
     243                 :            : 
     244                 :            : }; /* class WarningC */
     245                 :            : 
     246                 :            : /** The trace output class */
     247                 :            : class TraceC
     248                 :            : {
     249                 :            :   std::ostream* d_os;
     250                 :            :   std::vector<std::string> d_tags;
     251                 :            :   mutable Cvc5ostream d_stream;
     252                 :            : 
     253                 :            :  public:
     254                 :      29540 :   explicit TraceC(std::ostream* os) : d_os(os), d_stream(os) {}
     255                 :            : 
     256                 :         87 :   Cvc5ostream& operator()() const
     257                 :            :   {
     258                 :         87 :     d_stream.reset(d_os);
     259                 :         87 :     return d_stream;
     260                 :            :   }
     261                 :            :   Cvc5ostream& operator()(const std::string& tag) const
     262                 :            :   {
     263                 :            :     if (isOn(tag))
     264                 :            :     {
     265                 :            :       d_stream.reset(d_os);
     266                 :            :     }
     267                 :            :     else
     268                 :            :     {
     269                 :            :       d_stream.reset(nullptr);
     270                 :            :     }
     271                 :            :     return d_stream;
     272                 :            :   }
     273                 :            : 
     274                 :         29 :   bool on(const std::string& tag)
     275                 :            :   {
     276                 :         29 :     d_tags.emplace_back(tag);
     277                 :         29 :     return true;
     278                 :            :   }
     279                 :          3 :   bool off(const std::string& tag)
     280                 :            :   {
     281                 :          3 :     auto it = std::find(d_tags.begin(), d_tags.end(), tag);
     282         [ +  + ]:          3 :     if (it != d_tags.end())
     283                 :            :     {
     284                 :          2 :       *it = d_tags.back();
     285                 :          2 :       d_tags.pop_back();
     286                 :            :     }
     287                 :          3 :     return false;
     288                 :            :   }
     289                 :            : 
     290                 :13917853616 :   bool isOn(const std::string& tag) const
     291                 :            :   {
     292                 :            :     // This is faster than using std::set::find() or sorting the vector and
     293                 :            :     // using std::lower_bound.
     294                 :13917853616 :     return !d_tags.empty()
     295 [ +  + ][ +  + ]:13917853616 :            && std::find(d_tags.begin(), d_tags.end(), tag) != d_tags.end();
     296                 :            :   }
     297                 :            : 
     298                 :          5 :   std::ostream& setStream(std::ostream* os)
     299                 :            :   {
     300                 :          5 :     d_os = os;
     301                 :          5 :     return *d_os;
     302                 :            :   }
     303                 :          0 :   std::ostream& getStream() const { return *d_os; }
     304                 :            :   std::ostream* getStreamPointer() const { return d_os; }
     305                 :            : 
     306                 :            : }; /* class TraceC */
     307                 :            : 
     308                 :            : /** The warning output singleton */
     309                 :            : extern WarningC WarningChannel CVC5_EXPORT;
     310                 :            : /** The trace output singleton */
     311                 :            : extern TraceC TraceChannel CVC5_EXPORT;
     312                 :            : 
     313                 :            : #ifdef CVC5_MUZZLE
     314                 :            : 
     315                 :            : #define Warning                                              \
     316                 :            :   cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
     317                 :            :                                 : cvc5::internal::WarningChannel
     318                 :            : #define WarningOnce                                          \
     319                 :            :   cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
     320                 :            :                                 : cvc5::internal::WarningChannel
     321                 :            : #define TraceIsOn \
     322                 :            :   cvc5::internal::__cvc5_true() ? false : cvc5::internal::TraceChannel.isOn
     323                 :            : #define Trace(tag)                                           \
     324                 :            :   cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
     325                 :            :                                 : cvc5::internal::TraceChannel()
     326                 :            : 
     327                 :            : #else /* CVC5_MUZZLE */
     328                 :            : 
     329                 :            : #define Warning                                                         \
     330                 :            :   (!cvc5::internal::WarningChannel.isOn()) ? cvc5::internal::nullStream \
     331                 :            :                                            : cvc5::internal::WarningChannel
     332                 :            : #define WarningOnce                                                 \
     333                 :            :   (!cvc5::internal::WarningChannel.isOn()                           \
     334                 :            :    || !cvc5::internal::WarningChannel.warnOnce(__FILE__, __LINE__)) \
     335                 :            :       ? cvc5::internal::nullStream                                  \
     336                 :            :       : cvc5::internal::WarningChannel
     337                 :            : #ifdef CVC5_TRACING
     338                 :            : #define TraceIsOn cvc5::internal::TraceChannel.isOn
     339                 :            : #define Trace(tag)                                                     \
     340                 :            :   !cvc5::internal::TraceChannel.isOn(tag) ? cvc5::internal::nullStream \
     341                 :            :                                           : cvc5::internal::TraceChannel()
     342                 :            : #else /* CVC5_TRACING */
     343                 :            : #define TraceIsOn \
     344                 :            :   cvc5::internal::__cvc5_true() ? false : cvc5::internal::TraceChannel.isOn
     345                 :            : #define Trace(tag)                                           \
     346                 :            :   cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
     347                 :            :                                 : cvc5::internal::TraceChannel()
     348                 :            : #endif /* CVC5_TRACING */
     349                 :            : 
     350                 :            : #endif /* CVC5_MUZZLE */
     351                 :            : 
     352                 :            : // Disallow e.g. !Trace("foo").isOn() forms
     353                 :            : // because the ! will apply before the ? .
     354                 :            : // If a compiler error has directed you here,
     355                 :            : // just parenthesize it e.g. !(Trace("foo").isOn())
     356                 :            : class __cvc5_true
     357                 :            : {
     358                 :            :   CVC5_UNUSED void operator!();
     359                 :            :   CVC5_UNUSED void operator~();
     360                 :            :   CVC5_UNUSED void operator-();
     361                 :            :   CVC5_UNUSED void operator+();
     362                 :            : 
     363                 :            :  public:
     364                 :            :   inline operator bool() { return true; }
     365                 :            : }; /* __cvc5_true */
     366                 :            : 
     367                 :            : /**
     368                 :            :  * Pushes an indentation level on construction, pop on destruction.
     369                 :            :  * Useful for tracing recursive functions especially, but also can be
     370                 :            :  * used for clearly separating different phases of an algorithm,
     371                 :            :  * or iterations of a loop, or... etc.
     372                 :            :  */
     373                 :            : class IndentedScope
     374                 :            : {
     375                 :            :   Cvc5ostream& d_out;
     376                 :            : 
     377                 :            :  public:
     378                 :     235944 :   inline IndentedScope(Cvc5ostream& out) : d_out(out) { d_out << push; }
     379                 :     235944 :   inline ~IndentedScope() { d_out << pop; }
     380                 :            : }; /* class IndentedScope */
     381                 :            : 
     382                 :            : }  // namespace cvc5::internal
     383                 :            : 
     384                 :            : #endif /* CVC5__OUTPUT_H */

Generated by: LCOV version 1.14