Set incomplete if not applying ho extensionality (#6281)
[cvc5.git] / src / util / safe_print.h
1 /********************* */
2 /*! \file safe_print.h
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Andres Noetzli, Mathias Preiner
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2021 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.\endverbatim
11 **
12 ** \brief Print functions that are safe to use in a signal handler.
13 **
14 ** Signal handlers only allow a very limited set of operations, e.g. dynamic
15 ** memory allocation is not possible. This set of functions can be used to
16 ** print information from a signal handler.
17 **
18 ** The safe_print function takes a template parameter T and prints an argument
19 ** of type const T& to avoid copying, e.g. when printing std::strings. For
20 ** consistency, we also pass primitive types by reference (otherwise, functions
21 ** in statistics_registry.h would require specialization or we would have to
22 ** use function overloading).
23 **
24 ** If there exists a function `toString(obj)` for a given object, it will be
25 ** used automatically. This is useful for printing enum values for example.
26 ** IMPORTANT: The `toString(obj)` function *must not* perform any allocations
27 ** or call other functions that are not async-signal-safe.
28 **
29 ** This header is a "cvc4_private_library.h" header because it is private but
30 ** the safe_print functions are used in the driver. See also the description
31 ** of "statistics_registry.h" for more information on
32 ** "cvc4_private_library.h".
33 **/
34
35 #include "cvc4_private_library.h"
36
37 #ifndef CVC4__SAFE_PRINT_H
38 #define CVC4__SAFE_PRINT_H
39
40 #include <unistd.h>
41
42 #include <cstring>
43 #include <string>
44
45 #include "cvc4_export.h"
46
47 namespace cvc5 {
48
49 /**
50 * Prints arrays of chars (e.g. string literals) of length N. Safe to use in a
51 * signal handler.
52 */
53 template <size_t N>
54 void CVC4_EXPORT safe_print(int fd, const char (&msg)[N])
55 {
56 ssize_t nb = N - 1;
57 if (write(fd, msg, nb) != nb) {
58 abort();
59 }
60 }
61
62 /**
63 * The default method for converting an object to a string for safe printing.
64 * This method simply returns "<unsupported>". The `long` argument is used to
65 * indicate that we do not prefer this method over the version that calls
66 * `toString()`.
67 */
68 template <typename T>
69 const char* toStringImpl(const T& obj, long)
70 {
71 return "<unsupported>";
72 }
73
74 /**
75 * Returns the result of calling `toString(obj)`. This method is only defined
76 * if such an overload of `toString()` exists. To detect the existence of such
77 * a method, we use SFINAE and a trailing return type. The trailing return type
78 * is necessary because it allows us to refer to `obj`. The `int` argument is
79 * used to prefer this version of the function instead of the one that prints
80 * "<unsupported>".
81 */
82 template <typename T>
83 auto toStringImpl(const T& obj, int) -> decltype(toString(obj))
84 {
85 return toString(obj);
86 }
87
88 /**
89 * Prints a variable of type T. Safe to use in a signal handler. The default
90 * implementation either prints "<unsupported>" or the result of calling
91 * `toString(obj)` if such a method exists (this is useful for printing enum
92 * values for example without implementing a template specialization here).
93 *
94 * @param fd The file descriptor to print to
95 * @param obj The object to print
96 */
97 template <typename T>
98 void CVC4_EXPORT safe_print(int fd, const T& obj)
99 {
100 const char* s =
101 toStringImpl(obj, /* prefer the method that uses `toString()` */ 0);
102 ssize_t slen = static_cast<ssize_t>(strlen(s));
103 if (write(fd, s, slen) != slen)
104 {
105 abort();
106 }
107 }
108
109 template <>
110 void CVC4_EXPORT safe_print(int fd, const std::string& msg);
111 template <>
112 void CVC4_EXPORT safe_print(int fd, const int64_t& _i);
113 template <>
114 void CVC4_EXPORT safe_print(int fd, const int32_t& i);
115 template <>
116 void CVC4_EXPORT safe_print(int fd, const uint64_t& _i);
117 template <>
118 void CVC4_EXPORT safe_print(int fd, const uint32_t& i);
119 template <>
120 void CVC4_EXPORT safe_print(int fd, const double& _d);
121 template <>
122 void CVC4_EXPORT safe_print(int fd, const float& f);
123 template <>
124 void CVC4_EXPORT safe_print(int fd, const bool& b);
125 template <>
126 void CVC4_EXPORT safe_print(int fd, void* const& addr);
127 template <>
128 void CVC4_EXPORT safe_print(int fd, const timespec& t);
129
130 /** Prints an integer in hexadecimal. Safe to use in a signal handler. */
131 void safe_print_hex(int fd, uint64_t i);
132
133 /**
134 * Prints a right aligned number. Fills up remaining space with zeros. Safe to
135 * use in a signal handler.
136 */
137 void safe_print_right_aligned(int fd, uint64_t i, ssize_t width);
138
139 } // namespace cvc5
140
141 #endif /* CVC4__SAFE_PRINT_H */