blob: 52356b45de615b52eb64500528a0c7b84f3caa78 [file] [log] [blame]
/*
* 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 mutable_constant.hpp
* \author Andrey Semashev
* \date 06.11.2007
*
* The header contains implementation of a mutable constant attribute.
*/
#ifndef BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_
#define BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_
#include <boost/static_assert.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/mpl/if.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/locks.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#include <boost/log/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace attributes {
/*!
* \brief A class of an attribute that holds a single constant value with ability to change it
*
* The mutable_constant attribute stores a single value of type, specified as the first template argument.
* This value is returned on each attribute value acquisition.
*
* The attribute also allows to modify the stored value, even if the attribute is registered in an attribute set.
* In order to ensure thread safety of such modifications the \c mutable_constant class is also parametrized
* with three additional template arguments: mutex type, scoped write and scoped read lock types. If not specified,
* the lock types are automatically deduced based on the mutex type.
*
* The implementation may avoid using these types to actually create and use the mutex, if a more efficient synchronization method is
* available (such as atomic operations on the value type). By default no synchronization is done.
*/
#ifdef BOOST_LOG_DOXYGEN_PASS
template< typename T, typename MutexT = void, typename ScopedWriteLockT = auto, typename ScopedReadLockT = auto >
#else // BOOST_LOG_DOXYGEN_PASS
template<
typename T,
typename MutexT = void,
typename ScopedWriteLockT =
#ifndef BOOST_LOG_NO_THREADS
typename mpl::if_c<
boost::log::aux::is_exclusively_lockable< MutexT >::value,
boost::log::aux::exclusive_lock_guard< MutexT >,
void
>::type,
#else
void,
#endif // BOOST_LOG_NO_THREADS
typename ScopedReadLockT =
#ifndef BOOST_LOG_NO_THREADS
typename mpl::if_c<
boost::log::aux::is_shared_lockable< MutexT >::value,
boost::log::aux::shared_lock_guard< MutexT >,
ScopedWriteLockT
>::type
#else
ScopedWriteLockT
#endif // BOOST_LOG_NO_THREADS
#endif // BOOST_LOG_DOXYGEN_PASS
>
class mutable_constant :
public attribute
{
public:
//! The attribute value type
typedef T value_type;
protected:
//! Factory implementation
class BOOST_SYMBOL_VISIBLE impl :
public attribute::impl
{
private:
//! Mutex type
typedef MutexT mutex_type;
//! Shared lock type
typedef ScopedReadLockT scoped_read_lock;
//! Exclusive lock type
typedef ScopedWriteLockT scoped_write_lock;
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");
//! Attribute value wrapper
typedef attribute_value_impl< value_type > attr_value;
private:
//! Thread protection mutex
mutable mutex_type m_Mutex;
//! Pointer to the actual attribute value
intrusive_ptr< attr_value > m_Value;
public:
/*!
* Initializing constructor
*/
explicit impl(value_type const& value) : m_Value(new attr_value(value))
{
}
/*!
* Initializing constructor
*/
explicit impl(BOOST_RV_REF(value_type) value) : m_Value(new attr_value(boost::move(value)))
{
}
attribute_value get_value()
{
scoped_read_lock lock(m_Mutex);
return attribute_value(m_Value);
}
void set(value_type const& value)
{
intrusive_ptr< attr_value > p = new attr_value(value);
scoped_write_lock lock(m_Mutex);
m_Value.swap(p);
}
void set(BOOST_RV_REF(value_type) value)
{
intrusive_ptr< attr_value > p = new attr_value(boost::move(value));
scoped_write_lock lock(m_Mutex);
m_Value.swap(p);
}
value_type get() const
{
scoped_read_lock lock(m_Mutex);
return m_Value->get();
}
};
public:
/*!
* Constructor with the stored value initialization
*/
explicit mutable_constant(value_type const& value) : attribute(new impl(value))
{
}
/*!
* Constructor with the stored value initialization
*/
explicit mutable_constant(BOOST_RV_REF(value_type) value) : attribute(new impl(boost::move(value)))
{
}
/*!
* Constructor for casting support
*/
explicit mutable_constant(cast_source const& source) : attribute(source.as< impl >())
{
}
/*!
* The method sets a new attribute value. The implementation exclusively locks the mutex in order
* to protect the value assignment.
*/
void set(value_type const& value)
{
get_impl()->set(value);
}
/*!
* The method sets a new attribute value.
*/
void set(BOOST_RV_REF(value_type) value)
{
get_impl()->set(boost::move(value));
}
/*!
* The method acquires the current attribute value. The implementation non-exclusively locks the mutex in order
* to protect the value acquisition.
*/
value_type get() const
{
return get_impl()->get();
}
protected:
/*!
* \returns Pointer to the factory implementation
*/
impl* get_impl() const
{
return static_cast< impl* >(attribute::get_impl());
}
};
/*!
* \brief Specialization for unlocked case
*
* This version of attribute does not perform thread synchronization to access the stored value.
*/
template< typename T >
class mutable_constant< T, void, void, void > :
public attribute
{
public:
//! The attribute value type
typedef T value_type;
protected:
//! Factory implementation
class BOOST_SYMBOL_VISIBLE impl :
public attribute::impl
{
private:
//! Attribute value wrapper
typedef attribute_value_impl< value_type > attr_value;
private:
//! The actual value
intrusive_ptr< attr_value > m_Value;
public:
/*!
* Initializing constructor
*/
explicit impl(value_type const& value) : m_Value(new attr_value(value))
{
}
/*!
* Initializing constructor
*/
explicit impl(BOOST_RV_REF(value_type) value) : m_Value(new attr_value(boost::move(value)))
{
}
attribute_value get_value()
{
return attribute_value(m_Value);
}
void set(value_type const& value)
{
m_Value = new attr_value(value);
}
void set(BOOST_RV_REF(value_type) value)
{
m_Value = new attr_value(boost::move(value));
}
value_type get() const
{
return m_Value->get();
}
};
public:
/*!
* Constructor with the stored value initialization
*/
explicit mutable_constant(value_type const& value) : attribute(new impl(value))
{
}
/*!
* Constructor with the stored value initialization
*/
explicit mutable_constant(BOOST_RV_REF(value_type) value) : attribute(new impl(boost::move(value)))
{
}
/*!
* Constructor for casting support
*/
explicit mutable_constant(cast_source const& source) : attribute(source.as< impl >())
{
}
/*!
* The method sets a new attribute value.
*/
void set(value_type const& value)
{
get_impl()->set(value);
}
/*!
* The method sets a new attribute value.
*/
void set(BOOST_RV_REF(value_type) value)
{
get_impl()->set(boost::move(value));
}
/*!
* The method acquires the current attribute value.
*/
value_type get() const
{
return get_impl()->get();
}
protected:
/*!
* \returns Pointer to the factory implementation
*/
impl* get_impl() const
{
return static_cast< impl* >(attribute::get_impl());
}
};
} // namespace attributes
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#include <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_