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:
operator()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:
operator()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<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
115   class log {
116   private:
117     typedef OutputPolicy<Ch, Tr, A> output_policy;
118 
119   private:
120     std::ostream& _out;
121     const char *_filename;
122     int _line_number;
123     const char *_func;
124 
125   public:
log(std::ostream & out_arg,const char * filename,int line_number,const char * func)126     log(std::ostream& out_arg, const char* filename, int line_number, const char* func) :
127       _out(out_arg),
128       _filename(filename),
129       _line_number(line_number),
130       _func(func)
131     { }
132 
~log()133     virtual ~log()
134     {
135       output_policy()(arg, _out, _filename, _line_number, _func);
136     }
137 
138   public:
139     template<class T>
140       log &operator<<(const T &x)
141       {
142         arg << x;
143         return *this;
144       }
145 
146   private:
147     typename output_policy::stream_buffer arg;
148 
149   private:
150     log( const log& );
151     const log& operator=( const log& );
152   };
153 } // namespace detail
154 
155 class make_cerr : public detail::log<detail::channelln> {
156 public:
make_cerr(const char * filename,int line_number,const char * func)157   make_cerr(const char* filename, int line_number, const char* func) :
158     detail::log<detail::channelln>(std::cerr, filename, line_number, func)
159   { }
160 
161 private:
162   make_cerr( const make_cerr& );
163   const make_cerr& operator=( const make_cerr& );
164 };
165 
166 class cerr : public detail::log<detail::channel> {
167 public:
cerr(const char * filename,int line_number,const char * func)168   cerr(const char* filename, int line_number, const char* func) :
169     detail::log<detail::channel>(std::cout, filename, line_number, func)
170   { }
171 
172 private:
173   cerr( const cerr& );
174   const cerr& operator=( const cerr& );
175 };
176 
177 class clog : public detail::log<detail::channel> {
178 public:
clog(const char * filename,int line_number,const char * func)179   clog(const char* filename, int line_number, const char* func) :
180     detail::log<detail::channel>(std::clog, filename, line_number, func)
181   { }
182 
183 private:
184   clog( const clog& );
185   const clog& operator=( const clog& );
186 };
187 
188 class make_cout : public detail::log<detail::channelln> {
189 public:
make_cout(const char * filename,int line_number,const char * func)190   make_cout(const char* filename, int line_number, const char* func) :
191     detail::log<detail::channelln>(std::cout, filename, line_number, func)
192   { }
193 
194 private:
195   make_cout( const make_cout& );
196   const make_cout& operator=( const make_cout& );
197 };
198 
199 class cout : public detail::log<detail::channel> {
200 public:
cout(const char * filename,int line_number,const char * func)201   cout(const char* filename, int line_number, const char* func) :
202     detail::log<detail::channel>(std::cout, filename, line_number, func)
203   { }
204 
205 private:
206   cout( const cout& );
207   const cout& operator=( const cout& );
208 };
209 
210 
211 } // namespace stream
212 
213 #define Error stream::cerr(__FILE__, __LINE__, __func__)
214 
215 #define Out stream::cout(NULL, __LINE__, __func__)
216 
217 #define Outn() stream::cout(NULL, __LINE__, __func__) << " "
218 
219 #define Log stream::clog(NULL, __LINE__, __func__)
220 
221 #define Logn() stream::clog(NULL, __LINE__, __func__) << " "
222 
223 } // namespace libtest
224