1/*
2 * Copyright (C) 2012 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#ifndef PrintStream_h
27#define PrintStream_h
28
29#include <stdarg.h>
30#include <wtf/FastMalloc.h>
31#include <wtf/Noncopyable.h>
32#include <wtf/RawPointer.h>
33#include <wtf/StdLibExtras.h>
34
35namespace WTF {
36
37class CString;
38class String;
39class StringImpl;
40
41class PrintStream {
42    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(PrintStream);
43public:
44    PrintStream();
45    virtual ~PrintStream();
46
47    WTF_EXPORT_PRIVATE void printf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
48    virtual void vprintf(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(2, 0) = 0;
49
50    // Typically a no-op for many subclasses of PrintStream, this is a hint that
51    // the implementation should flush its buffers if it had not done so already.
52    virtual void flush();
53
54    template<typename T>
55    void print(const T& value)
56    {
57        printInternal(*this, value);
58    }
59
60    template<typename T, typename... Types>
61    void print(const T& value, const Types&... remainingValues)
62    {
63        printInternal(*this, value);
64        print(remainingValues...);
65    }
66};
67
68WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const char*);
69WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const CString&);
70WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const String&);
71WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const StringImpl*);
72inline void printInternal(PrintStream& out, char* value) { printInternal(out, static_cast<const char*>(value)); }
73inline void printInternal(PrintStream& out, CString& value) { printInternal(out, static_cast<const CString&>(value)); }
74inline void printInternal(PrintStream& out, String& value) { printInternal(out, static_cast<const String&>(value)); }
75inline void printInternal(PrintStream& out, StringImpl* value) { printInternal(out, static_cast<const StringImpl*>(value)); }
76WTF_EXPORT_PRIVATE void printInternal(PrintStream&, bool);
77WTF_EXPORT_PRIVATE void printInternal(PrintStream&, signed char); // NOTE: this prints as a number, not as a character; use CharacterDump if you want the character
78WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned char); // NOTE: see above.
79WTF_EXPORT_PRIVATE void printInternal(PrintStream&, short);
80WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned short);
81WTF_EXPORT_PRIVATE void printInternal(PrintStream&, int);
82WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned);
83WTF_EXPORT_PRIVATE void printInternal(PrintStream&, long);
84WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned long);
85WTF_EXPORT_PRIVATE void printInternal(PrintStream&, long long);
86WTF_EXPORT_PRIVATE void printInternal(PrintStream&, unsigned long long);
87WTF_EXPORT_PRIVATE void printInternal(PrintStream&, float);
88WTF_EXPORT_PRIVATE void printInternal(PrintStream&, double);
89WTF_EXPORT_PRIVATE void printInternal(PrintStream&, RawPointer);
90
91template<typename T>
92void printInternal(PrintStream& out, const T& value)
93{
94    value.dump(out);
95}
96
97#define MAKE_PRINT_ADAPTOR(Name, Type, function) \
98    class Name {                                 \
99    public:                                      \
100        Name(const Type& value)                  \
101            : m_value(value)                     \
102        {                                        \
103        }                                        \
104        void dump(PrintStream& out) const        \
105        {                                        \
106            function(out, m_value);              \
107        }                                        \
108    private:                                     \
109        Type m_value;                            \
110    }
111
112#define MAKE_PRINT_METHOD_ADAPTOR(Name, Type, method) \
113    class Name {                                 \
114    public:                                      \
115        Name(const Type& value)                  \
116            : m_value(value)                     \
117        {                                        \
118        }                                        \
119        void dump(PrintStream& out) const        \
120        {                                        \
121            m_value.method(out);                 \
122        }                                        \
123    private:                                     \
124        const Type& m_value;                     \
125    }
126
127#define MAKE_PRINT_METHOD(Type, dumpMethod, method) \
128    MAKE_PRINT_METHOD_ADAPTOR(DumperFor_##method, Type, dumpMethod);    \
129    DumperFor_##method method() const { return DumperFor_##method(*this); }
130
131// Use an adaptor-based dumper for characters to avoid situations where
132// you've "compressed" an integer to a character and it ends up printing
133// as ASCII when you wanted it to print as a number.
134WTF_EXPORT_PRIVATE void dumpCharacter(PrintStream&, char);
135MAKE_PRINT_ADAPTOR(CharacterDump, char, dumpCharacter);
136
137template<typename T>
138class PointerDump {
139public:
140    PointerDump(const T* ptr)
141        : m_ptr(ptr)
142    {
143    }
144
145    void dump(PrintStream& out) const
146    {
147        if (m_ptr)
148            printInternal(out, *m_ptr);
149        else
150            out.print("(null)");
151    }
152private:
153    const T* m_ptr;
154};
155
156template<typename T>
157PointerDump<T> pointerDump(const T* ptr) { return PointerDump<T>(ptr); }
158
159template<typename T, typename U>
160class ValueInContext {
161public:
162    ValueInContext(const T& value, U* context)
163        : m_value(&value)
164        , m_context(context)
165    {
166    }
167
168    void dump(PrintStream& out) const
169    {
170        m_value->dumpInContext(out, m_context);
171    }
172
173private:
174    const T* m_value;
175    U* m_context;
176};
177
178template<typename T, typename U>
179ValueInContext<T, U> inContext(const T& value, U* context)
180{
181    return ValueInContext<T, U>(value, context);
182}
183
184template<typename T, typename U>
185class PointerDumpInContext {
186public:
187    PointerDumpInContext(const T* ptr, U* context)
188        : m_ptr(ptr)
189        , m_context(context)
190    {
191    }
192
193    void dump(PrintStream& out) const
194    {
195        if (m_ptr)
196            m_ptr->dumpInContext(out, m_context);
197        else
198            out.print("(null)");
199    }
200
201private:
202    const T* m_ptr;
203    U* m_context;
204};
205
206template<typename T, typename U>
207PointerDumpInContext<T, U> pointerDumpInContext(const T* ptr, U* context)
208{
209    return PointerDumpInContext<T, U>(ptr, context);
210}
211
212template<typename T, typename U>
213class ValueIgnoringContext {
214public:
215    ValueIgnoringContext(const U& value)
216        : m_value(&value)
217    {
218    }
219
220    void dump(PrintStream& out) const
221    {
222        T context;
223        m_value->dumpInContext(out, &context);
224    }
225
226private:
227    const U* m_value;
228};
229
230template<typename T, typename U>
231ValueIgnoringContext<T, U> ignoringContext(const U& value)
232{
233    return ValueIgnoringContext<T, U>(value);
234}
235
236} // namespace WTF
237
238using WTF::CharacterDump;
239using WTF::PointerDump;
240using WTF::PrintStream;
241using WTF::ignoringContext;
242using WTF::inContext;
243using WTF::pointerDump;
244using WTF::pointerDumpInContext;
245
246#endif // PrintStream_h
247
248