libtest: improve output format; makes eyes hurt less
[awesomized/libmemcached] / libtest / stream.h
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Data Differential YATL (i.e. libtest) library
4 *
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #pragma once
38
39 #include <iostream>
40 #include <cassert>
41 #include <sstream>
42 #include <ctime>
43 #include <ostream>
44
45 namespace libtest {
46 namespace stream {
47
48 namespace detail {
49
50 template<class Ch, class Tr, class A>
51 class channel {
52 private:
53
54 public:
55 typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
56
57 public:
58 void operator()(const stream_buffer& s, std::ostream& _out,
59 const char* filename, int line_number, const char* func)
60 {
61 if (filename)
62 {
63 _out
64 << filename
65 << ":"
66 << line_number
67 << ": in "
68 << func << "() "
69 << s.str()
70 << std::endl;
71 }
72 else
73 {
74 _out
75 << s.str()
76 << std::endl;
77 }
78 }
79 };
80
81 template<class Ch, class Tr, class A>
82 class channelln {
83 private:
84
85 public:
86 typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
87
88 public:
89 void operator()(const stream_buffer& s, std::ostream& _out,
90 const char* filename, int line_number, const char* func)
91 {
92 if (filename)
93 {
94 _out
95 << std::endl
96 << filename
97 << ":"
98 << line_number
99 << ": in "
100 << func << "() "
101 << s.str()
102 << std::endl;
103 }
104 else
105 {
106 _out
107 << std::endl
108 << s.str()
109 << std::endl;
110 }
111 }
112 };
113
114 template<class Ch, class Tr, class A>
115 class channelfl {
116 private:
117
118 public:
119 typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
120
121 public:
122 void operator()(const stream_buffer& s, std::ostream& _out,
123 const char* filename, int line_number, const char* func)
124 {
125 if (filename)
126 {
127 _out
128 << filename
129 << ":"
130 << line_number
131 << ": in "
132 << func << "() "
133 << s.str()
134 << std::flush;
135 }
136 else
137 {
138 _out
139 << s.str()
140 << std::flush;
141 }
142 }
143 };
144
145 template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
146 class log {
147 private:
148 typedef OutputPolicy<Ch, Tr, A> output_policy;
149
150 private:
151 std::ostream& _out;
152 const char *_filename;
153 int _line_number;
154 const char *_func;
155
156 public:
157 log(std::ostream& out_arg, const char* filename, int line_number, const char* func) :
158 _out(out_arg),
159 _filename(filename),
160 _line_number(line_number),
161 _func(func)
162 { }
163
164 virtual ~log()
165 {
166 output_policy()(arg, _out, _filename, _line_number, _func);
167 }
168
169 public:
170 template<class T>
171 log &operator<<(const T &x)
172 {
173 arg << x;
174 return *this;
175 }
176
177 private:
178 typename output_policy::stream_buffer arg;
179
180 private:
181 log( const log& );
182 const log& operator=( const log& );
183 };
184 } // namespace detail
185
186 class make_cerr : public detail::log<detail::channelln> {
187 public:
188 make_cerr(const char* filename, int line_number, const char* func) :
189 detail::log<detail::channelln>(std::cerr, filename, line_number, func)
190 { }
191
192 private:
193 make_cerr( const make_cerr& );
194 const make_cerr& operator=( const make_cerr& );
195 };
196
197 class cerr : public detail::log<detail::channel> {
198 public:
199 cerr(const char* filename, int line_number, const char* func) :
200 detail::log<detail::channel>(std::cout, filename, line_number, func)
201 { }
202
203 private:
204 cerr( const cerr& );
205 const cerr& operator=( const cerr& );
206 };
207
208 class clog : public detail::log<detail::channel> {
209 public:
210 clog(const char* filename, int line_number, const char* func) :
211 detail::log<detail::channel>(std::clog, filename, line_number, func)
212 { }
213
214 private:
215 clog( const clog& );
216 const clog& operator=( const clog& );
217 };
218
219 class make_cout : public detail::log<detail::channelln> {
220 public:
221 make_cout(const char* filename, int line_number, const char* func) :
222 detail::log<detail::channelln>(std::cout, filename, line_number, func)
223 { }
224
225 private:
226 make_cout( const make_cout& );
227 const make_cout& operator=( const make_cout& );
228 };
229
230 class cout : public detail::log<detail::channel> {
231 public:
232 cout(const char* filename, int line_number, const char* func) :
233 detail::log<detail::channel>(std::cout, filename, line_number, func)
234 { }
235
236 private:
237 cout( const cout& );
238 const cout& operator=( const cout& );
239 };
240
241 class cecho : public detail::log<detail::channelfl> {
242 public:
243 cecho(const char* filename, int line_number, const char* func) :
244 detail::log<detail::channelfl>(std::cout, filename, line_number, func)
245 { }
246
247 private:
248 cecho( const cecho& );
249 const cecho& operator=( const cecho& );
250 };
251
252 } // namespace stream
253
254 #define Error stream::cerr(__FILE__, __LINE__, __func__)
255
256 #define Echo stream::cecho(NULL, __LINE__, __func__)
257
258 #define Out stream::cout(NULL, __LINE__, __func__)
259
260 #define Outn() stream::cout(NULL, __LINE__, __func__) << " "
261
262 #define Log stream::clog(NULL, __LINE__, __func__)
263
264 #define Logn() stream::clog(NULL, __LINE__, __func__) << " "
265
266 } // namespace libtest