• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   named_scope.cpp
9  * \author Andrey Semashev
10  * \date   24.06.2007
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 <utility>
18 #include <algorithm>
19 #include <boost/type_index.hpp>
20 #include <boost/optional/optional.hpp>
21 #include <boost/log/attributes/attribute.hpp>
22 #include <boost/log/attributes/attribute_value.hpp>
23 #include <boost/log/attributes/named_scope.hpp>
24 #include <boost/log/utility/type_dispatch/type_dispatcher.hpp>
25 #include <boost/log/detail/allocator_traits.hpp>
26 #include <boost/log/detail/singleton.hpp>
27 #if !defined(BOOST_LOG_NO_THREADS)
28 #include <boost/thread/tss.hpp>
29 #endif
30 #include "unique_ptr.hpp"
31 #include <boost/log/detail/header.hpp>
32 
33 namespace boost {
34 
35 BOOST_LOG_OPEN_NAMESPACE
36 
37 namespace attributes {
38 
39 BOOST_LOG_ANONYMOUS_NAMESPACE {
40 
41     //! Actual implementation of the named scope list
42     class writeable_named_scope_list :
43         public named_scope_list
44     {
45         //! Base type
46         typedef named_scope_list base_type;
47 
48     public:
49         //! Const reference type
50         typedef base_type::const_reference const_reference;
51 
52     public:
53         //! The method pushes the scope to the back of the list
54         BOOST_FORCEINLINE void push_back(const_reference entry) BOOST_NOEXCEPT
55         {
56             aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
57             entry._m_pPrev = top;
58             entry._m_pNext = &this->m_RootNode;
59 
60             BOOST_LOG_ASSUME(&entry != 0);
61             this->m_RootNode._m_pPrev = top->_m_pNext =
62                 const_cast< aux::named_scope_list_node* >(
63                     static_cast< const aux::named_scope_list_node* >(&entry));
64 
65             ++this->m_Size;
66         }
67         //! The method removes the top scope entry from the list
68         BOOST_FORCEINLINE void pop_back() BOOST_NOEXCEPT
69         {
70             aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
71             top->_m_pPrev->_m_pNext = top->_m_pNext;
72             top->_m_pNext->_m_pPrev = top->_m_pPrev;
73             --this->m_Size;
74         }
75     };
76 
77     //! Named scope attribute value
78     class named_scope_value :
79         public attribute_value::impl
80     {
81         //! Scope names stack
82         typedef named_scope_list scope_stack;
83 
84         //! Pointer to the actual scope value
85         scope_stack* m_pValue;
86         //! A thread-independent value
87         optional< scope_stack > m_DetachedValue;
88 
89     public:
90         //! Constructor
91         explicit named_scope_value(scope_stack* p) : m_pValue(p) {}
92 
93         //! The method dispatches the value to the given object. It returns true if the
94         //! object was capable to consume the real attribute value type and false otherwise.
95         bool dispatch(type_dispatcher& dispatcher) BOOST_OVERRIDE
96         {
97             type_dispatcher::callback< scope_stack > callback =
98                 dispatcher.get_callback< scope_stack >();
99             if (callback)
100             {
101                 callback(*m_pValue);
102                 return true;
103             }
104             else
105                 return false;
106         }
107 
108         /*!
109          * \return The attribute value type
110          */
111         typeindex::type_index get_type() const BOOST_OVERRIDE { return typeindex::type_id< scope_stack >(); }
112 
113         //! The method is called when the attribute value is passed to another thread (e.g.
114         //! in case of asynchronous logging). The value should ensure it properly owns all thread-specific data.
115         intrusive_ptr< attribute_value::impl > detach_from_thread() BOOST_OVERRIDE
116         {
117             if (!m_DetachedValue)
118             {
119                 m_DetachedValue = *m_pValue;
120                 m_pValue = m_DetachedValue.get_ptr();
121             }
122 
123             return this;
124         }
125     };
126 
127 } // namespace
128 
129 //! Named scope attribute implementation
130 struct BOOST_SYMBOL_VISIBLE named_scope::impl :
131     public attribute::impl,
132     public log::aux::singleton<
133         impl,
134         intrusive_ptr< impl >
135     >
136 {
137     //! Singleton base type
138     typedef log::aux::singleton<
139         impl,
140         intrusive_ptr< impl >
141     > singleton_base_type;
142 
143     //! Writable scope list type
144     typedef writeable_named_scope_list scope_list;
145 
146 #if !defined(BOOST_LOG_NO_THREADS)
147     //! Pointer to the thread-specific scope stack
148     thread_specific_ptr< scope_list > pScopes;
149 
150 #if defined(BOOST_LOG_USE_COMPILER_TLS)
151     //! Cached pointer to the thread-specific scope stack
152     static BOOST_LOG_TLS scope_list* pScopesCache;
153 #endif
154 
155 #else
156     //! Pointer to the scope stack
157     log::aux::unique_ptr< scope_list > pScopes;
158 #endif
159 
160     //! The method returns current thread scope stack
get_scope_listboost::attributes::named_scope::impl161     scope_list& get_scope_list()
162     {
163 #if defined(BOOST_LOG_USE_COMPILER_TLS)
164         scope_list* p = pScopesCache;
165 #else
166         scope_list* p = pScopes.get();
167 #endif
168         if (!p)
169         {
170             log::aux::unique_ptr< scope_list > pNew(new scope_list());
171             pScopes.reset(pNew.get());
172 #if defined(BOOST_LOG_USE_COMPILER_TLS)
173             pScopesCache = p = pNew.release();
174 #else
175             p = pNew.release();
176 #endif
177         }
178 
179         return *p;
180     }
181 
182     //! Instance initializer
init_instanceboost::attributes::named_scope::impl183     static void init_instance()
184     {
185         singleton_base_type::get_instance().reset(new impl());
186     }
187 
188     //! The method returns the actual attribute value. It must not return NULL.
get_valueboost::attributes::named_scope::impl189     attribute_value get_value() BOOST_OVERRIDE
190     {
191         return attribute_value(new named_scope_value(&get_scope_list()));
192     }
193 
194 private:
implboost::attributes::named_scope::impl195     impl() {}
196 };
197 
198 #if defined(BOOST_LOG_USE_COMPILER_TLS)
199 //! Cached pointer to the thread-specific scope stack
200 BOOST_LOG_TLS named_scope::impl::scope_list*
201 named_scope::impl::pScopesCache = NULL;
202 #endif // defined(BOOST_LOG_USE_COMPILER_TLS)
203 
204 
205 //! Copy constructor
named_scope_list(named_scope_list const & that)206 BOOST_LOG_API named_scope_list::named_scope_list(named_scope_list const& that) :
207     allocator_type(static_cast< allocator_type const& >(that)),
208     m_Size(that.size()),
209     m_fNeedToDeallocate(!that.empty())
210 {
211     if (m_Size > 0)
212     {
213         // Copy the container contents
214         pointer p = log::aux::allocator_traits< allocator_type >::allocate(*static_cast< allocator_type* >(this), that.size());
215         aux::named_scope_list_node* prev = &m_RootNode;
216         for (const_iterator src = that.begin(), end = that.end(); src != end; ++src, ++p)
217         {
218             log::aux::allocator_traits< allocator_type >::construct(*static_cast< allocator_type* >(this), p, *src); // won't throw
219             p->_m_pPrev = prev;
220             prev->_m_pNext = p;
221             prev = p;
222         }
223         m_RootNode._m_pPrev = prev;
224         prev->_m_pNext = &m_RootNode;
225     }
226 }
227 
228 //! Destructor
~named_scope_list()229 BOOST_LOG_API named_scope_list::~named_scope_list()
230 {
231     if (m_fNeedToDeallocate)
232     {
233         iterator it(m_RootNode._m_pNext);
234         iterator end(&m_RootNode);
235         while (it != end)
236             log::aux::allocator_traits< allocator_type >::destroy(*static_cast< allocator_type* >(this), &*(it++));
237         log::aux::allocator_traits< allocator_type >::deallocate(*static_cast< allocator_type* >(this), static_cast< pointer >(m_RootNode._m_pNext), m_Size);
238     }
239 }
240 
241 //! Swaps two instances of the container
swap(named_scope_list & that)242 BOOST_LOG_API void named_scope_list::swap(named_scope_list& that)
243 {
244     if (!this->empty())
245     {
246         if (!that.empty())
247         {
248             // both containers are not empty
249             std::swap(m_RootNode._m_pNext->_m_pPrev, that.m_RootNode._m_pNext->_m_pPrev);
250             std::swap(m_RootNode._m_pPrev->_m_pNext, that.m_RootNode._m_pPrev->_m_pNext);
251             std::swap(m_RootNode, that.m_RootNode);
252             std::swap(m_Size, that.m_Size);
253             std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
254         }
255         else
256         {
257             // this is not empty
258             m_RootNode._m_pNext->_m_pPrev = m_RootNode._m_pPrev->_m_pNext = &that.m_RootNode;
259             that.m_RootNode = m_RootNode;
260             m_RootNode._m_pNext = m_RootNode._m_pPrev = &m_RootNode;
261             std::swap(m_Size, that.m_Size);
262             std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
263         }
264     }
265     else if (!that.empty())
266     {
267         // that is not empty
268         that.m_RootNode._m_pNext->_m_pPrev = that.m_RootNode._m_pPrev->_m_pNext = &m_RootNode;
269         m_RootNode = that.m_RootNode;
270         that.m_RootNode._m_pNext = that.m_RootNode._m_pPrev = &that.m_RootNode;
271         std::swap(m_Size, that.m_Size);
272         std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
273     }
274 }
275 
276 //! Constructor
named_scope()277 named_scope::named_scope() :
278     attribute(impl::instance)
279 {
280 }
281 
282 //! Constructor for casting support
named_scope(cast_source const & source)283 named_scope::named_scope(cast_source const& source) :
284     attribute(source.as< impl >())
285 {
286 }
287 
288 //! The method pushes the scope to the stack
push_scope(scope_entry const & entry)289 void named_scope::push_scope(scope_entry const& entry) BOOST_NOEXCEPT
290 {
291     impl::scope_list& s = impl::instance->get_scope_list();
292     s.push_back(entry);
293 }
294 
295 //! The method pops the top scope
pop_scope()296 void named_scope::pop_scope() BOOST_NOEXCEPT
297 {
298     impl::scope_list& s = impl::instance->get_scope_list();
299     s.pop_back();
300 }
301 
302 //! Returns the current thread's scope stack
get_scopes()303 named_scope::value_type const& named_scope::get_scopes()
304 {
305     return impl::instance->get_scope_list();
306 }
307 
308 } // namespace attributes
309 
310 BOOST_LOG_CLOSE_NAMESPACE // namespace log
311 
312 } // namespace boost
313 
314 #include <boost/log/detail/footer.hpp>
315