• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   mutable_constant.hpp
9  * \author Andrey Semashev
10  * \date   06.11.2007
11  *
12  * The header contains implementation of a mutable constant attribute.
13  */
14 
15 #ifndef BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_
16 #define BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_
17 
18 #include <boost/static_assert.hpp>
19 #include <boost/smart_ptr/intrusive_ptr.hpp>
20 #include <boost/move/core.hpp>
21 #include <boost/move/utility_core.hpp>
22 #include <boost/type_traits/is_void.hpp>
23 #include <boost/type_traits/conditional.hpp>
24 #include <boost/log/detail/config.hpp>
25 #include <boost/log/detail/locks.hpp>
26 #include <boost/log/attributes/attribute.hpp>
27 #include <boost/log/attributes/attribute_cast.hpp>
28 #include <boost/log/attributes/attribute_value_impl.hpp>
29 #include <boost/log/detail/header.hpp>
30 
31 #ifdef BOOST_HAS_PRAGMA_ONCE
32 #pragma once
33 #endif
34 
35 namespace boost {
36 
37 BOOST_LOG_OPEN_NAMESPACE
38 
39 namespace attributes {
40 
41 /*!
42  * \brief A class of an attribute that holds a single constant value with ability to change it
43  *
44  * The mutable_constant attribute stores a single value of type, specified as the first template argument.
45  * This value is returned on each attribute value acquisition.
46  *
47  * The attribute also allows to modify the stored value, even if the attribute is registered in an attribute set.
48  * In order to ensure thread safety of such modifications the \c mutable_constant class is also parametrized
49  * with three additional template arguments: mutex type, scoped write and scoped read lock types. If not specified,
50  * the lock types are automatically deduced based on the mutex type.
51  *
52  * The implementation may avoid using these types to actually create and use the mutex, if a more efficient synchronization method is
53  * available (such as atomic operations on the value type). By default no synchronization is done.
54  */
55 #ifdef BOOST_LOG_DOXYGEN_PASS
56 template< typename T, typename MutexT = void, typename ScopedWriteLockT = auto, typename ScopedReadLockT = auto >
57 #else // BOOST_LOG_DOXYGEN_PASS
58 template<
59     typename T,
60     typename MutexT = void,
61     typename ScopedWriteLockT =
62 #ifndef BOOST_LOG_NO_THREADS
63         typename boost::conditional<
64             boost::log::aux::is_exclusively_lockable< MutexT >::value,
65             boost::log::aux::exclusive_lock_guard< MutexT >,
66             void
67         >::type,
68 #else
69         void,
70 #endif // BOOST_LOG_NO_THREADS
71     typename ScopedReadLockT =
72 #ifndef BOOST_LOG_NO_THREADS
73         typename boost::conditional<
74             boost::log::aux::is_shared_lockable< MutexT >::value,
75             boost::log::aux::shared_lock_guard< MutexT >,
76             ScopedWriteLockT
77         >::type
78 #else
79         ScopedWriteLockT
80 #endif // BOOST_LOG_NO_THREADS
81 #endif // BOOST_LOG_DOXYGEN_PASS
82 >
83 class mutable_constant :
84     public attribute
85 {
86 public:
87     //! The attribute value type
88     typedef T value_type;
89 
90 protected:
91     //! Factory implementation
92     class BOOST_SYMBOL_VISIBLE impl :
93         public attribute::impl
94     {
95     private:
96         //! Mutex type
97         typedef MutexT mutex_type;
98         //! Shared lock type
99         typedef ScopedReadLockT scoped_read_lock;
100         //! Exclusive lock type
101         typedef ScopedWriteLockT scoped_write_lock;
102         BOOST_STATIC_ASSERT_MSG(!(is_void< mutex_type >::value || is_void< scoped_read_lock >::value || is_void< scoped_write_lock >::value), "Boost.Log: Mutex and both lock types either must not be void or must all be void");
103         //! Attribute value wrapper
104         typedef attribute_value_impl< value_type > attr_value;
105 
106     private:
107         //! Thread protection mutex
108         mutable mutex_type m_Mutex;
109         //! Pointer to the actual attribute value
110         intrusive_ptr< attr_value > m_Value;
111 
112     public:
113         /*!
114          * Initializing constructor
115          */
impl(value_type const & value)116         explicit impl(value_type const& value) : m_Value(new attr_value(value))
117         {
118         }
119         /*!
120          * Initializing constructor
121          */
impl(BOOST_RV_REF (value_type)value)122         explicit impl(BOOST_RV_REF(value_type) value) : m_Value(new attr_value(boost::move(value)))
123         {
124         }
125 
get_value()126         attribute_value get_value()
127         {
128             scoped_read_lock lock(m_Mutex);
129             return attribute_value(m_Value);
130         }
131 
set(value_type const & value)132         void set(value_type const& value)
133         {
134             intrusive_ptr< attr_value > p = new attr_value(value);
135             scoped_write_lock lock(m_Mutex);
136             m_Value.swap(p);
137         }
138 
set(BOOST_RV_REF (value_type)value)139         void set(BOOST_RV_REF(value_type) value)
140         {
141             intrusive_ptr< attr_value > p = new attr_value(boost::move(value));
142             scoped_write_lock lock(m_Mutex);
143             m_Value.swap(p);
144         }
145 
get() const146         value_type get() const
147         {
148             scoped_read_lock lock(m_Mutex);
149             return m_Value->get();
150         }
151     };
152 
153 public:
154     /*!
155      * Constructor with the stored value initialization
156      */
mutable_constant(value_type const & value)157     explicit mutable_constant(value_type const& value) : attribute(new impl(value))
158     {
159     }
160     /*!
161      * Constructor with the stored value initialization
162      */
mutable_constant(BOOST_RV_REF (value_type)value)163     explicit mutable_constant(BOOST_RV_REF(value_type) value) : attribute(new impl(boost::move(value)))
164     {
165     }
166     /*!
167      * Constructor for casting support
168      */
mutable_constant(cast_source const & source)169     explicit mutable_constant(cast_source const& source) : attribute(source.as< impl >())
170     {
171     }
172 
173     /*!
174      * The method sets a new attribute value. The implementation exclusively locks the mutex in order
175      * to protect the value assignment.
176      */
set(value_type const & value)177     void set(value_type const& value)
178     {
179         get_impl()->set(value);
180     }
181 
182     /*!
183      * The method sets a new attribute value.
184      */
set(BOOST_RV_REF (value_type)value)185     void set(BOOST_RV_REF(value_type) value)
186     {
187         get_impl()->set(boost::move(value));
188     }
189 
190     /*!
191      * The method acquires the current attribute value. The implementation non-exclusively locks the mutex in order
192      * to protect the value acquisition.
193      */
get() const194     value_type get() const
195     {
196         return get_impl()->get();
197     }
198 
199 protected:
200     /*!
201      * \returns Pointer to the factory implementation
202      */
get_impl() const203     impl* get_impl() const
204     {
205         return static_cast< impl* >(attribute::get_impl());
206     }
207 };
208 
209 
210 /*!
211  * \brief Specialization for unlocked case
212  *
213  * This version of attribute does not perform thread synchronization to access the stored value.
214  */
215 template< typename T >
216 class mutable_constant< T, void, void, void > :
217     public attribute
218 {
219 public:
220     //! The attribute value type
221     typedef T value_type;
222 
223 protected:
224     //! Factory implementation
225     class BOOST_SYMBOL_VISIBLE impl :
226         public attribute::impl
227     {
228     private:
229         //! Attribute value wrapper
230         typedef attribute_value_impl< value_type > attr_value;
231 
232     private:
233         //! The actual value
234         intrusive_ptr< attr_value > m_Value;
235 
236     public:
237         /*!
238          * Initializing constructor
239          */
impl(value_type const & value)240         explicit impl(value_type const& value) : m_Value(new attr_value(value))
241         {
242         }
243         /*!
244          * Initializing constructor
245          */
impl(BOOST_RV_REF (value_type)value)246         explicit impl(BOOST_RV_REF(value_type) value) : m_Value(new attr_value(boost::move(value)))
247         {
248         }
249 
get_value()250         attribute_value get_value()
251         {
252             return attribute_value(m_Value);
253         }
254 
set(value_type const & value)255         void set(value_type const& value)
256         {
257             m_Value = new attr_value(value);
258         }
set(BOOST_RV_REF (value_type)value)259         void set(BOOST_RV_REF(value_type) value)
260         {
261             m_Value = new attr_value(boost::move(value));
262         }
263 
get() const264         value_type get() const
265         {
266             return m_Value->get();
267         }
268     };
269 
270 public:
271     /*!
272      * Constructor with the stored value initialization
273      */
mutable_constant(value_type const & value)274     explicit mutable_constant(value_type const& value) : attribute(new impl(value))
275     {
276     }
277     /*!
278      * Constructor with the stored value initialization
279      */
mutable_constant(BOOST_RV_REF (value_type)value)280     explicit mutable_constant(BOOST_RV_REF(value_type) value) : attribute(new impl(boost::move(value)))
281     {
282     }
283     /*!
284      * Constructor for casting support
285      */
mutable_constant(cast_source const & source)286     explicit mutable_constant(cast_source const& source) : attribute(source.as< impl >())
287     {
288     }
289 
290     /*!
291      * The method sets a new attribute value.
292      */
set(value_type const & value)293     void set(value_type const& value)
294     {
295         get_impl()->set(value);
296     }
297 
298     /*!
299      * The method sets a new attribute value.
300      */
set(BOOST_RV_REF (value_type)value)301     void set(BOOST_RV_REF(value_type) value)
302     {
303         get_impl()->set(boost::move(value));
304     }
305 
306     /*!
307      * The method acquires the current attribute value.
308      */
get() const309     value_type get() const
310     {
311         return get_impl()->get();
312     }
313 
314 protected:
315     /*!
316      * \returns Pointer to the factory implementation
317      */
get_impl() const318     impl* get_impl() const
319     {
320         return static_cast< impl* >(attribute::get_impl());
321     }
322 };
323 
324 } // namespace attributes
325 
326 BOOST_LOG_CLOSE_NAMESPACE // namespace log
327 
328 } // namespace boost
329 
330 #include <boost/log/detail/footer.hpp>
331 
332 #endif // BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_
333