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