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