summaryrefslogtreecommitdiff
path: root/libs/log/src/named_scope.cpp
blob: f86c1e2f4888b08530349443ef23bcf8a463e556 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
 *          Copyright Andrey Semashev 2007 - 2015.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   named_scope.cpp
 * \author Andrey Semashev
 * \date   24.06.2007
 *
 * \brief  This header is the Boost.Log library implementation, see the library documentation
 *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
 */

#include <memory>
#include <utility>
#include <algorithm>
#include <boost/optional/optional.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_value.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/utility/type_dispatch/type_dispatcher.hpp>
#include <boost/log/detail/singleton.hpp>
#if !defined(BOOST_LOG_NO_THREADS)
#include <boost/thread/tss.hpp>
#endif
#include <boost/log/detail/header.hpp>

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace attributes {

BOOST_LOG_ANONYMOUS_NAMESPACE {

    //! Actual implementation of the named scope list
    class writeable_named_scope_list :
        public named_scope_list
    {
        //! Base type
        typedef named_scope_list base_type;

    public:
        //! Const reference type
        typedef base_type::const_reference const_reference;

    public:
        //! The method pushes the scope to the back of the list
        BOOST_FORCEINLINE void push_back(const_reference entry) BOOST_NOEXCEPT
        {
            aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
            entry._m_pPrev = top;
            entry._m_pNext = &this->m_RootNode;

            BOOST_LOG_ASSUME(&entry != 0);
            this->m_RootNode._m_pPrev = top->_m_pNext =
                const_cast< aux::named_scope_list_node* >(
                    static_cast< const aux::named_scope_list_node* >(&entry));

            ++this->m_Size;
        }
        //! The method removes the top scope entry from the list
        BOOST_FORCEINLINE void pop_back() BOOST_NOEXCEPT
        {
            aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
            top->_m_pPrev->_m_pNext = top->_m_pNext;
            top->_m_pNext->_m_pPrev = top->_m_pPrev;
            --this->m_Size;
        }
    };

    //! Named scope attribute value
    class named_scope_value :
        public attribute_value::impl
    {
        //! Scope names stack
        typedef named_scope_list scope_stack;

        //! Pointer to the actual scope value
        scope_stack* m_pValue;
        //! A thread-independent value
        optional< scope_stack > m_DetachedValue;

    public:
        //! Constructor
        explicit named_scope_value(scope_stack* p) : m_pValue(p) {}

        //! The method dispatches the value to the given object. It returns true if the
        //! object was capable to consume the real attribute value type and false otherwise.
        bool dispatch(type_dispatcher& dispatcher)
        {
            type_dispatcher::callback< scope_stack > callback =
                dispatcher.get_callback< scope_stack >();
            if (callback)
            {
                callback(*m_pValue);
                return true;
            }
            else
                return false;
        }

        /*!
         * \return The attribute value type
         */
        type_info_wrapper get_type() const { return type_info_wrapper(typeid(scope_stack)); }

        //! The method is called when the attribute value is passed to another thread (e.g.
        //! in case of asynchronous logging). The value should ensure it properly owns all thread-specific data.
        intrusive_ptr< attribute_value::impl > detach_from_thread()
        {
            if (!m_DetachedValue)
            {
                m_DetachedValue = *m_pValue;
                m_pValue = m_DetachedValue.get_ptr();
            }

            return this;
        }
    };

} // namespace

//! Named scope attribute implementation
struct BOOST_SYMBOL_VISIBLE named_scope::impl :
    public attribute::impl,
    public log::aux::singleton<
        impl,
        intrusive_ptr< impl >
    >
{
    //! Singleton base type
    typedef log::aux::singleton<
        impl,
        intrusive_ptr< impl >
    > singleton_base_type;

    //! Writable scope list type
    typedef writeable_named_scope_list scope_list;

#if !defined(BOOST_LOG_NO_THREADS)
    //! Pointer to the thread-specific scope stack
    thread_specific_ptr< scope_list > pScopes;

#if defined(BOOST_LOG_USE_COMPILER_TLS)
    //! Cached pointer to the thread-specific scope stack
    static BOOST_LOG_TLS scope_list* pScopesCache;
#endif

#else
    //! Pointer to the scope stack
    std::auto_ptr< scope_list > pScopes;
#endif

    //! The method returns current thread scope stack
    scope_list& get_scope_list()
    {
#if defined(BOOST_LOG_USE_COMPILER_TLS)
        scope_list* p = pScopesCache;
#else
        scope_list* p = pScopes.get();
#endif
        if (!p)
        {
            std::auto_ptr< scope_list > pNew(new scope_list());
            pScopes.reset(pNew.get());
#if defined(BOOST_LOG_USE_COMPILER_TLS)
            pScopesCache = p = pNew.release();
#else
            p = pNew.release();
#endif
        }

        return *p;
    }

    //! Instance initializer
    static void init_instance()
    {
        singleton_base_type::get_instance().reset(new impl());
    }

    //! The method returns the actual attribute value. It must not return NULL.
    attribute_value get_value()
    {
        return attribute_value(new named_scope_value(&get_scope_list()));
    }

private:
    impl() {}
};

#if defined(BOOST_LOG_USE_COMPILER_TLS)
//! Cached pointer to the thread-specific scope stack
BOOST_LOG_TLS named_scope::impl::scope_list*
named_scope::impl::pScopesCache = NULL;
#endif // defined(BOOST_LOG_USE_COMPILER_TLS)


//! Copy constructor
BOOST_LOG_API named_scope_list::named_scope_list(named_scope_list const& that) :
    allocator_type(static_cast< allocator_type const& >(that)),
    m_Size(that.size()),
    m_fNeedToDeallocate(!that.empty())
{
    if (m_Size > 0)
    {
        // Copy the container contents
        pointer p = allocator_type::allocate(that.size());
        aux::named_scope_list_node* prev = &m_RootNode;
        for (const_iterator src = that.begin(), end = that.end(); src != end; ++src, ++p)
        {
            allocator_type::construct(p, *src); // won't throw
            p->_m_pPrev = prev;
            prev->_m_pNext = p;
            prev = p;
        }
        m_RootNode._m_pPrev = prev;
        prev->_m_pNext = &m_RootNode;
    }
}

//! Destructor
BOOST_LOG_API named_scope_list::~named_scope_list()
{
    if (m_fNeedToDeallocate)
    {
        iterator it(m_RootNode._m_pNext);
        iterator end(&m_RootNode);
        while (it != end)
            allocator_type::destroy(&*(it++));
        allocator_type::deallocate(static_cast< pointer >(m_RootNode._m_pNext), m_Size);
    }
}

//! Swaps two instances of the container
BOOST_LOG_API void named_scope_list::swap(named_scope_list& that)
{
    if (!this->empty())
    {
        if (!that.empty())
        {
            // both containers are not empty
            std::swap(m_RootNode._m_pNext->_m_pPrev, that.m_RootNode._m_pNext->_m_pPrev);
            std::swap(m_RootNode._m_pPrev->_m_pNext, that.m_RootNode._m_pPrev->_m_pNext);
            std::swap(m_RootNode, that.m_RootNode);
            std::swap(m_Size, that.m_Size);
            std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
        }
        else
        {
            // this is not empty
            m_RootNode._m_pNext->_m_pPrev = m_RootNode._m_pPrev->_m_pNext = &that.m_RootNode;
            that.m_RootNode = m_RootNode;
            m_RootNode._m_pNext = m_RootNode._m_pPrev = &m_RootNode;
            std::swap(m_Size, that.m_Size);
            std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
        }
    }
    else if (!that.empty())
    {
        // that is not empty
        that.m_RootNode._m_pNext->_m_pPrev = that.m_RootNode._m_pPrev->_m_pNext = &m_RootNode;
        m_RootNode = that.m_RootNode;
        that.m_RootNode._m_pNext = that.m_RootNode._m_pPrev = &that.m_RootNode;
        std::swap(m_Size, that.m_Size);
        std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
    }
}

//! Constructor
named_scope::named_scope() :
    attribute(impl::instance)
{
}

//! Constructor for casting support
named_scope::named_scope(cast_source const& source) :
    attribute(source.as< impl >())
{
}

//! The method pushes the scope to the stack
void named_scope::push_scope(scope_entry const& entry) BOOST_NOEXCEPT
{
    impl::scope_list& s = impl::instance->get_scope_list();
    s.push_back(entry);
}

//! The method pops the top scope
void named_scope::pop_scope() BOOST_NOEXCEPT
{
    impl::scope_list& s = impl::instance->get_scope_list();
    s.pop_back();
}

//! Returns the current thread's scope stack
named_scope::value_type const& named_scope::get_scopes()
{
    return impl::instance->get_scope_list();
}

} // namespace attributes

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>