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/enable_if.hpp>
23 #include <boost/core/explicit_operator_bool.hpp>
24 #include <boost/utility/string_ref_fwd.hpp>
25 #include <boost/utility/string_view_fwd.hpp>
26 #include <boost/type_traits/is_enum.hpp>
27 #include <boost/type_traits/is_scalar.hpp>
28 #include <boost/type_traits/remove_cv.hpp>
29 #include <boost/log/detail/config.hpp>
30 #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
31 #include <string_view>
32 #endif
33 #include <boost/log/detail/attachable_sstream_buf.hpp>
34 #include <boost/log/detail/code_conversion.hpp>
35 #include <boost/log/utility/string_literal_fwd.hpp>
36 #include <boost/log/utility/formatting_ostream_fwd.hpp>
37 #include <boost/log/detail/header.hpp>
38
39 #ifdef BOOST_HAS_PRAGMA_ONCE
40 #pragma once
41 #endif
42
43 namespace boost {
44
45 BOOST_LOG_OPEN_NAMESPACE
46
47 namespace aux {
48
49 template< typename T, typename R >
50 struct enable_if_streamable_char_type {};
51 template< typename T, typename R >
52 struct disable_if_streamable_char_type { typedef R type; };
53 template< typename R >
54 struct enable_if_streamable_char_type< char, R > { typedef R type; };
55 template< typename R >
56 struct disable_if_streamable_char_type< char, R > {};
57 template< typename R >
58 struct enable_if_streamable_char_type< wchar_t, R > { typedef R type; };
59 template< typename R >
60 struct disable_if_streamable_char_type< wchar_t, R > {};
61 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
62 #if !defined(BOOST_NO_CXX11_CHAR16_T)
63 template< typename R >
64 struct enable_if_streamable_char_type< char16_t, R > { typedef R type; };
65 template< typename R >
66 struct disable_if_streamable_char_type< char16_t, R > {};
67 #endif
68 #if !defined(BOOST_NO_CXX11_CHAR32_T)
69 template< typename R >
70 struct enable_if_streamable_char_type< char32_t, R > { typedef R type; };
71 template< typename R >
72 struct disable_if_streamable_char_type< char32_t, R > {};
73 #endif
74 #endif
75
76 template< typename StreamT, typename T, bool ByValueV, typename R >
77 struct enable_formatting_ostream_generic_operator {};
78
79 template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
80 struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, false, R > :
81 public boost::disable_if_c< boost::is_scalar< typename boost::remove_cv< T >::type >::value, R >
82 {
83 };
84
85 template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
86 struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, true, R > :
87 public boost::enable_if_c< boost::is_enum< typename boost::remove_cv< T >::type >::value, R >
88 {
89 };
90
91 template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
92 struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T*, true, R > :
93 public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R >
94 {
95 };
96
97 } // namespace aux
98
99 /*!
100 * \brief Stream wrapper for log records formatting.
101 *
102 * This stream wrapper is used by the library for log record formatting. It implements the standard string stream interface
103 * with a few differences:
104 *
105 * \li It does not derive from standard types <tt>std::basic_ostream</tt>, <tt>std::basic_ios</tt> and <tt>std::ios_base</tt>,
106 * although it tries to implement their interfaces closely. There are a few small differences, mostly regarding <tt>rdbuf</tt>
107 * and <tt>str</tt> signatures, as well as the supported insertion operator overloads. The actual wrapped stream can be accessed
108 * through the <tt>stream</tt> methods.
109 * \li By default, \c bool values are formatted using alphabetical representation rather than numeric.
110 * \li The stream supports writing strings of character types different from the stream character type. The stream will perform
111 * character code conversion as needed using the imbued locale.
112 * \li The stream operates on an external string object rather than on the embedded one. The string can be attached or detached
113 * from the stream dynamically.
114 *
115 * Although <tt>basic_formatting_ostream</tt> does not derive from <tt>std::basic_ostream</tt>, users are not required to add
116 * special overloads of \c operator<< for it since the stream will by default reuse the operators for <tt>std::basic_ostream</tt>.
117 * However, one can define special overloads of \c operator<< for <tt>basic_formatting_ostream</tt> if a certain type needs
118 * special formatting when output to log.
119 */
120 template< typename CharT, typename TraitsT, typename AllocatorT >
121 class basic_formatting_ostream
122 {
123 public:
124 //! Character type
125 typedef CharT char_type;
126 //! Character traits
127 typedef TraitsT traits_type;
128 //! Memory allocator
129 typedef AllocatorT allocator_type;
130 //! Stream buffer type
131 typedef boost::log::aux::basic_ostringstreambuf< char_type, traits_type, allocator_type > streambuf_type;
132 //! Target string type
133 typedef typename streambuf_type::string_type string_type;
134
135 //! Stream type
136 typedef std::basic_ostream< char_type, traits_type > ostream_type;
137 //! Stream position type
138 typedef typename ostream_type::pos_type pos_type;
139 //! Stream offset type
140 typedef typename ostream_type::off_type off_type;
141 //! Integer type for characters
142 typedef typename ostream_type::int_type int_type;
143
144 typedef typename ostream_type::failure failure;
145 typedef typename ostream_type::fmtflags fmtflags;
146 typedef typename ostream_type::iostate iostate;
147 typedef typename ostream_type::openmode openmode;
148 typedef typename ostream_type::seekdir seekdir;
149 typedef typename ostream_type::Init Init;
150
151 typedef typename ostream_type::event event;
152 typedef typename ostream_type::event_callback event_callback;
153
154 class sentry :
155 public ostream_type::sentry
156 {
157 typedef typename ostream_type::sentry base_type;
158
159 public:
sentry(basic_formatting_ostream & strm)160 explicit sentry(basic_formatting_ostream& strm) : base_type(strm.stream())
161 {
162 }
163
164 // A workaround for Solaris Studio 12.4 compiler, see: https://svn.boost.org/trac/boost/ticket/11545
165 BOOST_EXPLICIT_OPERATOR_BOOL()
166 bool operator! () const { return !static_cast< base_type const& >(*this); }
167
168 BOOST_DELETED_FUNCTION(sentry(sentry const&))
169 BOOST_DELETED_FUNCTION(sentry& operator= (sentry const&))
170 };
171
172 protected:
173 // Function types
174 typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
175 typedef std::basic_ios< char_type, traits_type >& (*basic_ios_manip)(std::basic_ios< char_type, traits_type >&);
176 typedef ostream_type& (*stream_manip)(ostream_type&);
177
178 public:
179 static BOOST_CONSTEXPR_OR_CONST fmtflags boolalpha = ostream_type::boolalpha;
180 static BOOST_CONSTEXPR_OR_CONST fmtflags dec = ostream_type::dec;
181 static BOOST_CONSTEXPR_OR_CONST fmtflags fixed = ostream_type::fixed;
182 static BOOST_CONSTEXPR_OR_CONST fmtflags hex = ostream_type::hex;
183 static BOOST_CONSTEXPR_OR_CONST fmtflags internal = ostream_type::internal;
184 static BOOST_CONSTEXPR_OR_CONST fmtflags left = ostream_type::left;
185 static BOOST_CONSTEXPR_OR_CONST fmtflags oct = ostream_type::oct;
186 static BOOST_CONSTEXPR_OR_CONST fmtflags right = ostream_type::right;
187 static BOOST_CONSTEXPR_OR_CONST fmtflags scientific = ostream_type::scientific;
188 static BOOST_CONSTEXPR_OR_CONST fmtflags showbase = ostream_type::showbase;
189 static BOOST_CONSTEXPR_OR_CONST fmtflags showpoint = ostream_type::showpoint;
190 static BOOST_CONSTEXPR_OR_CONST fmtflags skipws = ostream_type::skipws;
191 static BOOST_CONSTEXPR_OR_CONST fmtflags unitbuf = ostream_type::unitbuf;
192 static BOOST_CONSTEXPR_OR_CONST fmtflags uppercase = ostream_type::uppercase;
193 static BOOST_CONSTEXPR_OR_CONST fmtflags adjustfield = ostream_type::adjustfield;
194 static BOOST_CONSTEXPR_OR_CONST fmtflags basefield = ostream_type::basefield;
195 static BOOST_CONSTEXPR_OR_CONST fmtflags floatfield = ostream_type::floatfield;
196
197 static BOOST_CONSTEXPR_OR_CONST iostate badbit = ostream_type::badbit;
198 static BOOST_CONSTEXPR_OR_CONST iostate eofbit = ostream_type::eofbit;
199 static BOOST_CONSTEXPR_OR_CONST iostate failbit = ostream_type::failbit;
200 static BOOST_CONSTEXPR_OR_CONST iostate goodbit = ostream_type::goodbit;
201
202 static BOOST_CONSTEXPR_OR_CONST openmode app = ostream_type::app;
203 static BOOST_CONSTEXPR_OR_CONST openmode ate = ostream_type::ate;
204 static BOOST_CONSTEXPR_OR_CONST openmode binary = ostream_type::binary;
205 static BOOST_CONSTEXPR_OR_CONST openmode in = ostream_type::in;
206 static BOOST_CONSTEXPR_OR_CONST openmode out = ostream_type::out;
207 static BOOST_CONSTEXPR_OR_CONST openmode trunc = ostream_type::trunc;
208
209 static BOOST_CONSTEXPR_OR_CONST seekdir beg = ostream_type::beg;
210 static BOOST_CONSTEXPR_OR_CONST seekdir cur = ostream_type::cur;
211 static BOOST_CONSTEXPR_OR_CONST seekdir end = ostream_type::end;
212
213 static BOOST_CONSTEXPR_OR_CONST event erase_event = ostream_type::erase_event;
214 static BOOST_CONSTEXPR_OR_CONST event imbue_event = ostream_type::imbue_event;
215 static BOOST_CONSTEXPR_OR_CONST event copyfmt_event = ostream_type::copyfmt_event;
216
217 private:
218 mutable streambuf_type m_streambuf;
219 ostream_type m_stream;
220
221 public:
222 /*!
223 * Default constructor. Creates an empty record that is equivalent to the invalid record handle.
224 * The stream capability is not available after construction.
225 *
226 * \post <tt>!*this == true</tt>
227 */
basic_formatting_ostream()228 basic_formatting_ostream() : m_stream(&m_streambuf)
229 {
230 init_stream();
231 }
232
233 /*!
234 * Initializing constructor. Attaches the string to the constructed stream.
235 * The string will be used to store the formatted characters.
236 *
237 * \post <tt>!*this == false</tt>
238 * \param str The string buffer to attach.
239 */
basic_formatting_ostream(string_type & str)240 explicit basic_formatting_ostream(string_type& str) :
241 m_streambuf(str),
242 m_stream(&m_streambuf)
243 {
244 init_stream();
245 }
246
247 /*!
248 * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
249 */
~basic_formatting_ostream()250 ~basic_formatting_ostream()
251 {
252 if (m_streambuf.storage())
253 flush();
254 }
255
256 /*!
257 * Attaches the stream to the string. The string will be used to store the formatted characters.
258 *
259 * \param str The string buffer to attach.
260 */
attach(string_type & str)261 void attach(string_type& str)
262 {
263 m_streambuf.attach(str);
264 m_stream.clear(ostream_type::goodbit);
265 }
266 /*!
267 * Detaches the stream from the string. Any buffered data is flushed to the string.
268 */
detach()269 void detach()
270 {
271 m_streambuf.detach();
272 m_stream.clear(ostream_type::badbit);
273 }
274
275 /*!
276 * \returns Reference to the attached string. The string must be attached before calling this method.
277 */
str() const278 string_type const& str() const
279 {
280 string_type* const storage = m_streambuf.storage();
281 BOOST_ASSERT(storage != NULL);
282
283 m_streambuf.pubsync();
284
285 return *storage;
286 }
287
288 /*!
289 * \returns Reference to the wrapped stream
290 */
stream()291 ostream_type& stream() { return m_stream; }
292
293 /*!
294 * \returns Reference to the wrapped stream
295 */
stream() const296 ostream_type const& stream() const { return m_stream; }
297
298 // std::ios_base method forwarders
flags() const299 fmtflags flags() const { return m_stream.flags(); }
flags(fmtflags f)300 fmtflags flags(fmtflags f) { return m_stream.flags(f); }
setf(fmtflags f)301 fmtflags setf(fmtflags f) { return m_stream.setf(f); }
setf(fmtflags f,fmtflags mask)302 fmtflags setf(fmtflags f, fmtflags mask) { return m_stream.setf(f, mask); }
unsetf(fmtflags f)303 void unsetf(fmtflags f) { m_stream.unsetf(f); }
304
precision() const305 std::streamsize precision() const { return m_stream.precision(); }
precision(std::streamsize p)306 std::streamsize precision(std::streamsize p) { return m_stream.precision(p); }
307
width() const308 std::streamsize width() const { return m_stream.width(); }
width(std::streamsize w)309 std::streamsize width(std::streamsize w) { return m_stream.width(w); }
310
getloc() const311 std::locale getloc() const { return m_stream.getloc(); }
imbue(std::locale const & loc)312 std::locale imbue(std::locale const& loc) { return m_stream.imbue(loc); }
313
xalloc()314 static int xalloc() { return ostream_type::xalloc(); }
iword(int index)315 long& iword(int index) { return m_stream.iword(index); }
pword(int index)316 void*& pword(int index) { return m_stream.pword(index); }
317
register_callback(event_callback fn,int index)318 void register_callback(event_callback fn, int index) { m_stream.register_callback(fn, index); }
319
sync_with_stdio(bool sync=true)320 static bool sync_with_stdio(bool sync = true) { return ostream_type::sync_with_stdio(sync); }
321
322 // std::basic_ios method forwarders
323 BOOST_EXPLICIT_OPERATOR_BOOL()
324 bool operator! () const { return !m_stream; }
325
rdstate() const326 iostate rdstate() const { return m_stream.rdstate(); }
clear(iostate state=goodbit)327 void clear(iostate state = goodbit) { m_stream.clear(state); }
setstate(iostate state)328 void setstate(iostate state) { m_stream.setstate(state); }
good() const329 bool good() const { return m_stream.good(); }
eof() const330 bool eof() const { return m_stream.eof(); }
fail() const331 bool fail() const { return m_stream.fail(); }
bad() const332 bool bad() const { return m_stream.bad(); }
333
exceptions() const334 iostate exceptions() const { return m_stream.exceptions(); }
exceptions(iostate s)335 void exceptions(iostate s) { m_stream.exceptions(s); }
336
tie() const337 ostream_type* tie() const { return m_stream.tie(); }
tie(ostream_type * strm)338 ostream_type* tie(ostream_type* strm) { return m_stream.tie(strm); }
339
rdbuf() const340 streambuf_type* rdbuf() const { return &m_streambuf; }
341
copyfmt(std::basic_ios<char_type,traits_type> & rhs)342 basic_formatting_ostream& copyfmt(std::basic_ios< char_type, traits_type >& rhs)
343 {
344 m_stream.copyfmt(rhs);
345 return *this;
346 }
copyfmt(basic_formatting_ostream & rhs)347 basic_formatting_ostream& copyfmt(basic_formatting_ostream& rhs)
348 {
349 m_stream.copyfmt(rhs.stream());
350 return *this;
351 }
352
fill() const353 char_type fill() const { return m_stream.fill(); }
fill(char_type ch)354 char_type fill(char_type ch) { return m_stream.fill(ch); }
355
narrow(char_type ch,char def) const356 char narrow(char_type ch, char def) const { return m_stream.narrow(ch, def); }
widen(char ch) const357 char_type widen(char ch) const { return m_stream.widen(ch); }
358
359 // std::basic_ostream method forwarders
flush()360 basic_formatting_ostream& flush()
361 {
362 m_stream.flush();
363 return *this;
364 }
365
tellp()366 pos_type tellp() { return m_stream.tellp(); }
seekp(pos_type pos)367 basic_formatting_ostream& seekp(pos_type pos)
368 {
369 m_stream.seekp(pos);
370 return *this;
371 }
seekp(off_type off,std::ios_base::seekdir dir)372 basic_formatting_ostream& seekp(off_type off, std::ios_base::seekdir dir)
373 {
374 m_stream.seekp(off, dir);
375 return *this;
376 }
377
put(char_type c)378 basic_formatting_ostream& put(char_type c)
379 {
380 m_stream.put(c);
381 return *this;
382 }
383
384 template< typename OtherCharT >
385 typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
put(OtherCharT c)386 put(OtherCharT c)
387 {
388 write(&c, 1);
389 return *this;
390 }
391
write(const char_type * p,std::streamsize size)392 basic_formatting_ostream& write(const char_type* p, std::streamsize size)
393 {
394 m_stream.write(p, size);
395 return *this;
396 }
397
398 template< typename OtherCharT >
399 typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
write(const OtherCharT * p,std::streamsize size)400 write(const OtherCharT* p, std::streamsize size)
401 {
402 sentry guard(*this);
403 if (!!guard)
404 {
405 m_stream.flush();
406
407 if (!m_streambuf.storage_overflow())
408 {
409 string_type* storage = m_streambuf.storage();
410 if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
411 m_streambuf.storage_overflow(true);
412 }
413 }
414
415 return *this;
416 }
417
operator <<(ios_base_manip manip)418 basic_formatting_ostream& operator<< (ios_base_manip manip)
419 {
420 m_stream << manip;
421 return *this;
422 }
operator <<(basic_ios_manip manip)423 basic_formatting_ostream& operator<< (basic_ios_manip manip)
424 {
425 m_stream << manip;
426 return *this;
427 }
operator <<(stream_manip manip)428 basic_formatting_ostream& operator<< (stream_manip manip)
429 {
430 m_stream << manip;
431 return *this;
432 }
433
operator <<(char c)434 basic_formatting_ostream& operator<< (char c)
435 {
436 return this->formatted_write(&c, 1);
437 }
operator <<(const char * p)438 basic_formatting_ostream& operator<< (const char* p)
439 {
440 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char >::length(p)));
441 }
442
443 // When no native character type is supported, the following overloads are disabled as they have ambiguous meaning.
444 // Use basic_string_view or basic_string to explicitly indicate that the data is a string.
445 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
operator <<(wchar_t c)446 basic_formatting_ostream& operator<< (wchar_t c)
447 {
448 return this->formatted_write(&c, 1);
449 }
operator <<(const wchar_t * p)450 basic_formatting_ostream& operator<< (const wchar_t* p)
451 {
452 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< wchar_t >::length(p)));
453 }
454 #endif
455 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
456 #if !defined(BOOST_NO_CXX11_CHAR16_T)
operator <<(char16_t c)457 basic_formatting_ostream& operator<< (char16_t c)
458 {
459 return this->formatted_write(&c, 1);
460 }
operator <<(const char16_t * p)461 basic_formatting_ostream& operator<< (const char16_t* p)
462 {
463 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char16_t >::length(p)));
464 }
465 #endif
466 #if !defined(BOOST_NO_CXX11_CHAR32_T)
operator <<(char32_t c)467 basic_formatting_ostream& operator<< (char32_t c)
468 {
469 return this->formatted_write(&c, 1);
470 }
operator <<(const char32_t * p)471 basic_formatting_ostream& operator<< (const char32_t* p)
472 {
473 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char32_t >::length(p)));
474 }
475 #endif
476 #endif
477
operator <<(bool value)478 basic_formatting_ostream& operator<< (bool value)
479 {
480 m_stream << value;
481 return *this;
482 }
operator <<(signed char value)483 basic_formatting_ostream& operator<< (signed char value)
484 {
485 m_stream << value;
486 return *this;
487 }
operator <<(unsigned char value)488 basic_formatting_ostream& operator<< (unsigned char value)
489 {
490 m_stream << value;
491 return *this;
492 }
operator <<(short value)493 basic_formatting_ostream& operator<< (short value)
494 {
495 m_stream << value;
496 return *this;
497 }
operator <<(unsigned short value)498 basic_formatting_ostream& operator<< (unsigned short value)
499 {
500 m_stream << value;
501 return *this;
502 }
operator <<(int value)503 basic_formatting_ostream& operator<< (int value)
504 {
505 m_stream << value;
506 return *this;
507 }
operator <<(unsigned int value)508 basic_formatting_ostream& operator<< (unsigned int value)
509 {
510 m_stream << value;
511 return *this;
512 }
operator <<(long value)513 basic_formatting_ostream& operator<< (long value)
514 {
515 m_stream << value;
516 return *this;
517 }
operator <<(unsigned long value)518 basic_formatting_ostream& operator<< (unsigned long value)
519 {
520 m_stream << value;
521 return *this;
522 }
523 #if !defined(BOOST_NO_LONG_LONG)
operator <<(long long value)524 basic_formatting_ostream& operator<< (long long value)
525 {
526 m_stream << value;
527 return *this;
528 }
operator <<(unsigned long long value)529 basic_formatting_ostream& operator<< (unsigned long long value)
530 {
531 m_stream << value;
532 return *this;
533 }
534 #endif
535
operator <<(float value)536 basic_formatting_ostream& operator<< (float value)
537 {
538 m_stream << value;
539 return *this;
540 }
operator <<(double value)541 basic_formatting_ostream& operator<< (double value)
542 {
543 m_stream << value;
544 return *this;
545 }
operator <<(long double value)546 basic_formatting_ostream& operator<< (long double value)
547 {
548 m_stream << value;
549 return *this;
550 }
551
operator <<(std::basic_streambuf<char_type,traits_type> * buf)552 basic_formatting_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf)
553 {
554 m_stream << buf;
555 return *this;
556 }
557
558 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
559 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)560 operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
561 {
562 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
563 }
564
565 #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
566 template< typename OtherCharT, typename OtherTraitsT >
567 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,std::basic_string_view<OtherCharT,OtherTraitsT> const & str)568 operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str)
569 {
570 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
571 }
572 #endif
573
574 template< typename OtherCharT, typename OtherTraitsT >
575 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)576 operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
577 {
578 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
579 }
580
581 template< typename OtherCharT, typename OtherTraitsT >
582 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_view<OtherCharT,OtherTraitsT> const & str)583 operator<< (basic_formatting_ostream& strm, basic_string_view< OtherCharT, OtherTraitsT > const& str)
584 {
585 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
586 }
587
588 // Deprecated overload
589 template< typename OtherCharT, typename OtherTraitsT >
590 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)591 operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
592 {
593 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
594 }
595
596 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
597 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)598 operator<< (basic_formatting_ostream& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
599 {
600 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
601 }
602
603 #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
604 template< typename OtherCharT, typename OtherTraitsT >
605 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,std::basic_string_view<OtherCharT,OtherTraitsT> & str)606 operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str)
607 {
608 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
609 }
610 #endif
611
612 template< typename OtherCharT, typename OtherTraitsT >
613 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_literal<OtherCharT,OtherTraitsT> & str)614 operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
615 {
616 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
617 }
618
619 template< typename OtherCharT, typename OtherTraitsT >
620 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_view<OtherCharT,OtherTraitsT> & str)621 operator<< (basic_formatting_ostream& strm, basic_string_view< OtherCharT, OtherTraitsT >& str)
622 {
623 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
624 }
625
626 // Deprecated overload
627 template< typename OtherCharT, typename OtherTraitsT >
628 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream & strm,basic_string_ref<OtherCharT,OtherTraitsT> & str)629 operator<< (basic_formatting_ostream& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
630 {
631 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
632 }
633
634 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
635 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
636 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)637 operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT > const& str)
638 {
639 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
640 }
641
642 #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
643 template< typename OtherCharT, typename OtherTraitsT >
644 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,std::basic_string_view<OtherCharT,OtherTraitsT> const & str)645 operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str)
646 {
647 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
648 }
649 #endif
650
651 template< typename OtherCharT, typename OtherTraitsT >
652 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)653 operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str)
654 {
655 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
656 }
657
658 template< typename OtherCharT, typename OtherTraitsT >
659 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_view<OtherCharT,OtherTraitsT> const & str)660 operator<< (basic_formatting_ostream&& strm, basic_string_view< OtherCharT, OtherTraitsT > const& str)
661 {
662 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
663 }
664
665 // Deprecated overload
666 template< typename OtherCharT, typename OtherTraitsT >
667 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)668 operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT > const& str)
669 {
670 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
671 }
672
673 template< typename OtherCharT, typename OtherTraitsT, typename OtherAllocatorT >
674 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)675 operator<< (basic_formatting_ostream&& strm, std::basic_string< OtherCharT, OtherTraitsT, OtherAllocatorT >& str)
676 {
677 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
678 }
679
680 #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
681 template< typename OtherCharT, typename OtherTraitsT >
682 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,std::basic_string_view<OtherCharT,OtherTraitsT> & str)683 operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str)
684 {
685 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
686 }
687 #endif
688
689 template< typename OtherCharT, typename OtherTraitsT >
690 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_literal<OtherCharT,OtherTraitsT> & str)691 operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str)
692 {
693 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
694 }
695
696 template< typename OtherCharT, typename OtherTraitsT >
697 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_view<OtherCharT,OtherTraitsT> & str)698 operator<< (basic_formatting_ostream&& strm, basic_string_view< OtherCharT, OtherTraitsT >& str)
699 {
700 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
701 }
702
703 // Deprecated overload
704 template< typename OtherCharT, typename OtherTraitsT >
705 friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type
operator <<(basic_formatting_ostream && strm,basic_string_ref<OtherCharT,OtherTraitsT> & str)706 operator<< (basic_formatting_ostream&& strm, basic_string_ref< OtherCharT, OtherTraitsT >& str)
707 {
708 return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size()));
709 }
710 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
711
712 protected:
init_stream()713 void init_stream()
714 {
715 m_stream.exceptions(ostream_type::goodbit);
716 m_stream.clear(m_streambuf.storage() ? ostream_type::goodbit : ostream_type::badbit);
717 m_stream.flags
718 (
719 ostream_type::dec |
720 ostream_type::skipws |
721 ostream_type::boolalpha // this differs from the default stream flags but makes logs look better
722 );
723 m_stream.width(0);
724 m_stream.precision(6);
725 m_stream.fill(static_cast< char_type >(' '));
726 }
727
728 private:
formatted_write(const char_type * p,std::streamsize size)729 basic_formatting_ostream& formatted_write(const char_type* p, std::streamsize size)
730 {
731 sentry guard(*this);
732 if (!!guard)
733 {
734 m_stream.flush();
735
736 if (m_stream.width() <= size)
737 m_streambuf.append(p, static_cast< std::size_t >(size));
738 else
739 this->aligned_write(p, size);
740
741 m_stream.width(0);
742 }
743
744 return *this;
745 }
746
747 template< typename OtherCharT >
formatted_write(const OtherCharT * p,std::streamsize size)748 basic_formatting_ostream& formatted_write(const OtherCharT* p, std::streamsize size)
749 {
750 sentry guard(*this);
751 if (!!guard)
752 {
753 m_stream.flush();
754
755 if (m_stream.width() <= size)
756 {
757 if (!m_streambuf.storage_overflow())
758 {
759 if (!aux::code_convert(p, static_cast< std::size_t >(size), *m_streambuf.storage(), m_streambuf.max_size(), m_stream.getloc()))
760 m_streambuf.storage_overflow(true);
761 }
762 }
763 else
764 this->aligned_write(p, size);
765
766 m_stream.width(0);
767 }
768
769 return *this;
770 }
771
772 void aligned_write(const char_type* p, std::streamsize size);
773
774 template< typename OtherCharT >
775 void aligned_write(const OtherCharT* p, std::streamsize size);
776
777 //! Copy constructor (closed)
778 BOOST_DELETED_FUNCTION(basic_formatting_ostream(basic_formatting_ostream const& that))
779 //! Assignment (closed)
780 BOOST_DELETED_FUNCTION(basic_formatting_ostream& operator= (basic_formatting_ostream const& that))
781 };
782
783 template< typename CharT, typename TraitsT, typename AllocatorT >
784 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::boolalpha;
785 template< typename CharT, typename TraitsT, typename AllocatorT >
786 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::dec;
787 template< typename CharT, typename TraitsT, typename AllocatorT >
788 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fixed;
789 template< typename CharT, typename TraitsT, typename AllocatorT >
790 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::hex;
791 template< typename CharT, typename TraitsT, typename AllocatorT >
792 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::internal;
793 template< typename CharT, typename TraitsT, typename AllocatorT >
794 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::left;
795 template< typename CharT, typename TraitsT, typename AllocatorT >
796 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::oct;
797 template< typename CharT, typename TraitsT, typename AllocatorT >
798 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::right;
799 template< typename CharT, typename TraitsT, typename AllocatorT >
800 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::scientific;
801 template< typename CharT, typename TraitsT, typename AllocatorT >
802 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showbase;
803 template< typename CharT, typename TraitsT, typename AllocatorT >
804 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showpoint;
805 template< typename CharT, typename TraitsT, typename AllocatorT >
806 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::skipws;
807 template< typename CharT, typename TraitsT, typename AllocatorT >
808 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::unitbuf;
809 template< typename CharT, typename TraitsT, typename AllocatorT >
810 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::uppercase;
811 template< typename CharT, typename TraitsT, typename AllocatorT >
812 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::adjustfield;
813 template< typename CharT, typename TraitsT, typename AllocatorT >
814 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::basefield;
815 template< typename CharT, typename TraitsT, typename AllocatorT >
816 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::floatfield;
817
818 template< typename CharT, typename TraitsT, typename AllocatorT >
819 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::badbit;
820 template< typename CharT, typename TraitsT, typename AllocatorT >
821 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::eofbit;
822 template< typename CharT, typename TraitsT, typename AllocatorT >
823 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::failbit;
824 template< typename CharT, typename TraitsT, typename AllocatorT >
825 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::goodbit;
826
827 template< typename CharT, typename TraitsT, typename AllocatorT >
828 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::app;
829 template< typename CharT, typename TraitsT, typename AllocatorT >
830 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::ate;
831 template< typename CharT, typename TraitsT, typename AllocatorT >
832 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::binary;
833 template< typename CharT, typename TraitsT, typename AllocatorT >
834 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::in;
835 template< typename CharT, typename TraitsT, typename AllocatorT >
836 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::out;
837 template< typename CharT, typename TraitsT, typename AllocatorT >
838 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::trunc;
839
840 template< typename CharT, typename TraitsT, typename AllocatorT >
841 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::beg;
842 template< typename CharT, typename TraitsT, typename AllocatorT >
843 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::cur;
844 template< typename CharT, typename TraitsT, typename AllocatorT >
845 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::end;
846
847 template< typename CharT, typename TraitsT, typename AllocatorT >
848 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::erase_event;
849 template< typename CharT, typename TraitsT, typename AllocatorT >
850 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::imbue_event;
851 template< typename CharT, typename TraitsT, typename AllocatorT >
852 BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::copyfmt_event;
853
854 template< typename CharT, typename TraitsT, typename AllocatorT >
aligned_write(const char_type * p,std::streamsize size)855 void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const char_type* p, std::streamsize size)
856 {
857 typename string_type::size_type const alignment_size =
858 static_cast< typename string_type::size_type >(m_stream.width() - size);
859 const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
860 if (align_left)
861 {
862 m_streambuf.append(p, static_cast< std::size_t >(size));
863 m_streambuf.append(alignment_size, m_stream.fill());
864 }
865 else
866 {
867 m_streambuf.append(alignment_size, m_stream.fill());
868 m_streambuf.append(p, static_cast< std::size_t >(size));
869 }
870 }
871
872 template< typename CharT, typename TraitsT, typename AllocatorT >
873 template< typename OtherCharT >
aligned_write(const OtherCharT * p,std::streamsize size)874 void basic_formatting_ostream< CharT, TraitsT, AllocatorT >::aligned_write(const OtherCharT* p, std::streamsize size)
875 {
876 string_type* const storage = m_streambuf.storage();
877 typename string_type::size_type const alignment_size =
878 static_cast< typename string_type::size_type >(m_stream.width() - size);
879 const bool align_left = (m_stream.flags() & ostream_type::adjustfield) == ostream_type::left;
880 if (align_left)
881 {
882 if (!m_streambuf.storage_overflow())
883 {
884 if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
885 m_streambuf.storage_overflow(true);
886 }
887 m_streambuf.append(alignment_size, m_stream.fill());
888 }
889 else
890 {
891 m_streambuf.append(alignment_size, m_stream.fill());
892 if (!m_streambuf.storage_overflow())
893 {
894 if (!aux::code_convert(p, static_cast< std::size_t >(size), *storage, m_streambuf.max_size(), m_stream.getloc()))
895 m_streambuf.storage_overflow(true);
896 }
897 }
898 }
899
900 // Implementation note: these operators below should be the least attractive for the compiler
901 // so that user's overloads are chosen, when present. We use function template partial ordering for this purpose.
902 // We also don't use perfect forwarding for the right hand argument because in this case the generic overload
903 // would be more preferred than the typical one written by users:
904 //
905 // formatting_ostream& operator<< (formatting_ostream& strm, my_type const& arg);
906 //
907 // This is because my_type rvalues require adding const to the type, which counts as a conversion that is not required
908 // if there is a perfect forwarding overload.
909 template< typename StreamT, typename T >
910 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
operator <<(StreamT & strm,T value)911 operator<< (StreamT& strm, T value)
912 {
913 strm.stream() << value;
914 return strm;
915 }
916
917 template< typename StreamT, typename T >
918 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT & strm,T const & value)919 operator<< (StreamT& strm, T const& value)
920 {
921 strm.stream() << value;
922 return strm;
923 }
924
925 template< typename StreamT, typename T >
926 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT & strm,T & value)927 operator<< (StreamT& strm, T& value)
928 {
929 strm.stream() << value;
930 return strm;
931 }
932
933 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
934
935 template< typename StreamT, typename T >
936 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
operator <<(StreamT && strm,T value)937 operator<< (StreamT&& strm, T value)
938 {
939 strm.stream() << value;
940 return strm;
941 }
942
943 template< typename StreamT, typename T >
944 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT && strm,T const & value)945 operator<< (StreamT&& strm, T const& value)
946 {
947 strm.stream() << value;
948 return strm;
949 }
950
951 template< typename StreamT, typename T >
952 inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT && strm,T & value)953 operator<< (StreamT&& strm, T& value)
954 {
955 strm.stream() << value;
956 return strm;
957 }
958
959 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
960
961 BOOST_LOG_CLOSE_NAMESPACE // namespace log
962
963 } // namespace boost
964
965 #include <boost/log/detail/footer.hpp>
966
967 #endif // BOOST_LOG_UTILITY_FORMATTING_OSTREAM_HPP_INCLUDED_
968