refcntr.hpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     refcntr.hpp -- The implementation of reference counter class.
00004 
00005     Copyright (C) Sergey S. Lyalin, 2005
00006     University of Nizhni Novgorod, Russia
00007 
00008 *****************************************************************************/
00009 
00010 #ifndef _ARAGELI_refcntr_hpp_
00011 #define _ARAGELI_refcntr_hpp_
00012 
00013 #include "config.hpp"
00014 
00015 #include <cstddef>
00016 #include <memory>
00017 #include <algorithm>
00018 #include <limits>
00019 
00020 #include "exception.hpp"
00021 #include "type_opers.hpp"
00022 
00023 #include "std_import.hpp"
00024 
00025 namespace Arageli
00026 {
00027 
00028 
00029 
00030 template <typename T, typename TC = std::size_t>
00031 class refcntr
00032 {
00033 public:
00034 
00035     typedef T value_type;
00036     typedef TC counter_type;
00037 
00038     refcntr (const counter_type& refs_a = counter_type(1))
00039     : refs_m(refs_a) {}
00040     
00041     refcntr
00042     (
00043         const value_type& value_a,
00044         const counter_type& refs_a = counter_type(1)
00045     )
00046     : value_m(value_a), refs_m(refs_a) {}
00047 
00048     value_type& value () { return value_m; }
00049     const value_type& value () const { return value_m; }
00050 
00051     const counter_type& refs () const { return refs_m; }
00052     
00053     void link (const counter_type& n = counter_type(1))
00054     {
00055         ARAGELI_ASSERT_0(n >= 1);
00056         
00057         ARAGELI_ASSERT_0
00058         (
00059             !std::numeric_limits<TC>::is_bounded ||
00060             std::numeric_limits<TC>::max() - n >= refs_m
00061         );
00062 
00063         refs_m += n;
00064     }
00065     
00066     bool unlink (const counter_type& n = counter_type(1))
00067     {
00068         ARAGELI_ASSERT_0(n >= 1);
00069         ARAGELI_ASSERT_0(refs_m >= n);
00070 
00071         return !(refs_m -= n);
00072     }
00073 
00074     void unlink_all () { refs_m = counter_type(0); }
00075 
00076 private:
00077 
00078     counter_type refs_m;
00079     value_type value_m;
00080 };
00081 
00082 
00083 // 'refcntr_proxy' служит интерфейсом для отключаемого счётчика ссылок
00084 // и держит в себе значение. Нет общей реализации этого шаблона, предоставлены
00085 // две частичные специализации: для включённого счётчика ссылок (on_a == true)
00086 // и отключённого счётчика ссылок (on_a == false).
00087 template
00088 <
00089     typename T,
00090     bool on_a = true,
00091     typename TC = typename refcntr<T>::counter_type,
00092     typename A = std::allocator<T>
00093 >
00094 class refcntr_proxy;
00095 
00096 
00097 // Объект со счётчиком ссылок, держит значение и счётчик в памяти получаемой
00098 // с помощью распределителя A.
00099 template <typename T, typename TC, typename A>
00100 class refcntr_proxy<T, true, TC, A>
00101 {
00102 
00103     //template <typename, bool, typename, typename>
00104     //friend class refcntr_proxy;
00105 
00106     typedef typename A::template rebind<refcntr<T, TC> >::other Ref_alloc;
00107 
00108 public:
00109 
00110     typedef T value_type;
00111     typedef TC counter_type;
00112     typedef A Allocator;
00113     static const bool COUNTING = true;
00114 
00115 
00116     refcntr_proxy ()
00117     {
00118         refcntr_m = alloc.allocate(1);
00119         new (refcntr_m) refcntr<T>();
00120     }
00121     
00122     refcntr_proxy (const value_type& value_a)
00123     {
00124         refcntr_m = alloc.allocate(1);
00125         new (refcntr_m) refcntr<T>(value_a);
00126     }
00127 
00128     refcntr_proxy (const refcntr_proxy& x)
00129     : refcntr_m(x.refcntr_m)
00130     { refcntr_m->link(); }
00131 
00132     ~refcntr_proxy () { destroy(); }
00133 
00134     refcntr_proxy& operator= (const refcntr_proxy& x)
00135     {
00136         if(&x != this && refcntr_m != x.refcntr_m)
00137         {
00138             destroy();
00139             (refcntr_m = x.refcntr_m)->link();
00140         }
00141         return *this;
00142     }
00143 
00144     value_type& value () { return refcntr_m->value(); }
00145     const value_type& value () const { return refcntr_m->value(); }
00146 
00147     const counter_type& refs () const { return refcntr_m->refs(); }
00148     
00149     // возвращает true, если значение осталось прежним,
00150     // false, если была сделана новая копия
00151     bool unique ()
00152     {
00153         if(refs() == 1)return true;
00154         do_unique();
00155         return false;
00156     }
00157 
00158     void do_unique ()
00159     {
00160         typename Ref_alloc::pointer nt = alloc.allocate(1);
00161         new (nt) refcntr<T>(value());   // копия старого значения
00162         refcntr_m->unlink();
00163         refcntr_m = nt;
00164     }
00165 
00166     // возвращает true, если значение осталось прежним,
00167     // false, если был сделан новый чистый объект
00168     bool unique_clear ()
00169     {
00170         if(refs() == 1)return true;
00171         do_unique_clear();
00172         return false;
00173     }
00174 
00175     void do_unique_clear ()
00176     {
00177         typename Ref_alloc::pointer nt = alloc.allocate(1);
00178         new (nt) refcntr<T>;    // новый чистый объект
00179         refcntr_m->unlink();
00180         refcntr_m = nt;
00181     }
00182 
00183     bool counting () const { return COUNTING; }
00184 
00185     // ПРЕДУПРЕЖДЕНИЕ. Нужно ещё добавить swap в std.
00186 
00187     template <typename T1, typename TC1, typename A1>
00188     void swap (refcntr_proxy<T1, false, TC1, A1>& x)
00189     { swap_values(x); }
00190 
00191     template <typename T1, typename TC1, typename A1>
00192     void swap (refcntr_proxy<T1, true, TC1, A1>& x)
00193     {
00194         swap_help_1(x, equal_types<refcntr<T, TC>, refcntr<T1, TC1> >::value);
00195     }
00196 
00197 private:
00198 
00199     void destroy ()
00200     {
00201         if(refcntr_m->unlink())
00202         {
00203             alloc.destroy(refcntr_m);
00204             alloc.deallocate(refcntr_m, 1);
00205         }
00206     }
00207 
00208     template <typename T1, typename TC1, typename A1>
00209     void swap_help_1 (refcntr_proxy<T1, true, TC1, A1>& x, true_type)
00210     {
00211         ARAGELI_ASSERT_1
00212             ((equal_types<refcntr<T, TC>, refcntr<T1, TC1> >::bvalue));
00213 
00214         if(alloc == x.alloc)
00215             std::swap(refcntr_m, x.refcntr_m);
00216         else
00217             swap_values(x);
00218     }
00219 
00220     template <typename T1, typename TC1, typename A1>
00221     void swap_help_1 (refcntr_proxy<T1, true, TC1, A1>& x, false_type)
00222     { swap_values(x); }
00223 
00224     template <typename T1, bool REFCNT, typename TC1, typename A1>
00225     void swap_values (refcntr_proxy<T1, REFCNT, TC1, A1>& x)
00226     {
00227         unique(); x.unique();
00228         std::swap(value(), x.value());
00229     }
00230 
00231     typename Ref_alloc::pointer refcntr_m;
00232     Ref_alloc alloc;
00233 
00234 };
00235 
00236 
00237 // Значение без счётчика ссылок, содержит в себе объект типа T без счётчиков.
00238 // Распределитель памяти A в процессе работы не используется.
00239 template <typename T, typename TC, typename A>
00240 class refcntr_proxy<T, false, TC, A>
00241 {
00242     
00243     //template <typename, bool, typename, typename>
00244     //friend class refcntr_proxy;
00245 
00246 public:
00247 
00248     typedef T value_type;
00249     typedef TC counter_type;
00250     static const bool COUNTING = false;
00251     typedef A Allocator;
00252 
00253     refcntr_proxy () {}
00254     
00255     refcntr_proxy (const T& value_a)
00256     : value_m(value_a) {}
00257 
00258     value_type& value () { return value_m; }
00259     const value_type& value () const { return value_m; }
00260 
00261     const counter_type& refs () const { return one_always; }
00262     bool unique_clear () const { return true; }
00263     bool unique () const { return true; }
00264 
00265     bool counting () const { return COUNTING; }
00266 
00267     template <typename T1, bool REFCNT1, typename TC1, typename A1>
00268     void swap (refcntr_proxy<T1, REFCNT1, TC1, A1>& x)
00269     { std::swap(value(), x.value()); }
00270 
00271 private:
00272 
00273     value_type value_m;
00274     static const counter_type one_always = counter_type(1);
00275 
00276 };
00277 
00278 template <typename T, typename TC, typename A>
00279 const TC refcntr_proxy<T, false, TC, A>::one_always;
00280 
00281 
00282 }
00283 
00284 
00285 namespace std
00286 {
00287 
00288 template
00289 <
00290     typename T1, bool REFCNT1, typename TC1, typename A1,
00291     typename T2, bool REFCNT2, typename TC2, typename A2
00292 >
00293 inline void swap
00294 (
00295     Arageli::refcntr_proxy<T1, REFCNT1, TC1, A1>& a,
00296     Arageli::refcntr_proxy<T2, REFCNT2, TC2, A2>& b
00297 )
00298 { a.swap(b); }
00299 
00300 
00301 // Without this specialization ambigues call betwin standard swap and
00302 // swap above is appeared.
00303 template <typename T1, bool REFCNT1, typename TC1, typename A1>
00304 inline void swap
00305 (
00306     Arageli::refcntr_proxy<T1, REFCNT1, TC1, A1>& a,
00307     Arageli::refcntr_proxy<T1, REFCNT1, TC1, A1>& b
00308 )
00309 { a.swap(b); }
00310 
00311 
00312 
00313 }
00314 
00315 
00316 #endif  //  _ARAGELI_refcntr_hpp_

Generated on Thu Aug 31 17:38:09 2006 for Arageli by  doxygen 1.4.7