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/singleton.hpp>
26 #if !defined(BOOST_LOG_NO_THREADS)
27 #include <boost/thread/tss.hpp>
28 #endif
29 #include "unique_ptr.hpp"
30 #include <boost/log/detail/header.hpp>
31
32 namespace boost {
33
34 BOOST_LOG_OPEN_NAMESPACE
35
36 namespace attributes {
37
38 BOOST_LOG_ANONYMOUS_NAMESPACE {
39
40 //! Actual implementation of the named scope list
41 class writeable_named_scope_list :
42 public named_scope_list
43 {
44 //! Base type
45 typedef named_scope_list base_type;
46
47 public:
48 //! Const reference type
49 typedef base_type::const_reference const_reference;
50
51 public:
52 //! The method pushes the scope to the back of the list
53 BOOST_FORCEINLINE void push_back(const_reference entry) BOOST_NOEXCEPT
54 {
55 aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
56 entry._m_pPrev = top;
57 entry._m_pNext = &this->m_RootNode;
58
59 BOOST_LOG_ASSUME(&entry != 0);
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)
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 { 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()
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
129 struct 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
get_scope_listboost::attributes::named_scope::impl160 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(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
init_instanceboost::attributes::named_scope::impl182 static void init_instance()
183 {
184 singleton_base_type::get_instance().reset(new impl());
185 }
186
187 //! The method returns the actual attribute value. It must not return NULL.
get_valueboost::attributes::named_scope::impl188 attribute_value get_value()
189 {
190 return attribute_value(new named_scope_value(&get_scope_list()));
191 }
192
193 private:
implboost::attributes::named_scope::impl194 impl() {}
195 };
196
197 #if defined(BOOST_LOG_USE_COMPILER_TLS)
198 //! Cached pointer to the thread-specific scope stack
199 BOOST_LOG_TLS named_scope::impl::scope_list*
200 named_scope::impl::pScopesCache = NULL;
201 #endif // defined(BOOST_LOG_USE_COMPILER_TLS)
202
203
204 //! Copy constructor
named_scope_list(named_scope_list const & that)205 BOOST_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 = allocator_type::allocate(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 allocator_type::construct(p, *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
~named_scope_list()228 BOOST_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 allocator_type::destroy(&*(it++));
236 allocator_type::deallocate(static_cast< pointer >(m_RootNode._m_pNext), m_Size);
237 }
238 }
239
240 //! Swaps two instances of the container
swap(named_scope_list & that)241 BOOST_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(m_RootNode._m_pNext->_m_pPrev, that.m_RootNode._m_pNext->_m_pPrev);
249 std::swap(m_RootNode._m_pPrev->_m_pNext, that.m_RootNode._m_pPrev->_m_pNext);
250 std::swap(m_RootNode, that.m_RootNode);
251 std::swap(m_Size, that.m_Size);
252 std::swap(m_fNeedToDeallocate, 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(m_Size, that.m_Size);
261 std::swap(m_fNeedToDeallocate, 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(m_Size, that.m_Size);
271 std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
272 }
273 }
274
275 //! Constructor
named_scope()276 named_scope::named_scope() :
277 attribute(impl::instance)
278 {
279 }
280
281 //! Constructor for casting support
named_scope(cast_source const & source)282 named_scope::named_scope(cast_source const& source) :
283 attribute(source.as< impl >())
284 {
285 }
286
287 //! The method pushes the scope to the stack
push_scope(scope_entry const & entry)288 void 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
pop_scope()295 void 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
get_scopes()302 named_scope::value_type const& named_scope::get_scopes()
303 {
304 return impl::instance->get_scope_list();
305 }
306
307 } // namespace attributes
308
309 BOOST_LOG_CLOSE_NAMESPACE // namespace log
310
311 } // namespace boost
312
313 #include <boost/log/detail/footer.hpp>
314