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