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
43namespace boost {
44
45BOOST_LOG_OPEN_NAMESPACE
46
47namespace aux {
48
49template< typename T, typename R >
50struct enable_if_streamable_char_type {};
51template< typename T, typename R >
52struct disable_if_streamable_char_type { typedef R type; };
53template< typename R >
54struct enable_if_streamable_char_type< char, R > { typedef R type; };
55template< typename R >
56struct disable_if_streamable_char_type< char, R > {};
57template< typename R >
58struct enable_if_streamable_char_type< wchar_t, R > { typedef R type; };
59template< typename R >
60struct 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)
63template< typename R >
64struct enable_if_streamable_char_type< char16_t, R > { typedef R type; };
65template< typename R >
66struct disable_if_streamable_char_type< char16_t, R > {};
67#endif
68#if !defined(BOOST_NO_CXX11_CHAR32_T)
69template< typename R >
70struct enable_if_streamable_char_type< char32_t, R > { typedef R type; };
71template< typename R >
72struct disable_if_streamable_char_type< char32_t, R > {};
73#endif
74#endif
75
76template< typename StreamT, typename T, bool ByValueV, typename R >
77struct enable_formatting_ostream_generic_operator {};
78
79template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
80struct 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
85template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
86struct 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
91template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R >
92struct 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 */
120template< typename CharT, typename TraitsT, typename AllocatorT >
121class basic_formatting_ostream
122{
123public:
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:
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
172protected:
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
178public:
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
217private:
218 mutable streambuf_type m_streambuf;
219 ostream_type m_stream;
220
221public:
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 */
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 */
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 */
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 */
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 */
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 */
278 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 */
291 ostream_type& stream() { return m_stream; }
292
293 /*!
294 * \returns Reference to the wrapped stream
295 */
296 ostream_type const& stream() const { return m_stream; }
297
298 // std::ios_base method forwarders
299 fmtflags flags() const { return m_stream.flags(); }
300 fmtflags flags(fmtflags f) { return m_stream.flags(f); }
301 fmtflags setf(fmtflags f) { return m_stream.setf(f); }
302 fmtflags setf(fmtflags f, fmtflags mask) { return m_stream.setf(f, mask); }
303 void unsetf(fmtflags f) { m_stream.unsetf(f); }
304
305 std::streamsize precision() const { return m_stream.precision(); }
306 std::streamsize precision(std::streamsize p) { return m_stream.precision(p); }
307
308 std::streamsize width() const { return m_stream.width(); }
309 std::streamsize width(std::streamsize w) { return m_stream.width(w); }
310
311 std::locale getloc() const { return m_stream.getloc(); }
312 std::locale imbue(std::locale const& loc) { return m_stream.imbue(loc); }
313
314 static int xalloc() { return ostream_type::xalloc(); }
315 long& iword(int index) { return m_stream.iword(index); }
316 void*& pword(int index) { return m_stream.pword(index); }
317
318 void register_callback(event_callback fn, int index) { m_stream.register_callback(fn, index); }
319
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
326 iostate rdstate() const { return m_stream.rdstate(); }
327 void clear(iostate state = goodbit) { m_stream.clear(state); }
328 void setstate(iostate state) { m_stream.setstate(state); }
329 bool good() const { return m_stream.good(); }
330 bool eof() const { return m_stream.eof(); }
331 bool fail() const { return m_stream.fail(); }
332 bool bad() const { return m_stream.bad(); }
333
334 iostate exceptions() const { return m_stream.exceptions(); }
335 void exceptions(iostate s) { m_stream.exceptions(s); }
336
337 ostream_type* tie() const { return m_stream.tie(); }
338 ostream_type* tie(ostream_type* strm) { return m_stream.tie(strm); }
339
340 streambuf_type* rdbuf() const { return &m_streambuf; }
341
342 basic_formatting_ostream& copyfmt(std::basic_ios< char_type, traits_type >& rhs)
343 {
344 m_stream.copyfmt(rhs);
345 return *this;
346 }
347 basic_formatting_ostream& copyfmt(basic_formatting_ostream& rhs)
348 {
349 m_stream.copyfmt(rhs.stream());
350 return *this;
351 }
352
353 char_type fill() const { return m_stream.fill(); }
354 char_type fill(char_type ch) { return m_stream.fill(ch); }
355
356 char narrow(char_type ch, char def) const { return m_stream.narrow(ch, def); }
357 char_type widen(char ch) const { return m_stream.widen(ch); }
358
359 // std::basic_ostream method forwarders
360 basic_formatting_ostream& flush()
361 {
362 m_stream.flush();
363 return *this;
364 }
365
366 pos_type tellp() { return m_stream.tellp(); }
367 basic_formatting_ostream& seekp(pos_type pos)
368 {
369 m_stream.seekp(pos);
370 return *this;
371 }
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
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
386 put(OtherCharT c)
387 {
388 write(&c, 1);
389 return *this;
390 }
391
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
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
418 basic_formatting_ostream& operator<< (ios_base_manip manip)
419 {
420 m_stream << manip;
421 return *this;
422 }
423 basic_formatting_ostream& operator<< (basic_ios_manip manip)
424 {
425 m_stream << manip;
426 return *this;
427 }
428 basic_formatting_ostream& operator<< (stream_manip manip)
429 {
430 m_stream << manip;
431 return *this;
432 }
433
434 basic_formatting_ostream& operator<< (char c)
435 {
436 return this->formatted_write(&c, 1);
437 }
438 basic_formatting_ostream& operator<< (const char* p)
439 {
440 return this->formatted_write(p, static_cast< std::streamsize >(std::char_traits< char >::length(s: 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)
446 basic_formatting_ostream& operator<< (wchar_t c)
447 {
448 return this->formatted_write(&c, 1);
449 }
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(s: p)));
453 }
454#endif
455#if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
456#if !defined(BOOST_NO_CXX11_CHAR16_T)
457 basic_formatting_ostream& operator<< (char16_t c)
458 {
459 return this->formatted_write(&c, 1);
460 }
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(s: p)));
464 }
465#endif
466#if !defined(BOOST_NO_CXX11_CHAR32_T)
467 basic_formatting_ostream& operator<< (char32_t c)
468 {
469 return this->formatted_write(&c, 1);
470 }
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(s: p)));
474 }
475#endif
476#endif
477
478 basic_formatting_ostream& operator<< (bool value)
479 {
480 m_stream << value;
481 return *this;
482 }
483 basic_formatting_ostream& operator<< (signed char value)
484 {
485 m_stream << value;
486 return *this;
487 }
488 basic_formatting_ostream& operator<< (unsigned char value)
489 {
490 m_stream << value;
491 return *this;
492 }
493 basic_formatting_ostream& operator<< (short value)
494 {
495 m_stream << value;
496 return *this;
497 }
498 basic_formatting_ostream& operator<< (unsigned short value)
499 {
500 m_stream << value;
501 return *this;
502 }
503 basic_formatting_ostream& operator<< (int value)
504 {
505 m_stream << value;
506 return *this;
507 }
508 basic_formatting_ostream& operator<< (unsigned int value)
509 {
510 m_stream << value;
511 return *this;
512 }
513 basic_formatting_ostream& operator<< (long value)
514 {
515 m_stream << value;
516 return *this;
517 }
518 basic_formatting_ostream& operator<< (unsigned long value)
519 {
520 m_stream << value;
521 return *this;
522 }
523#if !defined(BOOST_NO_LONG_LONG)
524 basic_formatting_ostream& operator<< (long long value)
525 {
526 m_stream << value;
527 return *this;
528 }
529 basic_formatting_ostream& operator<< (unsigned long long value)
530 {
531 m_stream << value;
532 return *this;
533 }
534#endif
535
536 basic_formatting_ostream& operator<< (float value)
537 {
538 m_stream << value;
539 return *this;
540 }
541 basic_formatting_ostream& operator<< (double value)
542 {
543 m_stream << value;
544 return *this;
545 }
546 basic_formatting_ostream& operator<< (long double value)
547 {
548 m_stream << value;
549 return *this;
550 }
551
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
712protected:
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
728private:
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 >
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
783template< typename CharT, typename TraitsT, typename AllocatorT >
784BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::boolalpha;
785template< typename CharT, typename TraitsT, typename AllocatorT >
786BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::dec;
787template< typename CharT, typename TraitsT, typename AllocatorT >
788BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fixed;
789template< typename CharT, typename TraitsT, typename AllocatorT >
790BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::hex;
791template< typename CharT, typename TraitsT, typename AllocatorT >
792BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::internal;
793template< typename CharT, typename TraitsT, typename AllocatorT >
794BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::left;
795template< typename CharT, typename TraitsT, typename AllocatorT >
796BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::oct;
797template< typename CharT, typename TraitsT, typename AllocatorT >
798BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::right;
799template< typename CharT, typename TraitsT, typename AllocatorT >
800BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::scientific;
801template< typename CharT, typename TraitsT, typename AllocatorT >
802BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showbase;
803template< typename CharT, typename TraitsT, typename AllocatorT >
804BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::showpoint;
805template< typename CharT, typename TraitsT, typename AllocatorT >
806BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::skipws;
807template< typename CharT, typename TraitsT, typename AllocatorT >
808BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::unitbuf;
809template< typename CharT, typename TraitsT, typename AllocatorT >
810BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::uppercase;
811template< typename CharT, typename TraitsT, typename AllocatorT >
812BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::adjustfield;
813template< typename CharT, typename TraitsT, typename AllocatorT >
814BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::basefield;
815template< typename CharT, typename TraitsT, typename AllocatorT >
816BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::fmtflags basic_formatting_ostream< CharT, TraitsT, AllocatorT >::floatfield;
817
818template< typename CharT, typename TraitsT, typename AllocatorT >
819BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::badbit;
820template< typename CharT, typename TraitsT, typename AllocatorT >
821BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::eofbit;
822template< typename CharT, typename TraitsT, typename AllocatorT >
823BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::failbit;
824template< typename CharT, typename TraitsT, typename AllocatorT >
825BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::iostate basic_formatting_ostream< CharT, TraitsT, AllocatorT >::goodbit;
826
827template< typename CharT, typename TraitsT, typename AllocatorT >
828BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::app;
829template< typename CharT, typename TraitsT, typename AllocatorT >
830BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::ate;
831template< typename CharT, typename TraitsT, typename AllocatorT >
832BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::binary;
833template< typename CharT, typename TraitsT, typename AllocatorT >
834BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::in;
835template< typename CharT, typename TraitsT, typename AllocatorT >
836BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::out;
837template< typename CharT, typename TraitsT, typename AllocatorT >
838BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::openmode basic_formatting_ostream< CharT, TraitsT, AllocatorT >::trunc;
839
840template< typename CharT, typename TraitsT, typename AllocatorT >
841BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::beg;
842template< typename CharT, typename TraitsT, typename AllocatorT >
843BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::cur;
844template< typename CharT, typename TraitsT, typename AllocatorT >
845BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::seekdir basic_formatting_ostream< CharT, TraitsT, AllocatorT >::end;
846
847template< typename CharT, typename TraitsT, typename AllocatorT >
848BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::erase_event;
849template< typename CharT, typename TraitsT, typename AllocatorT >
850BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::imbue_event;
851template< typename CharT, typename TraitsT, typename AllocatorT >
852BOOST_CONSTEXPR_OR_CONST typename basic_formatting_ostream< CharT, TraitsT, AllocatorT >::event basic_formatting_ostream< CharT, TraitsT, AllocatorT >::copyfmt_event;
853
854template< typename CharT, typename TraitsT, typename AllocatorT >
855void 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
872template< typename CharT, typename TraitsT, typename AllocatorT >
873template< typename OtherCharT >
874void 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.
909template< typename StreamT, typename T >
910inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
911operator<< (StreamT& strm, T value)
912{
913 strm.stream() << value;
914 return strm;
915}
916
917template< typename StreamT, typename T >
918inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
919operator<< (StreamT& strm, T const& value)
920{
921 strm.stream() << value;
922 return strm;
923}
924
925template< typename StreamT, typename T >
926inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
927operator<< (StreamT& strm, T& value)
928{
929 strm.stream() << value;
930 return strm;
931}
932
933#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
934
935template< typename StreamT, typename T >
936inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, true, StreamT& >::type
937operator<< (StreamT&& strm, T value)
938{
939 strm.stream() << value;
940 return strm;
941}
942
943template< typename StreamT, typename T >
944inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
945operator<< (StreamT&& strm, T const& value)
946{
947 strm.stream() << value;
948 return strm;
949}
950
951template< typename StreamT, typename T >
952inline typename boost::log::aux::enable_formatting_ostream_generic_operator< StreamT, T, false, StreamT& >::type
953operator<< (StreamT&& strm, T& value)
954{
955 strm.stream() << value;
956 return strm;
957}
958
959#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
960
961BOOST_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

source code of boost/libs/log/include/boost/log/utility/formatting_ostream.hpp