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()35BOOST_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()56BOOST_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)153BOOST_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