copy_on_write.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 00005 */ 00006 00007 /**************************************************************************************************/ 00008 00009 #ifndef ADOBE_COPY_ON_WRITE_HPP 00010 #define ADOBE_COPY_ON_WRITE_HPP 00011 00012 /**************************************************************************************************/ 00013 00014 #include <adobe/config.hpp> 00015 00016 #include <algorithm> 00017 #include <cassert> 00018 #include <cstdlib> 00019 00020 #include <boost/noncopyable.hpp> 00021 #include <boost/operators.hpp> 00022 #include <boost/static_assert.hpp> 00023 00024 #include <adobe/counter.hpp> 00025 #include <adobe/memory.hpp> 00026 #include <adobe/move.hpp> 00027 #include <adobe/once.hpp> 00028 #include <adobe/typeinfo.hpp> 00029 00030 /**************************************************************************************************/ 00031 00032 namespace adobe { 00033 00034 /**************************************************************************************************/ 00035 00036 namespace version_1 { 00037 00038 /**************************************************************************************************/ 00039 00069 template <typename T, // T models Regular 00070 typename A = adobe::capture_allocator<T> > // A models Allocator 00071 class copy_on_write 00072 { 00073 public: 00075 typedef T value_type; 00077 typedef A allocator_type; 00078 00079 #if !defined(ADOBE_NO_DOCUMENTATION) 00080 private: 00081 struct implementation_t; 00082 typedef typename allocator_type::template rebind<implementation_t>::other implementation_allocator_type; 00083 public: 00084 #endif 00085 00091 copy_on_write() 00092 { 00093 adobe::call_once(init_default, flag_s); 00094 object_m = default_s; 00095 object_m->header_m.get().count_m.increment(); 00096 } 00097 00101 explicit copy_on_write(const allocator_type& a) : 00102 object_m(0) 00103 { 00104 implementation_allocator_type other_allocator(a); 00105 00106 object_m = allocate(other_allocator); 00107 } 00108 00116 copy_on_write(T x) : 00117 object_m(allocate_move(0, adobe::move(x))) 00118 { } 00119 00124 copy_on_write(const copy_on_write& x) : 00125 object_m(x.object_m) 00126 { 00127 if (object_m) 00128 object_m->header_m.get().count_m.increment(); 00129 } 00130 00131 copy_on_write(move_from<copy_on_write> x) : 00132 object_m(x.source.object_m) 00133 { 00134 x.source.object_m = 0; 00135 } 00136 00137 ~copy_on_write() 00138 { 00139 release(object_m); 00140 } 00141 00147 copy_on_write& operator=(copy_on_write x) 00148 { swap(*this, x); return *this; } 00149 00150 00151 copy_on_write& operator=(T x) 00152 { 00153 if (!object_m) 00154 object_m = allocate_move(0, adobe::move(x)); 00155 else if (object_m->header_m.get().count_m.is_one()) 00156 object_m->value_m = adobe::move(x); 00157 else 00158 reset(allocate_move(object_m, adobe::move(x))); 00159 00160 return *this; 00161 } 00162 00175 value_type& write() 00176 { 00177 assert(object_m && "FATAL (sparent) : using a moved copy_on_write object"); 00178 00179 if (!object_m->header_m.get().count_m.is_one()) 00180 reset(allocate(object_m, object_m->value_m)); 00181 00182 return object_m->value_m; 00183 } 00184 00190 const value_type& read() const 00191 { 00192 assert(object_m && "FATAL (sparent) : using a moved copy_on_write object"); 00193 return object_m->value_m; 00194 } 00195 00201 operator const value_type& () const 00202 { return read(); } 00203 00214 const value_type& operator*() const 00215 { return read(); } 00216 00227 const value_type* operator->() const 00228 { return &read(); } 00229 00237 bool unique_instance() const 00238 { return !object_m || object_m->header_m.get().count_m.is_one(); } 00239 00247 bool identity(const copy_on_write& x) const 00248 { return object_m == x.object_m; } 00249 00250 friend inline void swap(copy_on_write& x, copy_on_write& y) 00251 { std::swap(x.object_m, y.object_m); } 00252 00253 friend inline bool operator<(const copy_on_write& x, const copy_on_write& y) 00254 { return y.object_m && (!x.object_m || (!x.identity(y) && *x < *y)); } 00255 00256 friend inline bool operator>(const copy_on_write& x, const copy_on_write& y) 00257 { return y < x; } 00258 00259 friend inline bool operator<=(const copy_on_write& x, const copy_on_write& y) 00260 { return !(y < x); } 00261 00262 friend inline bool operator>=(const copy_on_write& x, const copy_on_write& y) 00263 { return !(x < y); } 00264 00265 friend inline bool operator==(const copy_on_write& x, const copy_on_write& y) 00266 { return x.identity(y) || (x.object_m && y.object_m && *x == *y); } 00267 00268 friend inline bool operator!=(const copy_on_write& x, const copy_on_write& y) 00269 { return !(x == y); } 00270 00271 allocator_type get_allocator() const 00272 { return object_m ? allocator_type(object_m->get_allocator()) : allocator_type(); } 00273 00274 private: 00275 #if !defined(ADOBE_NO_DOCUMENTATION) 00276 static implementation_t* allocate(const implementation_t* alloc_src, const T& x = T()) 00277 { 00278 implementation_allocator_type allocator(alloc_src ? 00279 alloc_src->get_allocator() : 00280 implementation_allocator_type()); 00281 00282 return allocate(allocator, x); 00283 } 00284 00285 static implementation_t* allocate(implementation_allocator_type& allocator, const T& x = T()) 00286 { 00287 implementation_t* tmp(allocator.allocate(1)); 00288 00289 try { 00290 ::new(static_cast<void*>(tmp)) implementation_t(x); 00291 } catch (...) { 00292 tmp->get_allocator().deallocate(tmp, 1); 00293 throw; 00294 } 00295 00296 return tmp; 00297 } 00298 00299 static implementation_t* allocate_move(const implementation_t* alloc_src, T x) 00300 { 00301 implementation_allocator_type allocator(alloc_src ? 00302 alloc_src->get_allocator() : 00303 implementation_allocator_type()); 00304 implementation_t* tmp(allocator.allocate(1)); 00305 00306 try { 00307 ::new(static_cast<void*>(tmp)) implementation_t(adobe::move(x)); 00308 } catch (...) { 00309 tmp->get_allocator().deallocate(tmp, 1); 00310 throw; 00311 } 00312 00313 return tmp; 00314 } 00315 00316 static void release(implementation_t* x) 00317 { 00318 /* 00319 I thought about returning a bool from this routine (denoting whether 00320 or not a deallocation took place) but decided not to in the end. 00321 Release's semantics are that of giving up ownership of the 00322 implementation instance, so you are not allowed to subsequently 00323 interact with the implementation instance you've released. Thus, 00324 notifying the caller of a deallocation is a moot point. 00325 */ 00326 00327 if (x == 0 || x->header_m.get().count_m.decrement() == false) 00328 return; 00329 00330 implementation_allocator_type allocator(x->get_allocator()); 00331 00332 destroy(x); 00333 00334 allocator.deallocate(x, 1); 00335 } 00336 00337 void reset(implementation_t* to) 00338 { 00339 release(object_m); 00340 object_m = to; 00341 } 00342 00343 implementation_t* object_m; 00344 00345 static once_flag flag_s; 00346 static implementation_t* default_s; 00347 00348 static void release_default(); 00349 static void init_default(); 00350 #endif 00351 }; 00352 00353 /**************************************************************************************************/ 00354 00355 #if !defined(ADOBE_NO_DOCUMENTATION) 00356 00357 /**************************************************************************************************/ 00358 00359 template <typename T, typename A> 00360 once_flag copy_on_write<T, A>::flag_s = ADOBE_ONCE_INIT; 00361 00362 template <typename T, typename A> 00363 typename copy_on_write<T, A>::implementation_t* copy_on_write<T, A>::default_s; 00364 00365 template <typename T, typename A> 00366 struct copy_on_write<T, A>::implementation_t : private boost::noncopyable 00367 { 00368 // Assert proper size for counter_t 00369 BOOST_STATIC_ASSERT((sizeof(counter_t) == sizeof(std::size_t))); 00370 // Assert proper alignment for counter_t 00371 BOOST_STATIC_ASSERT((sizeof(counter_t) == sizeof(void*))); 00372 00373 struct header_t 00374 { 00375 counter_t count_m; 00376 allocator_type allocator_m; 00377 }; 00378 00379 explicit implementation_t(T x) : 00380 value_m(adobe::move(x)) 00381 { } 00382 00383 implementation_allocator_type get_allocator() const 00384 { return implementation_allocator_type(header_m.get().allocator_m); } 00385 00386 aligned_storage<header_t> header_m; 00387 value_type value_m; 00388 }; 00389 00390 template <typename T, typename A> 00391 void copy_on_write<T, A>::init_default() 00392 { 00393 implementation_allocator_type allocator; 00394 00395 default_s = allocate(allocator); 00396 00397 std::atexit(release_default); // ignore failure 00398 } 00399 00400 template <typename T, typename A> 00401 void copy_on_write<T, A>::release_default() 00402 { 00403 release(default_s); 00404 } 00405 00406 #endif 00407 00408 /**************************************************************************************************/ 00409 00410 } // namespace version_1 00411 00412 /**************************************************************************************************/ 00413 00414 using version_1::copy_on_write; 00415 00416 /**************************************************************************************************/ 00417 00418 template <typename T, typename A> struct is_movable<copy_on_write<T, A> > : boost::mpl::true_ { }; 00419 00420 /**************************************************************************************************/ 00421 00422 } // namespace adobe 00423 00424 /**************************************************************************************************/ 00425 00426 ADOBE_NAME_TYPE_1("copy_on_write:version_1:adobe", adobe::version_1::copy_on_write<T0, adobe::capture_allocator<T0> >) 00427 ADOBE_NAME_TYPE_2("copy_on_write:version_1:adobe", adobe::version_1::copy_on_write<T0, T1>) 00428 00429 /**************************************************************************************************/ 00430 00431 #endif 00432 00433 /**************************************************************************************************/ |