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   locking_ptr.hpp
9  * \author Andrey Semashev
10  * \date   15.07.2009
11  *
12  * 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 #ifndef BOOST_LOG_DETAIL_LOCKING_PTR_HPP_INCLUDED_
17 #define BOOST_LOG_DETAIL_LOCKING_PTR_HPP_INCLUDED_
18 
19 #include <cstddef>
20 #include <boost/move/core.hpp>
21 #include <boost/smart_ptr/shared_ptr.hpp>
22 #include <boost/thread/lock_options.hpp>
23 #include <boost/log/detail/config.hpp>
24 #include <boost/utility/explicit_operator_bool.hpp>
25 #include <boost/log/detail/header.hpp>
26 
27 #ifdef BOOST_HAS_PRAGMA_ONCE
28 #pragma once
29 #endif
30 
31 namespace boost {
32 
33 BOOST_LOG_OPEN_NAMESPACE
34 
35 namespace aux {
36 
37 //! A pointer type that locks the backend until it's destroyed
38 template< typename T, typename LockableT >
39 class locking_ptr
40 {
41     typedef locking_ptr this_type;
42     BOOST_COPYABLE_AND_MOVABLE_ALT(this_type)
43 
44 public:
45     //! Pointed type
46     typedef T element_type;
47 
48 private:
49     //! Lockable type
50     typedef LockableT lockable_type;
51 
52 private:
53     //! The pointer to the backend
54     shared_ptr< element_type > m_pElement;
55     //! Reference to the shared lock control object
56     lockable_type* m_pLock;
57 
58 public:
59     //! Default constructor
locking_ptr()60     locking_ptr() BOOST_NOEXCEPT : m_pLock(NULL)
61     {
62     }
63     //! Constructor
locking_ptr(shared_ptr<element_type> const & p,lockable_type & l)64     locking_ptr(shared_ptr< element_type > const& p, lockable_type& l) : m_pElement(p), m_pLock(&l)
65     {
66         m_pLock->lock();
67     }
68     //! Constructor
locking_ptr(shared_ptr<element_type> const & p,lockable_type & l,try_to_lock_t const &)69     locking_ptr(shared_ptr< element_type > const& p, lockable_type& l, try_to_lock_t const&) : m_pElement(p), m_pLock(&l)
70     {
71         if (!m_pLock->try_lock())
72         {
73             m_pElement.reset();
74             m_pLock = NULL;
75         }
76     }
77     //! Copy constructor
locking_ptr(locking_ptr const & that)78     locking_ptr(locking_ptr const& that) : m_pElement(that.m_pElement), m_pLock(that.m_pLock)
79     {
80         if (m_pLock)
81             m_pLock->lock();
82     }
83     //! Move constructor
locking_ptr(BOOST_RV_REF (this_type)that)84     locking_ptr(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT : m_pLock(that.m_pLock)
85     {
86         m_pElement.swap(that.m_pElement);
87         that.m_pLock = NULL;
88     }
89 
90     //! Destructor
~locking_ptr()91     ~locking_ptr()
92     {
93         if (m_pLock)
94             m_pLock->unlock();
95     }
96 
97     //! Assignment
operator =(locking_ptr that)98     locking_ptr& operator= (locking_ptr that) BOOST_NOEXCEPT
99     {
100         this->swap(that);
101         return *this;
102     }
103 
104     //! Indirection
operator ->() const105     element_type* operator-> () const BOOST_NOEXCEPT { return m_pElement.get(); }
106     //! Dereferencing
operator *() const107     element_type& operator* () const BOOST_NOEXCEPT { return *m_pElement; }
108 
109     //! Accessor to the raw pointer
get() const110     element_type* get() const BOOST_NOEXCEPT { return m_pElement.get(); }
111 
112     //! Checks for null pointer
113     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
114     //! Checks for null pointer
115     bool operator! () const BOOST_NOEXCEPT { return !m_pElement; }
116 
117     //! Swaps two pointers
swap(locking_ptr & that)118     void swap(locking_ptr& that) BOOST_NOEXCEPT
119     {
120         m_pElement.swap(that.m_pElement);
121         lockable_type* p = m_pLock;
122         m_pLock = that.m_pLock;
123         that.m_pLock = p;
124     }
125 };
126 
127 //! Free raw pointer getter to assist generic programming
128 template< typename T, typename LockableT >
get_pointer(locking_ptr<T,LockableT> const & p)129 inline T* get_pointer(locking_ptr< T, LockableT > const& p) BOOST_NOEXCEPT
130 {
131     return p.get();
132 }
133 //! Free swap operation
134 template< typename T, typename LockableT >
swap(locking_ptr<T,LockableT> & left,locking_ptr<T,LockableT> & right)135 inline void swap(locking_ptr< T, LockableT >& left, locking_ptr< T, LockableT >& right) BOOST_NOEXCEPT
136 {
137     left.swap(right);
138 }
139 
140 } // namespace aux
141 
142 BOOST_LOG_CLOSE_NAMESPACE // namespace log
143 
144 } // namespace boost
145 
146 #include <boost/log/detail/footer.hpp>
147 
148 #endif // BOOST_LOG_DETAIL_LOCKING_PTR_HPP_INCLUDED_
149