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

source code of boost/libs/log/src/named_scope.cpp