stlab.adobe.com Adobe Systems Incorporated

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 /**************************************************************************************************/

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google