00001 #ifndef toast_logstream_hpp_INCLUDED
00002 #define toast_logstream_hpp_INCLUDED
00003
00004 #include <toast/log.hpp>
00005
00006 #include <iostream>
00007
00008 #include <boost/utility/enable_if.hpp>
00009 #include <boost/type_traits/is_same.hpp>
00010
00011 #include <toast/config.hpp>
00012
00013 namespace toast {
00014
00020 namespace detail {
00021 template <typename CharT, typename Traits, typename Alloc>
00022 class proxy_logstream;
00023 }
00024
00030 template <typename CharT, typename Traits = std::char_traits<CharT>,
00031 typename Alloc = std::allocator<CharT> >
00032 class basic_logbuf : public std::basic_stringbuf<CharT, Traits, Alloc>
00033 {
00034 static const int BUFFER_START_SIZE_ = 8;
00035 typedef std::basic_stringbuf<CharT, Traits, Alloc> base_type;
00036
00037 void init()
00038 {
00039 set_new_buffer(BUFFER_START_SIZE_);
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 setp(reinterpret_cast<char_type*>(1), reinterpret_cast<char_type*>(1));
00051 }
00052
00053 public:
00054 typedef Alloc allocator_type;
00055 typedef CharT char_type;
00056 typedef Traits traits_type;
00057 typedef typename traits_type::int_type int_type;
00058 typedef typename traits_type::off_type off_type;
00059 typedef typename traits_type::pos_type pos_type;
00060 typedef basic_log_handle<CharT> log_handle_type;
00061
00062 basic_logbuf(log::severity s = log::DEFAULT) : severity_(s)
00063 {
00064 init();
00065 }
00066
00067 basic_logbuf(log_handle_type const &log, log::severity s = log::DEFAULT)
00068 : log_(log), severity_(s)
00069 {
00070 init();
00071 }
00072
00073 virtual ~basic_logbuf()
00074 {
00075 delete[] real_pbase;
00076 }
00077
00078 void log(log_handle_type const &log) { log_ = log; }
00079 log_handle_type log() const { return log_; }
00080
00081 log::severity severity() const { return severity_; }
00082 void severity(log::severity s) { severity_ = s; }
00083
00084 bool check(log::severity s) const { return log_.check(s); }
00085
00086 protected:
00087 virtual int sync()
00088 {
00089 if(real_pbase != real_pptr) {
00090 real_sputc_with_overflow_check(traits_type::to_char_type('\0'));
00091
00092 std::streamsize n = remaining_space();
00093
00094 if(!log_.consume_forced_message(real_pbase, severity_)) {
00095
00096
00097
00098
00099
00100
00101
00102
00103 set_new_buffer(n);
00104 }
00105 else {
00106
00107 real_pptr = real_pbase;
00108 }
00109 }
00110 return 0;
00111 }
00112
00113 virtual std::streamsize xsputn(char_type const *s, std::streamsize n)
00114 {
00115
00116
00117 if(!check(severity_))
00118
00119
00120
00121
00122 return n;
00123
00124 grow_buffer_to_fit(n);
00125
00126 std::copy(s, s + n, real_pptr);
00127 real_pptr += n;
00128
00129 return n;
00130 }
00131
00132 virtual int_type overflow(int_type meta = traits_type::eof())
00133 {
00134
00135
00136
00137
00138
00139
00140
00141 if(!check(severity_))
00142 return meta;
00143
00144 return real_sputc_with_overflow_check(traits_type::to_char_type(meta));
00145 }
00146
00147 private:
00148 std::streamsize remaining_space()
00149 {
00150 return real_epptr - real_pptr;
00151 }
00152
00153 int_type real_sputc_with_overflow_check(char_type ch)
00154 {
00155 grow_buffer_to_fit(1);
00156
00157 return traits_type::not_eof(real_sputc(ch));
00158 }
00159
00160 int_type real_sputc(char_type ch)
00161 {
00162 return traits_type::to_int_type(*(real_pptr++) = ch);
00163 }
00164
00165 bool will_overflow(std::streamsize n_chars_to_write)
00166 {
00167 return (real_pptr + n_chars_to_write - 1) >= real_epptr;
00168 }
00169
00170 void grow_buffer_to_fit(std::streamsize n)
00171 {
00172 if(!will_overflow(n))
00173 return;
00174
00175 char_type
00176 *oldbuf_base = real_pbase,
00177 *oldbuf_next = real_pptr,
00178 *oldbuf_end = real_epptr;
00179 std::streamsize relative_loc = real_pptr - real_pbase;
00180 std::streamsize len = oldbuf_end - oldbuf_base;
00181 set_new_buffer(std::max(static_cast<std::streamsize>(len * 1.5), len + n));
00182
00183 std::copy(oldbuf_base, oldbuf_end, real_pbase);
00184 real_pptr = real_pbase + relative_loc;
00185
00186 delete[] oldbuf_base;
00187 }
00188
00189 void set_new_buffer(std::streamsize n)
00190 {
00191 char_type* newbuf = new char_type[n];
00192
00193 real_pbase = newbuf;
00194 real_pptr = newbuf;
00195 real_epptr = newbuf + n;
00196 }
00197
00198 #ifdef TOAST_NESTED_FRIEND_TEMPLATES
00199
00200 template<typename T>
00201 friend detail::proxy_logstream<CharT, Traits, Alloc>& detail::proxy_logstream<CharT, Traits, Alloc>::operator<<(T const &toStream);
00202
00203 #else
00204
00205 public:
00206
00207 #endif
00208
00209 char_type *real_pbase, *real_pptr, *real_epptr;
00210 log_handle_type log_;
00211 log::severity severity_;
00212 };
00213
00217 template <typename CharT, typename Traits = std::char_traits<CharT>,
00218 typename Alloc = std::allocator<CharT> >
00219 class basic_logstream : public std::basic_ostream<CharT, Traits>
00220 {
00221 typedef std::basic_ostream<CharT, Traits> base_type;
00222 public:
00223 typedef basic_logbuf<CharT, Traits, Alloc> streambuf_type;
00224 typedef typename streambuf_type::log_handle_type log_handle_type;
00225
00226 basic_logstream(log::severity s = log::DEFAULT)
00227 : base_type(new streambuf_type(s)) {}
00228
00229 basic_logstream(log_handle_type const &logger,
00230 log::severity s = log::DEFAULT)
00231 : base_type(new streambuf_type(logger, s))
00232 {}
00233
00234 ~basic_logstream() { delete rdbuf(); }
00235
00236 streambuf_type const* rdbuf() const
00237 {
00238 return static_cast<streambuf_type const *>(base_type::rdbuf());
00239 }
00240
00241 streambuf_type* rdbuf()
00242 {
00243 return static_cast<streambuf_type *>(base_type::rdbuf());
00244 }
00245
00246 void log(log_handle_type const &logger)
00247 {
00248 base_type::flush();
00249 rdbuf()->log(logger);
00250 }
00251
00252 log_handle_type log() const { return rdbuf()->log(); }
00253
00254 log::severity severity() const { return rdbuf()->severity(); }
00255
00256 void severity(log::severity s)
00257 {
00258 base_type::flush();
00259 rdbuf()->severity(s);
00260 }
00261
00262 bool check(log::severity s) const { return rdbuf()->check(s); }
00263
00264 };
00265
00266 namespace detail {
00267
00268
00269
00270 template <typename CharT, typename Traits, typename Alloc>
00271 class proxy_logstream
00272 {
00273 typedef proxy_logstream<CharT, Traits, Alloc> this_t;
00274 typedef basic_logstream<CharT, Traits, Alloc> real_logstream_t;
00275
00276 public:
00277 proxy_logstream(real_logstream_t& stream, bool active) :
00278 _stream(stream), _active(active) {}
00279
00280 operator real_logstream_t& () { return _stream; }
00281
00282 proxy_logstream& operator <<(log::severity s)
00283 {
00284 _stream.severity(s);
00285 _active = _stream.check(s);
00286 return *this;
00287 }
00288
00289
00290
00291
00292 proxy_logstream& operator<<(std::basic_ostream<CharT, Traits>& (*pf)(std::basic_ostream<CharT, Traits>&))
00293 {
00294 pf(_stream);
00295 return *this;
00296 }
00297
00298 template<typename T>
00299 proxy_logstream& operator<<(T const &toStream)
00300 {
00301 if(!_active)
00302 return *this;
00303
00304 static_cast<std::basic_ostream<CharT, Traits>&>(_stream) << toStream;
00305 return *this;
00306 }
00307
00308 private:
00309 real_logstream_t& _stream;
00310 bool _active;
00311 };
00312
00313 }
00314
00315 template <typename CharT, typename Traits, typename Alloc>
00316 detail::proxy_logstream<CharT, Traits, Alloc> operator <<(
00317 basic_logstream<CharT, Traits, Alloc> &os, log::severity s)
00318 {
00319 os.severity(s);
00320 return detail::proxy_logstream<CharT, Traits, Alloc>(os, os.check(os.severity()));
00321 }
00322
00323 template <typename CharT, typename Traits,
00324 typename Alloc, typename T >
00325 detail::proxy_logstream<CharT, Traits, Alloc> operator<<(basic_logstream<CharT, Traits, Alloc>& stream, T const &toStream)
00326 {
00327 if(stream.check(stream.severity())) {
00328 detail::proxy_logstream<CharT, Traits, Alloc> proxy(stream, true);
00329 proxy << toStream;
00330
00331 return proxy;
00332 }
00333
00334 return detail::proxy_logstream<CharT, Traits, Alloc>(stream, false);
00335 }
00336
00340 typedef basic_logbuf<char> logbuf;
00341
00343 typedef basic_logstream<char> logstream;
00344
00347 namespace log {
00348
00349 using ::toast::logbuf;
00350 using ::toast::logstream;
00351
00352 }
00353 }
00354
00355 #endif // toast_logstream_hpp_INCLUDED