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