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