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