cvc5-cvc5-1.2.0.src.base.output.h Maven / Gradle / Ivy
The newest version!
/******************************************************************************
* Top contributors (to current version):
* Morgan Deters, Mathias Preiner, Andres Noetzli
*
* This file is part of the cvc5 project.
*
* Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
* in the top-level source directory and their institutional affiliations.
* All rights reserved. See the file COPYING in the top-level source
* directory for licensing information.
* ****************************************************************************
*
* Output utility classes and functions.
*/
#include "cvc5_private_library.h"
#ifndef CVC5__OUTPUT_H
#define CVC5__OUTPUT_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace cvc5::internal {
template
std::ostream& operator<<(std::ostream& out, const std::pair& p) {
return out << "[" << p.first << "," << p.second << "]";
}
/**
* A utility class to provide (essentially) a "/dev/null" streambuf.
* If debugging support is compiled in, but debugging for
* e.g. "parser" is off, then Trace("parser") returns a stream
* attached to a null_streambuf instance so that output is directed to
* the bit bucket.
*/
class null_streambuf : public std::streambuf
{
public:
/* Overriding overflow() just ensures that EOF isn't returned on the
* stream. Perhaps this is not so critical, but recommended; this
* way the output stream looks like it's functioning, in a non-error
* state. */
int overflow(int c) override { return c; }
}; /* class null_streambuf */
/** A null stream-buffer singleton */
extern null_streambuf null_sb;
/** A null output stream singleton */
extern std::ostream null_os CVC5_EXPORT;
class Cvc5ostream
{
static const std::string s_tab CVC5_EXPORT;
static const int s_indentIosIndex CVC5_EXPORT;
/** The underlying ostream */
std::ostream* d_os;
/** Are we in the first column? */
bool d_firstColumn;
/** The endl manipulator (why do we need to keep this?) */
std::ostream& (*const d_endl)(std::ostream&);
// do not allow use
Cvc5ostream& operator=(const Cvc5ostream&);
public:
Cvc5ostream() : d_os(NULL), d_firstColumn(false), d_endl(&std::endl) {}
explicit Cvc5ostream(std::ostream* os)
: d_os(os), d_firstColumn(true), d_endl(&std::endl)
{
}
void pushIndent() {
if(d_os != NULL) {
++d_os->iword(s_indentIosIndex);
}
}
void popIndent() {
if(d_os != NULL) {
long& indent = d_os->iword(s_indentIosIndex);
if(indent > 0) {
--indent;
}
}
}
Cvc5ostream& flush()
{
if(d_os != NULL) {
d_os->flush();
}
return *this;
}
bool isConnected() const { return d_os != NULL; }
operator std::ostream&() const { return isConnected() ? *d_os : null_os; }
std::ostream* getStreamPointer() const { return d_os; }
template
Cvc5ostream& operator<<(T const& t)
{
if (d_os != nullptr)
{
if (d_firstColumn)
{
d_firstColumn = false;
long indent = d_os->iword(s_indentIosIndex);
for (long i = 0; i < indent; ++i)
{
d_os = &(*d_os << s_tab);
}
}
*d_os << t;
}
return *this;
}
// support manipulators, endl, etc..
Cvc5ostream& operator<<(std::ostream& (*pf)(std::ostream&))
{
if(d_os != NULL) {
d_os = &(*d_os << pf);
if(pf == d_endl) {
d_firstColumn = true;
}
}
return *this;
}
Cvc5ostream& operator<<(std::ios& (*pf)(std::ios&))
{
if(d_os != NULL) {
d_os = &(*d_os << pf);
}
return *this;
}
Cvc5ostream& operator<<(std::ios_base& (*pf)(std::ios_base&))
{
if(d_os != NULL) {
d_os = &(*d_os << pf);
}
return *this;
}
Cvc5ostream& operator<<(Cvc5ostream& (*pf)(Cvc5ostream&))
{
return pf(*this);
}
}; /* class Cvc5ostream */
inline Cvc5ostream& push(Cvc5ostream& stream)
{
stream.pushIndent();
return stream;
}
inline Cvc5ostream& pop(Cvc5ostream& stream)
{
stream.popIndent();
return stream;
}
/**
* Does nothing; designed for compilation of non-debug/non-trace
* builds. None of these should ever be called in such builds, but we
* offer this to the compiler so it doesn't complain.
*/
class NullC
{
public:
operator bool() const { return false; }
operator Cvc5ostream() const { return Cvc5ostream(); }
operator std::ostream&() const { return null_os; }
}; /* class NullC */
extern NullC nullStream CVC5_EXPORT;
/** The warning output class */
class WarningC
{
std::set > d_alreadyWarned;
std::ostream* d_os;
public:
explicit WarningC(std::ostream* os) : d_os(os) {}
Cvc5ostream operator()() const { return Cvc5ostream(d_os); }
std::ostream& setStream(std::ostream* os) { d_os = os; return *d_os; }
std::ostream& getStream() const { return *d_os; }
std::ostream* getStreamPointer() const { return d_os; }
bool isOn() const { return d_os != &null_os; }
// This function supports the WarningOnce() macro, which allows you
// to easily indicate that a warning should be emitted, but only
// once for a given run of cvc5.
bool warnOnce(const std::string& file, size_t line)
{
std::pair pr = std::make_pair(file, line);
if(d_alreadyWarned.find(pr) != d_alreadyWarned.end()) {
// signal caller not to warn again
return false;
}
// okay warn this time, but don't do it again
d_alreadyWarned.insert(pr);
return true;
}
}; /* class WarningC */
/** The trace output class */
class TraceC
{
std::ostream* d_os;
std::vector d_tags;
public:
explicit TraceC(std::ostream* os) : d_os(os) {}
Cvc5ostream operator()() const
{
return Cvc5ostream(d_os);
}
Cvc5ostream operator()(const std::string& tag) const
{
if (isOn(tag)) {
return Cvc5ostream(d_os);
} else {
return Cvc5ostream();
}
}
bool on(const std::string& tag)
{
d_tags.emplace_back(tag);
return true;
}
bool off(const std::string& tag)
{
auto it = std::find(d_tags.begin(), d_tags.end(), tag);
if (it != d_tags.end())
{
*it = d_tags.back();
d_tags.pop_back();
}
return false;
}
bool isOn(const std::string& tag) const
{
// This is faster than using std::set::find() or sorting the vector and
// using std::lower_bound.
return !d_tags.empty() && std::find(d_tags.begin(), d_tags.end(), tag) != d_tags.end();
}
std::ostream& setStream(std::ostream* os) { d_os = os; return *d_os; }
std::ostream& getStream() const { return *d_os; }
std::ostream* getStreamPointer() const { return d_os; }
}; /* class TraceC */
/** The warning output singleton */
extern WarningC WarningChannel CVC5_EXPORT;
/** The trace output singleton */
extern TraceC TraceChannel CVC5_EXPORT;
#ifdef CVC5_MUZZLE
#define Warning \
cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
: cvc5::internal::WarningChannel
#define WarningOnce \
cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
: cvc5::internal::WarningChannel
#define TraceIsOn \
cvc5::internal::__cvc5_true() ? false : cvc5::internal::TraceChannel.isOn
#define Trace(tag) \
cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
: cvc5::internal::TraceChannel()
#else /* CVC5_MUZZLE */
#define Warning \
(!cvc5::internal::WarningChannel.isOn()) ? cvc5::internal::nullStream \
: cvc5::internal::WarningChannel
#define WarningOnce \
(!cvc5::internal::WarningChannel.isOn() \
|| !cvc5::internal::WarningChannel.warnOnce(__FILE__, __LINE__)) \
? cvc5::internal::nullStream \
: cvc5::internal::WarningChannel
#ifdef CVC5_TRACING
#define TraceIsOn cvc5::internal::TraceChannel.isOn
#define Trace(tag) \
!cvc5::internal::TraceChannel.isOn(tag) ? cvc5::internal::nullStream \
: cvc5::internal::TraceChannel()
#else /* CVC5_TRACING */
#define TraceIsOn \
cvc5::internal::__cvc5_true() ? false : cvc5::internal::TraceChannel.isOn
#define Trace(tag) \
cvc5::internal::__cvc5_true() ? cvc5::internal::nullStream \
: cvc5::internal::TraceChannel()
#endif /* CVC5_TRACING */
#endif /* CVC5_MUZZLE */
// Disallow e.g. !Trace("foo").isOn() forms
// because the ! will apply before the ? .
// If a compiler error has directed you here,
// just parenthesize it e.g. !(Trace("foo").isOn())
class __cvc5_true
{
CVC5_UNUSED void operator!();
CVC5_UNUSED void operator~();
CVC5_UNUSED void operator-();
CVC5_UNUSED void operator+();
public:
inline operator bool() { return true; }
}; /* __cvc5_true */
/**
* Pushes an indentation level on construction, pop on destruction.
* Useful for tracing recursive functions especially, but also can be
* used for clearly separating different phases of an algorithm,
* or iterations of a loop, or... etc.
*/
class IndentedScope
{
Cvc5ostream d_out;
public:
inline IndentedScope(Cvc5ostream out) : d_out(out) { d_out << push; }
inline ~IndentedScope() { d_out << pop; }
}; /* class IndentedScope */
} // namespace cvc5::internal
#endif /* CVC5__OUTPUT_H */