1 /*
2 * Copyright Andrey Semashev 2007 - 2015.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7 /*!
8 * \file formatting_ostream.hpp
9 * \author Andrey Semashev
10 * \date 11.07.2012
11 *
12 * The header contains implementation of a string stream used for log record formatting.
13 */
14
15 #ifndef BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
16 #define BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
17
18 #include <ostream>
19 #include <string>
20 #include <memory>
21 #include <locale>
22 #include <boost/core/explicit_operator_bool.hpp>
23 #include <boost/utility/string_ref_fwd.hpp>
24 #include <boost/type_traits/remove_cv.hpp>
25 #include <boost/log/detail/config.hpp>
26 #include <boost/log/detail/attachable_sstream_buf.hpp>
27 #include <boost/log/detail/code_conversion.hpp>
28 #include <boost/log/utility/string_literal_fwd.hpp>
29 #include <boost/log/utility/formatting_ostream_fwd.hpp>
30 #include <boost/log/detail/header.hpp>
31
32 #ifdef BOOST_HAS_PRAGMA_ONCE
33 #pragma once
34 #endif
35
36 namespace boost {
37
38 BOOST_LOG_OPEN_NAMESPACE
39
40 namespace aux {
41
42 template< typename T, typename R >
43 struct enable_if_streamable_char_type {};
44 template< typename R >
45 struct enable_if_streamable_char_type< char, R > { typedef R type; };
46 template< typename R >
47 struct enable_if_streamable_char_type< wchar_t, R > { typedef R type; };
48 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
49 #if !defined(BOOST_NO_CXX11_CHAR16_T)
50 template< typename R >
51 struct enable_if_streamable_char_type< char16_t, R > { typedef R type; };
52 #endif
53 #if !defined(BOOST_NO_CXX11_CHAR32_T)
54 template< typename R >
55 struct enable_if_streamable_char_type< char32_t, R > { typedef R type; };
56 #endif
57 #endif
58
59 template< typename StreamT, typename R >
60 struct enable_if_formatting_ostream {};
61 template< typename CharT, typename TraitsT, typename AllocatorT, typename R >
62 struct enable_if_formatting_ostream< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, R > { typedef R type; };
63
64 } // namespace aux
65
66 /*!
67 * \brief Stream wrapper for log records formatting.
68 *
69 * This stream wrapper is used by the library for log record formatting. It implements the standard string stream interface
70 * with a few differences:
71 *
72 * \li It does not derive from standard types <tt>std::basic_ostream</tt>, <tt>std::basic_ios</tt> and <tt>std::ios_base</tt>,
73 * although it tries to implement their interfaces closely. There are a few small differences, mostly regarding <tt>rdbuf</tt>
74 * and <tt>str</tt> signatures, as well as the supported insertion operator overloads. The actual wrapped stream can be accessed
75 * through the <tt>stream</tt> methods.
76 * \li By default, \c bool values are formatted using alphabetical representation rather than numeric.
77 * \li The stream supports writing strings of character types different from the stream character type. The stream will perform
78 * character code conversion as needed using the imbued locale.
79 * \li The stream operates on an external string object rather than on the embedded one. The string can be attached or detached
80 * from the stream dynamically.
81 *
82 * Although <tt>basic_formatting_ostream</tt> does not derive from <tt>std::basic_ostream</tt>, users are not required to add
83 * special overloads of \c operator<< for it since the stream will by default reuse the operators for <tt>std::basic_ostream</tt>.
84 * However, one can define special overloads of \c operator<< for <tt>basic_formatting_ostream</tt> if a certain type needs
85 * special formatting when output to log.
86 */
87 template< typename CharT, typename TraitsT, typename AllocatorT >
88 class basic_formatting_ostream
89 {
90 public:
91 //! Character type
92 typedef CharT char_type;
93 //! Character traits
94 typedef TraitsT traits_type;
95 //! Memory allocator
96 typedef AllocatorT allocator_type;
97 //! Stream buffer type
98 typedef boost::log::aux::basic_ostringstreambuf< char_type, traits_type, allocator_type > streambuf_type;
99 //! Target string type
100 typedef typename streambuf_type::string_type string_type;
101
102 //! Stream type
103 typedef std::basic_ostream< char_type, traits_type > ostream_type;
104 //! Stream position type
105 typedef typename ostream_type::pos_type pos_type;
106 //! Stream offset type
107 typedef typename ostream_type::off_type off_type;
108 //! Integer type for characters
109 typedef typename ostream_type::int_type int_type;
110
111 typedef typename ostream_type::failure failure;
112 typedef typename ostream_type::fmtflags fmtflags;
113 typedef typename ostream_type::iostate iostate;
114 typedef typename ostream_type::openmode openmode;
115 typedef typename ostream_type::seekdir seekdir;
116 typedef typename ostream_type::Init Init;
117
118 typedef typename ostream_type::event event;
119 typedef typename ostream_type::event_callback event_callback;
120
121 class sentry :
122 public ostream_type::sentry
123 {
124 typedef typename ostream_type::sentry base_type;
125
126 public:
sentry(basic_formatting_ostream & strm)127 explicit sentry(basic_formatting_ostream& strm) : base_type(strm.stream())
128 {
129 }
130
131 BOOST_DELETED_FUNCTION(sentry(sentry const&))
132 BOOST_DELETED_FUNCTION(sentry& operator= (sentry const&))
133 };
134
135 private:
136 // Function types
137 typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
138 typedef std::basic_ios< char_type, traits_type >& (*basic_ios_manip)(std::basic_ios< char_type, traits_type >&);
139 typedef ostream_type& (*stream_manip)(ostream_type&);
140
141 public:
142 static BOOST_CONSTEXPR_OR_CONST fmtflags boolalpha = ostream_type::boolalpha;
143 static BOOST_CONSTEXPR_OR_CONST fmtflags dec = ostream_type::dec;
144 static BOOST_CONSTEXPR_OR_CONST fmtflags fixed = ostream_type::fixed;
145 static BOOST_CONSTEXPR_OR_CONST fmtflags hex = ostream_type::hex;
146 static BOOST_CONSTEXPR_OR_CONST fmtflags internal = ostream_type::internal;
147 static BOOST_CONSTEXPR_OR_CONST fmtflags left = ostream_type::left;
148 static BOOST_CONSTEXPR_OR_CONST fmtflags oct = ostream_type::oct;
149 static BOOST_CONSTEXPR_OR_CONST fmtflags right = ostream_type::right;
150 static BOOST_CONSTEXPR_OR_CONST fmtflags scientific = ostream_type::scientific;
151 static BOOST_CONSTEXPR_OR_CONST fmtflags showbase = ostream_type::showbase;
152 static BOOST_CONSTEXPR_OR_CONST fmtflags showpoint = ostream_type::showpoint;
153 static BOOST_CONSTEXPR_OR_CONST fmtflags skipws = ostream_type::skipws;
154 static BOOST_CONSTEXPR_OR_CONST fmtflags unitbuf = ostream_type::unitbuf;
155 static BOOST_CONSTEXPR_OR_CONST fmtflags uppercase = ostream_type::uppercase;
156 static BOOST_CONSTEXPR_OR_CONST fmtflags adjustfield = ostream_type::adjustfield;
157 static BOOST_CONSTEXPR_OR_CONST fmtflags basefield = ostream_type::basefield;
158 static BOOST_CONSTEXPR_OR_CONST fmtflags floatfield = ostream_type::floatfield;
159
160 static BOOST_CONSTEXPR_OR_CONST iostate badbit = ostream_type::badbit;
161 static BOOST_CONSTEXPR_OR_CONST iostate eofbit = ostream_type::eofbit;
162 static BOOST_CONSTEXPR_OR_CONST iostate failbit = ostream_type::failbit;
163 static BOOST_CONSTEXPR_OR_CONST iostate goodbit = ostream_type::goodbit;
164
165 static BOOST_CONSTEXPR_OR_CONST openmode app = ostream_type::app;
166 static BOOST_CONSTEXPR_OR_CONST openmode ate = ostream_type::ate;
167 static BOOST_CONSTEXPR_OR_CONST openmode binary = ostream_type::binary;
168 static BOOST_CONSTEXPR_OR_CONST openmode in = ostream_type::in;
169 static BOOST_CONSTEXPR_OR_CONST openmode out = ostream_type::out;
170 static BOOST_CONSTEXPR_OR_CONST openmode trunc = ostream_type::trunc;
171
172 static BOOST_CONSTEXPR_OR_CONST seekdir beg = ostream_type::beg;
173 static BOOST_CONSTEXPR_OR_CONST seekdir cur = ostream_type::cur;
174 static BOOST_CONSTEXPR_OR_CONST seekdir end = ostream_type::end;
175
176 static BOOST_CONSTEXPR_OR_CONST event erase_event = ostream_type::erase_event;
177 static BOOST_CONSTEXPR_OR_CONST event imbue_event = ostream_type::imbue_event;
178 static BOOST_CONSTEXPR_OR_CONST event copyfmt_event = ostream_type::copyfmt_event;
179
180 private:
181 mutable streambuf_type m_streambuf;
182 ostream_type m_stream;
183
184 public:
185 /*!
186 * Default constructor. Creates an empty record that is equivalent to the invalid record handle.
187 * The stream capability is not available after construction.
188 *
189 * \post <tt>!*this == true</tt>
190 */
basic_formatting_ostream()191 basic_formatting_ostream() : m_stream(&m_streambuf)
192 {
193 init_stream();
194 }
195
196 /*!
197 * Initializing constructor. Attaches the string to the constructed stream.
198 * The string will be used to store the formatted characters.
199 *
200 * \post <tt>!*this == false</tt>
201 * \param str The string buffer to attach.
202 */
basic_formatting_ostream(string_type & str)203 explicit basic_formatting_ostream(string_type& str) :
204 m_streambuf(str),
205 m_stream(&m_streambuf)
206 {
207 init_stream();
208 }
209
210 /*!
211 * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
212 */
~basic_formatting_ostream()213 ~basic_formatting_ostream()
214 {
215 if (m_streambuf.storage())
216 flush();
217 }
218
219 /*!
220 * Attaches the stream to the string. The string will be used to store the formatted characters.
221 *
222 * \param str The string buffer to attach.
223 */
attach(string_type & str)224 void attach(string_type& str)
225 {
226 m_streambuf.attach(str);
227 m_stream.clear(ostream_type::goodbit);
228 }
229 /*!
230 * Detaches the stream from the string. Any buffered data is flushed to the string.
231 */
detach()232 void detach()
233 {
234 m_streambuf.detach();
235 m_stream.clear(ostream_type::badbit);
236 }
237
238 /*!
239 * \returns Reference to the attached string. The string must be attached before calling this method.
240 */
str() const241 string_type const& str() const
242 {
243 string_type* storage = m_streambuf.storage();
244 BOOST_ASSERT(storage != NULL);
245
246 m_streambuf.pubsync();
247
248 return *storage;
249 }
250
251 /*!
252 * \returns Reference to the wrapped stream
253 */
stream()254 ostream_type& stream() { return m_stream; }
255
256 /*!
257 * \returns Reference to the wrapped stream
258 */
stream() const259 ostream_type const& stream() const { return m_stream; }
260
261 // std::ios_base method forwarders
flags() const262 fmtflags flags() const { return m_stream.flags(); }
flags(fmtflags f)263 fmtflags flags(fmtflags f) { return m_stream.flags(f); }
setf(fmtflags f)264 fmtflags setf(fmtflags f) { return m_stream.setf(f); }
setf(fmtflags f,fmtflags mask)265 fmtflags setf(fmtflags f, fmtflags mask) { return m_stream.setf(f, mask); }
unsetf(fmtflags f)266 void unsetf(fmtflags f) { m_stream.unsetf(f); }
267
precision() const268 std::streamsize precision() const { return m_stream.precision(); }
precision(std::streamsize p)269 std::streamsize precision(std::streamsize p) { return m_stream.precision(p); }
270
width() const271 std::streamsize width() const { return m_stream.width(); }
width(std::streamsize w)272 std::streamsize width(std::streamsize w) { return m_stream.width(w); }
273
getloc() const274 std::locale getloc() const { return m_stream.getloc(); }
imbue(std::locale const & loc)275 std::locale imbue(std::locale const& loc) { return m_stream.imbue(loc); }
276
xalloc()277 static int xalloc() { return ostream_type::xalloc(); }
iword(int index)278 long& iword(int index) { return m_stream.iword(index); }
pword(int index)279 void*& pword(int index) { return m_stream.pword(index); }
280
register_callback(event_callback fn,int index)281 void register_callback(event_callback fn, int index) { m_stream.register_callback(fn, index); }
282
sync_with_stdio(bool sync=true)283 static bool sync_with_stdio(bool sync = true) { return ostream_type::sync_with_stdio(sync); }
284
285 // std::basic_ios method forwarders
286 BOOST_EXPLICIT_OPERATOR_BOOL()
287 bool operator! () const { return !m_stream; }
288
rdstate() const289 iostate rdstate() const { return m_stream.rdstate(); }
clear(iostate state=goodbit)290 void clear(iostate state = goodbit) { m_stream.clear(state); }
setstate(iostate state)291 void setstate(iostate state) { m_stream.setstate(state); }
good() const292 bool good() const { return m_stream.good(); }
eof() const293 bool eof() const { return m_stream.eof(); }
fail() const294 bool fail() const { return m_stream.fail(); }
bad() const295 bool bad() const { return m_stream.bad(); }
296
exceptions() const297 iostate exceptions() const { return m_stream.exceptions(); }
exceptions(iostate s)298 void exceptions(iostate s) { m_stream.exceptions(s); }
299
tie() const300 ostream_type* tie() const { return m_stream.tie(); }
tie(ostream_type * strm)301 ostream_type* tie(ostream_type* strm) { return m_stream.tie(strm); }
302
rdbuf() const303 streambuf_type* rdbuf() const { return &m_streambuf; }
304
copyfmt(std::basic_ios<char_type,traits_type> & rhs)305 basic_formatting_ostream& copyfmt(std::basic_ios< char_type, traits_type >& rhs)
306 {
307 m_stream.copyfmt(rhs);
308 return *this;
309 }
copyfmt(basic_formatting_ostream & rhs)310 basic_formatting_ostream& copyfmt(basic_formatting_ostream& rhs)
311 {
312 m_stream.copyfmt(rhs.stream());
313 return *this;
314 }
315
fill() const316 char_type fill() const { return m_stream.fill(); }
fill(char_type ch)317 char_type fill(char_type ch) { return m_stream.fill(ch); }
318
narrow(char_type ch,char def) const319 char narrow(char_type ch, char def) const { return m_stream.narrow(ch, def); }
widen(char ch) const320 char_type widen(char ch) const { return m_stream.widen(ch); }
321
322 // std::basic_ostream method forwarders
flush()323 basic_formatting_ostream& flush()
324 {
325 m_stream.flush();
326 return *this;
327 }
328
tellp()329 pos_type tellp() { return m_stream.tellp(); }
seekp(pos_type pos)330 basic_formatting_ostream& seekp(pos_type pos)
331 {
332 m_stream.seekp(pos);
333 return *this;
334 }
seekp(off_type off,std::ios_base::seekdir dir)335 basic_formatting_ostream& seekp(off_type off, std::ios_base::seekdir dir)
336 {
337 m_stream.seekp(off, dir);
338 return *this;
339 }
340
put(char_type c)341 basic_formatting_ostream& put(char_type c)
342 {
343 m_stream.put(c);
344 return *this;
345 }
346
347 template< typename OtherCharT >
348 typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
put(OtherCharT c)349 put(OtherCharT c)
350 {
351 write(&c, 1);
352 return *this;
353 }
354
write(const char_type * p,std::streamsize size)355 basic_formatting_ostream& write(const char_type* p, std::streamsize size)
356 {
357 m_stream.write(p, size);
358 return *this;
359 }
360
361 template< typename OtherCharT >
362 typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
write(const OtherCharT * p,std::streamsize size)363 write(const OtherCharT* p, std::streamsize size)
364 {
365 sentry guard(*this);
366 if (guard)
367 {
368 m_stream.flush();
369
370 string_type* storage = m_streambuf.storage();
371 aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc());
372 }
373
374 return *this;
375 }
376
operator <<(ios_base_manip manip)377 basic_formatting_ostream& operator<< (ios_base_manip manip)
378 {
379 m_stream << manip;
380 return *this;
381 }
operator <<(basic_ios_manip manip)382 basic_formatting_ostream& operator<< (basic_ios_manip manip)
383 {
384 m_stream << manip;
385 return *this;
386 }
operator <<(stream_manip manip)387 basic_formatting_ostream& operator<< (stream_manip manip)
388 {
389 m_stream << manip;
390 return *this;
391 }
392
operator <<(char c)393 basic_formatting_ostream& operator<< (char c)
394 {
395 return this->formatted_write(&c, 1);
396 }
operator <<(const char * p)397 basic_formatting_ostream& operator<< (const char* p)
398 {
399 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char >::length(p)));
400 }
401
402 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
operator <<(wchar_t c)403 basic_formatting_ostream& operator<< (wchar_t c)
404 {
405 return this->formatted_write(&c, 1);
406 }
operator <<(const wchar_t * p)407 basic_formatting_ostream& operator<< (const wchar_t* p)
408 {
409 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< wchar_t >::length(p)));
410 }
411 #endif
412 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
413 #if !defined(BOOST_NO_CXX11_CHAR16_T)
operator <<(char16_t c)414 basic_formatting_ostream& operator<< (char16_t c)
415 {
416 return this->formatted_write(&c, 1);
417 }
operator <<(const char16_t * p)418 basic_formatting_ostream& operator<< (const char16_t* p)
419 {
420 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char16_t >::length(p)));
421 }
422 #endif
423 #if !defined(BOOST_NO_CXX11_CHAR32_T)
operator <<(char32_t c)424 basic_formatting_ostream& operator<< (char32_t c)
425 {
426 return this->formatted_write(&c, 1);
427 }
operator <<(const char32_t * p)428 basic_formatting_ostream& operator<< (const char32_t* p)
429 {
430 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char32_t >::length(p)));
431 }
432 #endif
433 #endif
434
operator <<(bool value)435 basic_formatting_ostream& operator<< (bool value)
436 {
437 m_stream << value;
438 return *this;
439 }
operator <<(signed char value)440 basic_formatting_ostream& operator<< (signed char value)
441 {
442 m_stream << value;
443 return *this;
444 }
operator <<(unsigned char value)445 basic_formatting_ostream& operator<< (unsigned char value)
446 {
447 m_stream << value;
448 return *this;
449 }
operator <<(short value)450 basic_formatting_ostream& operator<< (short value)
451 {
452 m_stream << value;
453 return *this;
454 }
operator <<(unsigned short value)455 basic_formatting_ostream& operator<< (unsigned short value)
456 {
457 m_stream << value;
458 return *this;
459 }
operator <<(int value)460 basic_formatting_ostream& operator<< (int value)
461 {
462 m_stream << value;
463 return *this;
464 }
operator <<(unsigned int value)465 basic_formatting_ostream& operator<< (unsigned int value)
466 {
467 m_stream << value;
468 return *this;
469 }
operator <<(long value)470 basic_formatting_ostream& operator<< (long value)
471 {
472 m_stream << value;
473 return *this;
474 }
operator <<(unsigned long value)475 basic_formatting_ostream& operator<< (unsigned long value)
476 {
477 m_stream << value;
478 return *this;
479 }
480 #if !defined(BOOST_NO_LONG_LONG)
operator <<(long long value)481 basic_formatting_ostream& operator<< (long long value)
482 {
483 m_stream << value;
484 return *this;
485 }
operator <<(unsigned long long value)486 basic_formatting_ostream& operator<< (unsigned long long value)
487 {
488 m_stream << value;
489 return *this;
490 }
491 #endif
492
operator <<(float value)493 basic_formatting_ostream& operator<< (float value)
494 {
495 m_stream << value;
496 return *this;
497 }
operator <<(double value)498 basic_formatting_ostream& operator<< (double value)
499 {
500 m_stream << value;
501 return *this;
502 }
operator <<(long double value)503 basic_formatting_ostream& operator<< (long double value)
504 {
505 m_stream << value;
506 return *this;
507 }
508
operator <<(const void * value)509 basic_formatting_ostream& operator<< (const void* value)
510 {
511 m_stream << value;
512 return *this;
513 }
514
operator <<(std::basic_streambuf<char_type,traits_type> * buf)515 basic_formatting_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf)
516 {
517 m_stream << buf;
518 return *this;
519 }
520
521 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
522 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,std::basic_string<OtherCharT,OtherTraitsT,OtherAllocatorT> const & str)523 operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
524 {
525 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
526 }
527
528 template< typename OtherCharT, typename OtherTraitsT >
529 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_literal<OtherCharT,OtherTraitsT> const & str)530 operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
531 {
532 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
533 }
534
535 template< typename OtherCharT, typename OtherTraitsT >
536 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_ref<OtherCharT,OtherTraitsT> const & str)537 operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
538 {
539 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
540 }
541
542 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
543 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,std::basic_string<OtherCharT,OtherTraitsT,OtherAllocatorT> & str)544 operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
545 {
546 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
547 }
548
549 template< typename OtherCharT, typename OtherTraitsT >
550 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_literal<OtherCharT,OtherTraitsT> & str)551 operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
552 {
553 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
554 }
555
556 template< typename OtherCharT, typename OtherTraitsT >
557 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_ref<OtherCharT,OtherTraitsT> & str)558 operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
559 {
560 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
561 }
562
563 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
564 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
565 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,std::basic_string<OtherCharT,OtherTraitsT,OtherAllocatorT> const & str)566 operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
567 {
568 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
569 }
570
571 template< typename OtherCharT, typename OtherTraitsT >
572 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_literal<OtherCharT,OtherTraitsT> const & str)573 operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
574 {
575 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
576 }
577
578 template< typename OtherCharT, typename OtherTraitsT >
579 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_ref<OtherCharT,OtherTraitsT> const & str)580 operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
581 {
582 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
583 }
584
585 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
586 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,std::basic_string<OtherCharT,OtherTraitsT,OtherAllocatorT> & str)587 operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
588 {
589 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
590 }
591
592 template< typename OtherCharT, typename OtherTraitsT >
593 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_literal<OtherCharT,OtherTraitsT> & str)594 operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
595 {
596 return strm.formatted_write(str.c_str(), static_cast< std::streamsize >(str.size()));
597 }
598
599 template< typename OtherCharT, typename OtherTraitsT >
600 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_ref<OtherCharT,OtherTraitsT> & str)601 operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
602 {
603 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
604 }
605 #endif
606
607 private:
init_stream()608 void init_stream()
609 {
610 m_stream.clear(m_streambuf.storage() ? ostream_type::goodbit : ostream_type::badbit);
611 m_stream.flags
612 (
613 ostream_type::dec |
614 ostream_type::skipws |
615 ostream_type::boolalpha // this differs from the default stream flags but makes logs look better
616 );
617 m_stream.width(0);
618 m_stream.precision(6);
619 m_stream.fill(static_cast< char_type >(' '));
620 }
621
formatted_write(const char_type * p,std::streamsize size)622 basic_formatting_ostream& formatted_write(const char_type* p, std::streamsize size)
623 {
624 sentry guard(*this);
625 if (guard)
626 {
627 m_stream.flush();
628
629 if (m_stream.width() <= size)
630 m_streambuf.storage()->append(p, static_cast< std::size_t >(size));
631 else
632 this->aligned_write(p, size);
633
634 m_stream.width(0);
635 }
636
637 return *this;
638 }
639
640 template< typename OtherCharT >
formatted_write(const OtherCharT * p,std::streamsize size)641 basic_formatting_ostream& formatted_write(const OtherCharT* p, std::streamsize size)
642 {
643 sentry guard(*this);
644 if (guard)
645 {
646 m_stream.flush();
647
648 if (m_stream.width() <= size)
649 aux::code_convert(p, static_cast< std::size_t >(size), *m_streambuf.storage(), m_stream.getloc());
650 else
651 this->aligned_write(p, size);
652
653 m_stream.width(0);
654 }
655
656 return *this;
657 }
658
659 void aligned_write(const char_type* p, std::streamsize size);
660
661 template< typename OtherCharT >
662 void aligned_write(const OtherCharT* p, std::streamsize size);
663
664 //! Copy constructor (closed)
665 BOOST_DELETED_FUNCTION(basic_formatting_ostream(basic_formatting_ostream const& that))
666 //! Assignment (closed)
667 BOOST_DELETED_FUNCTION(basic_formatting_ostream& operator= (basic_formatting_ostream const& that))
668 };
669
670 template< typename CharT, typename TraitsT, typename AllocatorT >
671 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::boolalpha;
672 template< typename CharT, typename TraitsT, typename AllocatorT >
673 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::dec;
674 template< typename CharT, typename TraitsT, typename AllocatorT >
675 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fixed;
676 template< typename CharT, typename TraitsT, typename AllocatorT >
677 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::hex;
678 template< typename CharT, typename TraitsT, typename AllocatorT >
679 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::internal;
680 template< typename CharT, typename TraitsT, typename AllocatorT >
681 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::left;
682 template< typename CharT, typename TraitsT, typename AllocatorT >
683 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::oct;
684 template< typename CharT, typename TraitsT, typename AllocatorT >
685 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::right;
686 template< typename CharT, typename TraitsT, typename AllocatorT >
687 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::scientific;
688 template< typename CharT, typename TraitsT, typename AllocatorT >
689 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showbase;
690 template< typename CharT, typename TraitsT, typename AllocatorT >
691 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showpoint;
692 template< typename CharT, typename TraitsT, typename AllocatorT >
693 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::skipws;
694 template< typename CharT, typename TraitsT, typename AllocatorT >
695 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::unitbuf;
696 template< typename CharT, typename TraitsT, typename AllocatorT >
697 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::uppercase;
698 template< typename CharT, typename TraitsT, typename AllocatorT >
699 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::adjustfield;
700 template< typename CharT, typename TraitsT, typename AllocatorT >
701 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::basefield;
702 template< typename CharT, typename TraitsT, typename AllocatorT >
703 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::floatfield;
704
705 template< typename CharT, typename TraitsT, typename AllocatorT >
706 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::badbit;
707 template< typename CharT, typename TraitsT, typename AllocatorT >
708 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::eofbit;
709 template< typename CharT, typename TraitsT, typename AllocatorT >
710 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::failbit;
711 template< typename CharT, typename TraitsT, typename AllocatorT >
712 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::goodbit;
713
714 template< typename CharT, typename TraitsT, typename AllocatorT >
715 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::app;
716 template< typename CharT, typename TraitsT, typename AllocatorT >
717 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::ate;
718 template< typename CharT, typename TraitsT, typename AllocatorT >
719 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::binary;
720 template< typename CharT, typename TraitsT, typename AllocatorT >
721 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::in;
722 template< typename CharT, typename TraitsT, typename AllocatorT >
723 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::out;
724 template< typename CharT, typename TraitsT, typename AllocatorT >
725 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::trunc;
726
727 template< typename CharT, typename TraitsT, typename AllocatorT >
728 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::beg;
729 template< typename CharT, typename TraitsT, typename AllocatorT >
730 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::cur;
731 template< typename CharT, typename TraitsT, typename AllocatorT >
732 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::end;
733
734 template< typename CharT, typename TraitsT, typename AllocatorT >
735 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::erase_event;
736 template< typename CharT, typename TraitsT, typename AllocatorT >
737 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::imbue_event;
738 template< typename CharT, typename TraitsT, typename AllocatorT >
739 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::copyfmt_event;
740
741 template< typename CharT, typename TraitsT, typename AllocatorT >
aligned_write(const char_type * p,std::streamsize size)742 void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const char_type* p, std::streamsize size)
743 {
744 string_type* const storage = m_streambuf.storage();
745 typename string_type::size_type const alignment_size =
746 static_cast< typename string_type::size_type >(m_stream.width() - size);
747 const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
748 if (align_left)
749 {
750 storage->append(p, static_cast< std::size_t >(size));
751 storage->append(alignment_size, m_stream.fill());
752 }
753 else
754 {
755 storage->append(alignment_size, m_stream.fill());
756 storage->append(p, static_cast< std::size_t >(size));
757 }
758 }
759
760 template< typename CharT, typename TraitsT, typename AllocatorT >
761 template< typename OtherCharT >
aligned_write(const OtherCharT * p,std::streamsize size)762 void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const OtherCharT* p, std::streamsize size)
763 {
764 string_type* const storage = m_streambuf.storage();
765 typename string_type::size_type const alignment_size =
766 static_cast< typename string_type::size_type >(m_stream.width() - size);
767 const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
768 if (align_left)
769 {
770 aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc());
771 storage->append(alignment_size, m_stream.fill());
772 }
773 else
774 {
775 storage->append(alignment_size, m_stream.fill());
776 aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_stream.getloc());
777 }
778 }
779
780 // Implementation note: these operators below should be the least attractive for the compiler
781 // so that user's overloads are chosen, when present. We use function template partial ordering for this purpose.
782 template< typename StreamT, typename T >
783 inline typename boost::log::aux::enable_if_formatting_ostream< StreamT, StreamT& >::type
operator <<(StreamT & strm,T const & value)784 operator<< (StreamT& strm, T const& value)
785 {
786 strm.stream() << value;
787 return strm;
788 }
789
790 template< typename StreamT, typename T >
791 inline typename boost::log::aux::enable_if_formatting_ostream< StreamT, StreamT& >::type
operator <<(StreamT & strm,T & value)792 operator<< (StreamT& strm, T& value)
793 {
794 strm.stream() << value;
795 return strm;
796 }
797
798 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
799
800 template< typename StreamT, typename T >
801 inline typename boost::log::aux::enable_if_formatting_ostream< StreamT, StreamT& >::type
operator <<(StreamT && strm,T const & value)802 operator<< (StreamT&& strm, T const& value)
803 {
804 strm.stream() << value;
805 return strm;
806 }
807
808 template< typename StreamT, typename T >
809 inline typename boost::log::aux::enable_if_formatting_ostream< StreamT, StreamT& >::type
operator <<(StreamT && strm,T & value)810 operator<< (StreamT&& strm, T& value)
811 {
812 strm.stream() << value;
813 return strm;
814 }
815
816 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
817
818 BOOST_LOG_CLOSE_NAMESPACE // namespace log
819
820 } // namespace boost
821
822 #include <boost/log/detail/footer.hpp>
823
824 #endif // BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
825