00001
00002
00003
00004
00005
00006
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
00084
00085
00086
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
00099 template <typename T, typename TC, typename A>
00100 class refcntr_proxy<T, true, TC, A>
00101 {
00102
00103
00104
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
00150
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
00167
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
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
00238
00239 template <typename T, typename TC, typename A>
00240 class refcntr_proxy<T, false, TC, A>
00241 {
00242
00243
00244
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
00302
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_