xref: /trunk/main/o3tl/inc/o3tl/cow_wrapper.hxx (revision b0075c8b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef INCLUDED_O3TL_COW_WRAPPER_HXX
25 #define INCLUDED_O3TL_COW_WRAPPER_HXX
26 
27 #include <osl/interlck.h>
28 
29 #include <algorithm>
30 
31 #include <boost/utility.hpp>
32 #include <boost/checked_delete.hpp>
33 
34 namespace o3tl
35 {
36     /** Thread-unsafe refcounting
37 
38         This is the default locking policy for cow_wrapper. No
39         locking/guarding against concurrent access is performed
40         whatsoever.
41      */
42     struct UnsafeRefCountingPolicy
43     {
44         typedef sal_uInt32 ref_count_t;
incrementCounto3tl::UnsafeRefCountingPolicy45         static void incrementCount( ref_count_t& rCount ) { ++rCount; }
decrementCounto3tl::UnsafeRefCountingPolicy46         static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
47     };
48 
49     /** Thread-safe refcounting
50 
51         Use this to have the cow_wrapper refcounting mechanisms employ
52         the thread-safe oslInterlockedCount .
53      */
54     struct ThreadSafeRefCountingPolicy
55     {
56         typedef oslInterlockedCount ref_count_t;
incrementCounto3tl::ThreadSafeRefCountingPolicy57         static void incrementCount( ref_count_t& rCount ) { osl_incrementInterlockedCount(&rCount); }
decrementCounto3tl::ThreadSafeRefCountingPolicy58         static bool decrementCount( ref_count_t& rCount )
59         {
60             if( rCount == 1 ) // caller is already the only/last reference
61                 return false;
62             else
63                 return osl_decrementInterlockedCount(&rCount) != 0;
64         }
65     };
66 
67     /** Copy-on-write wrapper.
68 
69         This template provides copy-on-write semantics for the wrapped
70         type: when copying, the operation is performed shallow,
71         i.e. different cow_wrapper objects share the same underlying
72         instance. Only when accessing the underlying object via
73         non-const methods, a unique copy is provided.
74 
75         The type parameter <code>T</code> must satisfy the following
76         requirements: it must be default-constructible, copyable (it
77         need not be assignable), and be of non-reference type. Note
78         that, despite the fact that this template provides access to
79         the wrapped type via pointer-like methods
80         (<code>operator->()</code> and <code>operator*()</code>), it does
81         <em>not</em> work like e.g. the boost pointer wrappers
82         (shared_ptr, scoped_ptr, etc.). Internally, the cow_wrapper
83         holds a by-value instance of the wrapped object. This is to
84         avoid one additional heap allocation, and providing access via
85         <code>operator->()</code>/<code>operator*()</code> is because
86         <code>operator.()</code> cannot be overridden.
87 
88         Regarding thread safety: this wrapper is <em>not</em>
89         thread-safe per se, because cow_wrapper has no way of
90         syncronizing the potentially many different cow_wrapper
91         instances, that reference a single shared value_type
92         instance. That said, when passing
93         <code>ThreadSafeRefCountingPolicy</code> as the
94         <code>MTPolicy</code> parameter, accessing a thread-safe
95         pointee through multiple cow_wrapper instances might be
96         thread-safe, if the individual pointee methods are
97         thread-safe, <em>including</em> pointee's copy
98         constructor. Any wrapped object that needs external
99         synchronisation (e.g. via an external mutex, which arbitrates
100         access to object methods, and can be held across multiple
101         object method calls) cannot easily be dealt with in a
102         thread-safe way, because, as noted, objects are shared behind
103         the client's back.
104 
105         @attention if one wants to use the pimpl idiom together with
106         cow_wrapper (i.e. put an opaque type into the cow_wrapper),
107         then <em>all<em> methods in the surrounding class needs to be
108         non-inline (<em>including</em> destructor, copy constructor
109         and assignment operator).
110 
111         @example
112         <pre>
113 class cow_wrapper_client_impl;
114 
115 class cow_wrapper_client
116 {
117 public:
118     cow_wrapper_client();
119     cow_wrapper_client( const cow_wrapper_client& );
120     ~cow_wrapper_client();
121 
122     cow_wrapper_client& operator=( const cow_wrapper_client& );
123 
124     void modify( int nVal );
125     int queryUnmodified() const;
126 
127 private:
128     otl::cow_wrapper< cow_wrapper_client_impl > maImpl;
129 };
130         </pre>
131         and the implementation file would look like this:
132         <pre>
133 class cow_wrapper_client_impl
134 {
135 public:
136 	void setValue( int nVal ) { mnValue = nVal; }
137 	int getValue() const { return mnValue; }
138 
139 private:
140 	int mnValue;
141 }
142 
143 cow_wrapper_client::cow_wrapper_client() :
144 	maImpl()
145 {
146 }
147 cow_wrapper_client::cow_wrapper_client( const cow_wrapper_client& rSrc ) :
148 	maImpl( rSrc.maImpl )
149 {
150 }
151 cow_wrapper_client::~cow_wrapper_client()
152 {
153 }
154 cow_wrapper_client& cow_wrapper_client::operator=( const cow_wrapper_client& rSrc )
155 {
156 	maImpl = rSrc.maImpl;
157     return *this;
158 }
159 void cow_wrapper_client::modify( int nVal )
160 {
161 	maImpl->setValue( nVal );
162 }
163 void cow_wrapper_client::queryUnmodified() const
164 {
165 	return maImpl->getValue();
166 }
167         </pre>
168      */
169     template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
170     {
171         /** shared value object - gets cloned before cow_wrapper hands
172             out a non-const reference to it
173          */
174         struct impl_t : private boost::noncopyable
175         {
impl_to3tl::cow_wrapper::impl_t176             impl_t() :
177                 m_value(),
178                 m_ref_count(1)
179             {
180             }
181 
impl_to3tl::cow_wrapper::impl_t182             explicit impl_t( const T& v ) :
183                 m_value(v),
184                 m_ref_count(1)
185             {
186             }
187 
188             T                              m_value;
189             typename MTPolicy::ref_count_t m_ref_count;
190         };
191 
release()192         void release()
193         {
194             if( !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
195                 boost::checked_delete(m_pimpl), m_pimpl=0;
196         }
197 
198     public:
199         typedef T        value_type;
200         typedef T*       pointer;
201         typedef const T* const_pointer;
202         typedef MTPolicy mt_policy;
203 
204         /** Default-construct wrapped type instance
205          */
cow_wrapper()206         cow_wrapper() :
207             m_pimpl( new impl_t() )
208         {
209         }
210 
211         /** Copy-construct wrapped type instance from given object
212          */
cow_wrapper(const value_type & r)213         explicit cow_wrapper( const value_type& r ) :
214             m_pimpl( new impl_t(r) )
215         {
216         }
217 
218         /** Shallow-copy given cow_wrapper
219          */
cow_wrapper(const cow_wrapper & rSrc)220         explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
221             m_pimpl( rSrc.m_pimpl )
222         {
223             MTPolicy::incrementCount( m_pimpl->m_ref_count );
224         }
225 
~cow_wrapper()226         ~cow_wrapper() // nothrow, if ~T does not throw
227         {
228             release();
229         }
230 
231         /// now sharing rSrc cow_wrapper instance with us
operator =(const cow_wrapper & rSrc)232         cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
233         {
234             // this already guards against self-assignment
235             MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
236 
237             release();
238             m_pimpl = rSrc.m_pimpl;
239 
240             return *this;
241         }
242 
243         /// unshare with any other cow_wrapper instance
make_unique()244         value_type& make_unique()
245         {
246             if( m_pimpl->m_ref_count > 1 )
247             {
248                 impl_t* pimpl = new impl_t(m_pimpl->m_value);
249                 release();
250                 m_pimpl = pimpl;
251             }
252 
253             return m_pimpl->m_value;
254         }
255 
256         /// true, if not shared with any other cow_wrapper instance
is_unique() const257         bool is_unique() const // nothrow
258         {
259             return m_pimpl->m_ref_count == 1;
260         }
261 
262         /// return number of shared instances (1 for unique object)
use_count() const263         typename MTPolicy::ref_count_t use_count() const // nothrow
264         {
265             return m_pimpl->m_ref_count;
266         }
267 
swap(cow_wrapper & r)268         void swap(cow_wrapper& r) // never throws
269         {
270             std::swap(m_pimpl, r.m_pimpl);
271         }
272 
operator ->()273         pointer		      operator->()       { return &make_unique(); }
operator *()274         value_type&       operator*()        { return make_unique(); }
operator ->() const275         const_pointer     operator->() const { return &m_pimpl->m_value; }
operator *() const276         const value_type& operator*()  const { return m_pimpl->m_value; }
277 
get()278         pointer           get()       { return &make_unique(); }
get() const279         const_pointer	  get() const { return &m_pimpl->m_value; }
280 
281         /// true, if both cow_wrapper internally share the same object
same_object(const cow_wrapper & rOther) const282         bool              same_object( const cow_wrapper& rOther ) const
283         {
284             return rOther.m_pimpl == m_pimpl;
285         }
286 
287     private:
288         impl_t* m_pimpl;
289     };
290 
291 
operator ==(const cow_wrapper<T,P> & a,const cow_wrapper<T,P> & b)292     template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
293                                                        const cow_wrapper<T,P>& b )
294     {
295         return a.same_object(b) ? true : *a == *b;
296     }
297 
operator !=(const cow_wrapper<T,P> & a,const cow_wrapper<T,P> & b)298     template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
299                                                        const cow_wrapper<T,P>& b )
300     {
301         return a.same_object(b) ? false : *a != *b;
302     }
303 
operator <(const cow_wrapper<A,P> & a,const cow_wrapper<B,P> & b)304     template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
305                                                                const cow_wrapper<B,P>& b )
306     {
307         return *a < *b;
308     }
309 
swap(cow_wrapper<T,P> & a,cow_wrapper<T,P> & b)310     template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
311                                                  cow_wrapper<T,P>& b )
312     {
313         a.swap(b);
314     }
315 
316     // to enable boost::mem_fn on cow_wrapper
get_pointer(const cow_wrapper<T,P> & r)317     template<class T, class P> inline T * get_pointer( const cow_wrapper<T,P>& r )
318     {
319         return r.get();
320     }
321 
322 }
323 
324 #endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
325