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   record_ostream.cpp
9  * \author Andrey Semashev
10  * \date   17.04.2008
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <locale>
17 #include <utility>
18 #include <boost/log/sources/record_ostream.hpp>
19 #include <boost/log/detail/singleton.hpp>
20 #include <boost/log/attributes/attribute_value_impl.hpp>
21 #include <boost/log/expressions/message.hpp>
22 #if !defined(BOOST_LOG_NO_THREADS)
23 #include <boost/thread/tss.hpp>
24 #endif
25 #include "unique_ptr.hpp"
26 #include <boost/log/detail/header.hpp>
27 
28 namespace boost {
29 
30 BOOST_LOG_OPEN_NAMESPACE
31 
32 //! The function initializes the stream and the stream buffer
33 template< typename CharT >
init_stream()34 BOOST_LOG_API void basic_record_ostream< CharT >::init_stream()
35 {
36     base_type::imbue(std::locale());
37     if (m_record)
38     {
39         typedef attributes::attribute_value_impl< string_type > message_impl_type;
40         intrusive_ptr< message_impl_type > p = new message_impl_type(string_type());
41         attribute_value value(p);
42 
43         // This may fail if the record already has Message attribute
44         std::pair< attribute_value_set::const_iterator, bool > res =
45             m_record->attribute_values().insert(expressions::tag::message::get_name(), value);
46         if (!res.second)
47             const_cast< attribute_value& >(res.first->second).swap(value);
48 
49         base_type::attach(const_cast< string_type& >(p->get()));
50     }
51 }
52 //! The function resets the stream into a detached (default initialized) state
53 template< typename CharT >
detach_from_record()54 BOOST_LOG_API void basic_record_ostream< CharT >::detach_from_record() BOOST_NOEXCEPT
55 {
56     if (m_record)
57     {
58         base_type::detach();
59         m_record = NULL;
60         base_type::exceptions(stream_type::goodbit);
61     }
62 }
63 
64 namespace aux {
65 
66 BOOST_LOG_ANONYMOUS_NAMESPACE {
67 
68 //! The pool of stream compounds
69 template< typename CharT >
70 class stream_compound_pool :
71     public log::aux::lazy_singleton<
72         stream_compound_pool< CharT >,
73 #if !defined(BOOST_LOG_NO_THREADS)
74         thread_specific_ptr< stream_compound_pool< CharT > >
75 #else
76         log::aux::unique_ptr< stream_compound_pool< CharT > >
77 #endif
78     >
79 {
80     //! Self type
81     typedef stream_compound_pool< CharT > this_type;
82 #if !defined(BOOST_LOG_NO_THREADS)
83     //! Thread-specific pointer type
84     typedef thread_specific_ptr< this_type > tls_ptr_type;
85 #else
86     //! Thread-specific pointer type
87     typedef log::aux::unique_ptr< this_type > tls_ptr_type;
88 #endif
89     //! Singleton base type
90     typedef log::aux::lazy_singleton<
91         this_type,
92         tls_ptr_type
93     > base_type;
94     //! Stream compound type
95     typedef typename stream_provider< CharT >::stream_compound stream_compound_t;
96 
97 public:
98     //! Pooled stream compounds
99     stream_compound_t* m_Top;
100 
101     ~stream_compound_pool()
102     {
103         stream_compound_t* p = NULL;
104         while ((p = m_Top) != NULL)
105         {
106             m_Top = p->next;
107             delete p;
108         }
109     }
110 
111     //! The method returns pool instance
112     static stream_compound_pool& get()
113     {
114         tls_ptr_type& ptr = base_type::get();
115         this_type* p = ptr.get();
116         if (!p)
117         {
118             log::aux::unique_ptr< this_type > pNew(new this_type());
119             ptr.reset(pNew.get());
120             p = pNew.release();
121         }
122         return *p;
123     }
124 
125 private:
126     stream_compound_pool() : m_Top(NULL) {}
127 };
128 
129 } // namespace
130 
131 //! The method returns an allocated stream compound
132 template< typename CharT >
133 BOOST_LOG_API typename stream_provider< CharT >::stream_compound*
134 stream_provider< CharT >::allocate_compound(record& rec)
135 {
136     stream_compound_pool< char_type >& pool = stream_compound_pool< char_type >::get();
137     if (pool.m_Top)
138     {
139         stream_compound* p = pool.m_Top;
140         pool.m_Top = p->next;
141         p->next = NULL;
142         p->stream.attach_record(rec);
143         return p;
144     }
145     else
146         return new stream_compound(rec);
147 }
148 
149 //! The method releases a compound
150 template< typename CharT >
release_compound(stream_compound * compound)151 BOOST_LOG_API void stream_provider< CharT >::release_compound(stream_compound* compound) BOOST_NOEXCEPT
152 {
153     stream_compound_pool< char_type >& pool = stream_compound_pool< char_type >::get();
154     compound->next = pool.m_Top;
155     pool.m_Top = compound;
156     compound->stream.detach_from_record();
157 }
158 
159 //! Explicitly instantiate stream_provider implementation
160 #ifdef BOOST_LOG_USE_CHAR
161 template struct stream_provider< char >;
162 #endif
163 #ifdef BOOST_LOG_USE_WCHAR_T
164 template struct stream_provider< wchar_t >;
165 #endif
166 
167 } // namespace aux
168 
169 //! Explicitly instantiate basic_record_ostream implementation
170 #ifdef BOOST_LOG_USE_CHAR
171 template class basic_record_ostream< char >;
172 #endif
173 #ifdef BOOST_LOG_USE_WCHAR_T
174 template class basic_record_ostream< wchar_t >;
175 #endif
176 
177 BOOST_LOG_CLOSE_NAMESPACE // namespace log
178 
179 } // namespace boost
180 
181 #include <boost/log/detail/footer.hpp>
182