LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/base - output.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 76 80.3 %
Date: 2026-02-21 11:58:00 Functions: 43 409 10.5 %
Branches: 14 26 53.8 %

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

Generated by: LCOV version 1.14