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 : : * Wrappers to handle memory management of streams. 11 : : * 12 : : * This file contains wrappers to handle special cases of managing memory 13 : : * related to streams stored in options. 14 : : */ 15 : : 16 : : #include "cvc5_public.h" 17 : : 18 : : #ifndef CVC5__OPTIONS__MANAGED_STREAMS_H 19 : : #define CVC5__OPTIONS__MANAGED_STREAMS_H 20 : : 21 : : #include <memory> 22 : : #include <ostream> 23 : : 24 : : namespace cvc5::internal { 25 : : 26 : : namespace detail { 27 : : /* 28 : : * Open a file as an output stream and return it as a pointer. The caller 29 : : * assumes the ownership of the returned pointer. 30 : : */ 31 : : std::unique_ptr<std::ostream> openOStream(const std::string& filename); 32 : : /* 33 : : * Open a file as an input stream and return it as a pointer. The caller 34 : : * assumes the ownership of the returned pointer. 35 : : */ 36 : : std::unique_ptr<std::istream> openIStream(const std::string& filename); 37 : : } // namespace detail 38 : : 39 : : /** 40 : : * Implements memory management for streams, both input and output. It is 41 : : * intended to be subclassed, where a subclass can provide a default value and 42 : : * special cases. Usually, users should use one of these subclasses. 43 : : * The template argument type should be either std::istream or std::ostream, 44 : : * indicating whether the type wraps an input or output stream. 45 : : */ 46 : : template <typename Stream> 47 : : class ManagedStream 48 : : { 49 : : public: 50 : 585704 : ManagedStream(Stream* nonowned, std::string description) 51 : 585704 : : d_nonowned(nonowned), d_description(std::move(description)) 52 : : { 53 : 585704 : } 54 : 544876 : virtual ~ManagedStream() {} 55 : : 56 : : /** 57 : : * Open the stream from the given value. First check the special cases and 58 : : * then fall back to using `std::ofstream` or `std::ifstream`. 59 : : */ 60 : 368 : void open(const std::string& value) 61 : : { 62 [ + + ]: 368 : if (specialCases(value)) return; 63 : : if constexpr (std::is_same<Stream, std::ostream>::value) 64 : : { 65 : 293 : d_nonowned = nullptr; 66 : 293 : d_owned = detail::openOStream(value); 67 : 0 : d_description = value; 68 : : } 69 : : else if constexpr (std::is_same<Stream, std::istream>::value) 70 : : { 71 : 71 : d_nonowned = nullptr; 72 : 71 : d_owned = detail::openIStream(value); 73 : 0 : d_description = value; 74 : : } 75 : : } 76 : : 77 : 785761 : Stream& operator*() const { return *getPtr(); } 78 : : Stream* operator->() const { return getPtr(); } 79 : 6669 : operator Stream&() const { return *getPtr(); } 80 : 4 : operator Stream*() const { return getPtr(); } 81 : : 82 : 7006 : const std::string& description() const { return d_description; } 83 : : 84 : : protected: 85 : : Stream* d_nonowned; 86 : : std::shared_ptr<Stream> d_owned; 87 : : std::string d_description = "<null>"; 88 : : 89 : : private: 90 : : /** 91 : : * Check if there is a special case for this value. If so, the implementation 92 : : * should set d_stream appropriately and return true to skip the default 93 : : * methods for opening a stream. 94 : : */ 95 : : virtual bool specialCases(const std::string& value) = 0; 96 : : 97 : : /** Return the pointer, either from d_nonowned or d_owned. */ 98 : 792434 : Stream* getPtr() const 99 : : { 100 [ + - ]: 792434 : if (d_nonowned != nullptr) return d_nonowned; 101 : 0 : return d_owned.get(); 102 : : } 103 : : }; 104 : : 105 : : template <typename Stream> 106 : 7006 : std::ostream& operator<<(std::ostream& os, const ManagedStream<Stream>& ms) 107 : : { 108 : 7006 : return os << ms.description(); 109 : : } 110 : : 111 : : /** 112 : : * Managed error output. It recognizes "stderr" and "--" as special valued for 113 : : * std::cerr. 114 : : */ 115 : : class ManagedErr : public ManagedStream<std::ostream> 116 : : { 117 : : public: 118 : : ManagedErr(); 119 : : 120 : : private: 121 : : bool specialCases(const std::string& value) override final; 122 : : }; 123 : : 124 : : /** 125 : : * Managed standard input. It recognizes "stdin" and "--" as special valued for 126 : : * std::cin. 127 : : */ 128 : : class ManagedIn : public ManagedStream<std::istream> 129 : : { 130 : : public: 131 : : ManagedIn(); 132 : : 133 : : private: 134 : : bool specialCases(const std::string& value) override final; 135 : : }; 136 : : 137 : : /** 138 : : * Managed standard output. It recognizes "stdout" and "--" as special valued 139 : : * for std::cout. 140 : : */ 141 : : class ManagedOut : public ManagedStream<std::ostream> 142 : : { 143 : : public: 144 : : ManagedOut(); 145 : : 146 : : private: 147 : : bool specialCases(const std::string& value) override final; 148 : : }; 149 : : 150 : : } // namespace cvc5::internal 151 : : 152 : : #endif /* CVC5__OPTIONS__MANAGED_STREAMS_H */