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