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