1 | /* |
2 | * Copyright (C) 2012-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include <memory> |
29 | #include <stdarg.h> |
30 | #include <tuple> |
31 | #include <wtf/Forward.h> |
32 | #include <wtf/FastMalloc.h> |
33 | #include <wtf/Noncopyable.h> |
34 | #include <wtf/Optional.h> |
35 | #include <wtf/RawPointer.h> |
36 | #include <wtf/RefPtr.h> |
37 | #include <wtf/StdLibExtras.h> |
38 | |
39 | namespace WTF { |
40 | |
41 | inline const char* boolForPrinting(bool value) |
42 | { |
43 | return value ? "true" : "false" ; |
44 | } |
45 | |
46 | class PrintStream { |
47 | WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(PrintStream); |
48 | public: |
49 | PrintStream(); |
50 | virtual ~PrintStream(); |
51 | |
52 | WTF_EXPORT_PRIVATE void printf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); |
53 | WTF_EXPORT_PRIVATE void printfVariableFormat(const char* format, ...); |
54 | virtual void vprintf(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(2, 0) = 0; |
55 | |
56 | // Typically a no-op for many subclasses of PrintStream, this is a hint that |
57 | // the implementation should flush its buffers if it had not done so already. |
58 | virtual void flush(); |
59 | |
60 | template<typename Func> |
61 | void atomically(const Func& func) |
62 | { |
63 | func(begin()); |
64 | end(); |
65 | } |
66 | |
67 | template<typename... Types> |
68 | void print(const Types&... values) |
69 | { |
70 | atomically( |
71 | [&] (PrintStream& out) { |
72 | out.printImpl(values...); |
73 | }); |
74 | } |
75 | |
76 | template<typename... Types> |
77 | void println(const Types&... values) |
78 | { |
79 | print(values..., "\n" ); |
80 | } |
81 | |
82 | protected: |
83 | void printImpl() { } |
84 | |
85 | template<typename T, typename... Types> |
86 | void printImpl(const T& value, const Types&... remainingValues) |
87 | { |
88 | printInternal(*this, value); |
89 | printImpl(remainingValues...); |
90 | } |
91 | |
92 | virtual PrintStream& begin(); |
93 | virtual void end(); |
94 | }; |
95 | |
96 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const char*); |
97 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const StringView&); |
98 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const CString&); |
99 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const String&); |
100 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const StringImpl*); |
101 | inline void printInternal(PrintStream& out, const AtomStringImpl* value) { printInternal(out, bitwise_cast<const StringImpl*>(value)); } |
102 | inline void printInternal(PrintStream& out, const UniquedStringImpl* value) { printInternal(out, bitwise_cast<const StringImpl*>(value)); } |
103 | inline void printInternal(PrintStream& out, const UniquedStringImpl& value) { printInternal(out, &value); } |
104 | inline void printInternal(PrintStream& out, char* value) { printInternal(out, static_cast<const char*>(value)); } |
105 | inline void printInternal(PrintStream& out, CString& value) { printInternal(out, static_cast<const CString&>(value)); } |
106 | inline void printInternal(PrintStream& out, String& value) { printInternal(out, static_cast<const String&>(value)); } |
107 | inline void printInternal(PrintStream& out, StringImpl* value) { printInternal(out, static_cast<const StringImpl*>(value)); } |
108 | inline void printInternal(PrintStream& out, AtomStringImpl* value) { printInternal(out, static_cast<const AtomStringImpl*>(value)); } |
109 | inline void printInternal(PrintStream& out, UniquedStringImpl* value) { printInternal(out, static_cast<const UniquedStringImpl*>(value)); } |
110 | inline void printInternal(PrintStream& out, UniquedStringImpl& value) { printInternal(out, &value); } |
111 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, bool); |
112 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, signed char); // NOTE: this prints as a number, not as a character; use CharacterDump if you want the character |
113 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned char); // NOTE: see above. |
114 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, short); |
115 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned short); |
116 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, int); |
117 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned); |
118 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, long); |
119 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned long); |
120 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, long long); |
121 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned long long); |
122 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, float); |
123 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, double); |
124 | WTF_EXPORT_PRIVATE void printInternal(PrintStream&, RawPointer); |
125 | |
126 | template<typename T> |
127 | void printInternal(PrintStream& out, const T& value) |
128 | { |
129 | value.dump(out); |
130 | } |
131 | |
132 | #define MAKE_PRINT_ADAPTOR(Name, Type, function) \ |
133 | class Name { \ |
134 | public: \ |
135 | Name(Type value) \ |
136 | : m_value(value) \ |
137 | { \ |
138 | } \ |
139 | void dump(PrintStream& out) const \ |
140 | { \ |
141 | function(out, m_value); \ |
142 | } \ |
143 | private: \ |
144 | Type m_value; \ |
145 | } |
146 | |
147 | #define MAKE_PRINT_METHOD_ADAPTOR(Name, Type, method) \ |
148 | class Name { \ |
149 | public: \ |
150 | Name(const Type& value) \ |
151 | : m_value(value) \ |
152 | { \ |
153 | } \ |
154 | void dump(PrintStream& out) const \ |
155 | { \ |
156 | m_value.method(out); \ |
157 | } \ |
158 | private: \ |
159 | const Type& m_value; \ |
160 | } |
161 | |
162 | #define MAKE_PRINT_METHOD(Type, dumpMethod, method) \ |
163 | MAKE_PRINT_METHOD_ADAPTOR(DumperFor_##method, Type, dumpMethod); \ |
164 | DumperFor_##method method() const { return DumperFor_##method(*this); } |
165 | |
166 | // Use an adaptor-based dumper for characters to avoid situations where |
167 | // you've "compressed" an integer to a character and it ends up printing |
168 | // as ASCII when you wanted it to print as a number. |
169 | WTF_EXPORT_PRIVATE void dumpCharacter(PrintStream&, char); |
170 | MAKE_PRINT_ADAPTOR(CharacterDump, char, dumpCharacter); |
171 | |
172 | template<typename T> |
173 | class PointerDump { |
174 | public: |
175 | PointerDump(const T* ptr) |
176 | : m_ptr(ptr) |
177 | { |
178 | } |
179 | |
180 | void dump(PrintStream& out) const |
181 | { |
182 | if (m_ptr) |
183 | printInternal(out, *m_ptr); |
184 | else |
185 | out.print("(null)" ); |
186 | } |
187 | private: |
188 | const T* m_ptr; |
189 | }; |
190 | |
191 | template<typename T> |
192 | PointerDump<T> pointerDump(const T* ptr) { return PointerDump<T>(ptr); } |
193 | |
194 | template<typename T> |
195 | void printInternal(PrintStream& out, const std::unique_ptr<T>& value) |
196 | { |
197 | out.print(pointerDump(value.get())); |
198 | } |
199 | |
200 | template<typename T> |
201 | void printInternal(PrintStream& out, const RefPtr<T>& value) |
202 | { |
203 | out.print(pointerDump(value.get())); |
204 | } |
205 | |
206 | template<typename T, typename U> |
207 | class ValueInContext { |
208 | public: |
209 | ValueInContext(const T& value, U* context) |
210 | : m_value(&value) |
211 | , m_context(context) |
212 | { |
213 | } |
214 | |
215 | void dump(PrintStream& out) const |
216 | { |
217 | m_value->dumpInContext(out, m_context); |
218 | } |
219 | |
220 | private: |
221 | const T* m_value; |
222 | U* m_context; |
223 | }; |
224 | |
225 | template<typename T, typename U> |
226 | ValueInContext<T, U> inContext(const T& value, U* context) |
227 | { |
228 | return ValueInContext<T, U>(value, context); |
229 | } |
230 | |
231 | template<typename T, typename U> |
232 | class PointerDumpInContext { |
233 | public: |
234 | PointerDumpInContext(const T* ptr, U* context) |
235 | : m_ptr(ptr) |
236 | , m_context(context) |
237 | { |
238 | } |
239 | |
240 | void dump(PrintStream& out) const |
241 | { |
242 | if (m_ptr) |
243 | m_ptr->dumpInContext(out, m_context); |
244 | else |
245 | out.print("(null)" ); |
246 | } |
247 | |
248 | private: |
249 | const T* m_ptr; |
250 | U* m_context; |
251 | }; |
252 | |
253 | template<typename T, typename U> |
254 | PointerDumpInContext<T, U> pointerDumpInContext(const T* ptr, U* context) |
255 | { |
256 | return PointerDumpInContext<T, U>(ptr, context); |
257 | } |
258 | |
259 | template<typename T, typename U> |
260 | class ValueIgnoringContext { |
261 | public: |
262 | ValueIgnoringContext(const U& value) |
263 | : m_value(&value) |
264 | { |
265 | } |
266 | |
267 | void dump(PrintStream& out) const |
268 | { |
269 | T context; |
270 | m_value->dumpInContext(out, &context); |
271 | } |
272 | |
273 | private: |
274 | const U* m_value; |
275 | }; |
276 | |
277 | template<typename T, typename U> |
278 | ValueIgnoringContext<T, U> ignoringContext(const U& value) |
279 | { |
280 | return ValueIgnoringContext<T, U>(value); |
281 | } |
282 | |
283 | template<unsigned index, typename... Types> |
284 | struct FormatImplUnpacker { |
285 | template<typename... Args> |
286 | static void unpack(PrintStream& out, const std::tuple<Types...>& tuple, const Args&... values); |
287 | }; |
288 | |
289 | template<typename... Types> |
290 | struct FormatImplUnpacker<0, Types...> { |
291 | template<typename... Args> |
292 | static void unpack(PrintStream& out, const std::tuple<Types...>& tuple, const Args&... values) |
293 | { |
294 | out.printfVariableFormat(std::get<0>(tuple), values...); |
295 | } |
296 | }; |
297 | |
298 | template<unsigned index, typename... Types> |
299 | template<typename... Args> |
300 | void FormatImplUnpacker<index, Types...>::unpack(PrintStream& out, const std::tuple<Types...>& tuple, const Args&... values) |
301 | { |
302 | FormatImplUnpacker<index - 1, Types...>::unpack(out, tuple, std::get<index>(tuple), values...); |
303 | } |
304 | |
305 | template<typename... Types> |
306 | class FormatImpl { |
307 | public: |
308 | FormatImpl(Types... values) |
309 | : m_values(values...) |
310 | { |
311 | } |
312 | |
313 | void dump(PrintStream& out) const |
314 | { |
315 | FormatImplUnpacker<sizeof...(Types) - 1, Types...>::unpack(out, m_values); |
316 | } |
317 | |
318 | private: |
319 | std::tuple<Types...> m_values; |
320 | }; |
321 | |
322 | template<typename... Types> |
323 | FormatImpl<Types...> format(Types... values) |
324 | { |
325 | return FormatImpl<Types...>(values...); |
326 | } |
327 | |
328 | template<typename T> |
329 | void printInternal(PrintStream& out, const Optional<T>& value) |
330 | { |
331 | if (value) |
332 | out.print(*value); |
333 | else |
334 | out.print("<nullopt>" ); |
335 | } |
336 | |
337 | } // namespace WTF |
338 | |
339 | using WTF::boolForPrinting; |
340 | using WTF::CharacterDump; |
341 | using WTF::PointerDump; |
342 | using WTF::PrintStream; |
343 | using WTF::format; |
344 | using WTF::ignoringContext; |
345 | using WTF::inContext; |
346 | using WTF::pointerDump; |
347 | using WTF::pointerDumpInContext; |
348 | |