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