00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00040 #ifndef SCYTHE_DATABLOCK_H
00041 #define SCYTHE_DATABLOCK_H
00042
00043 #ifdef SCYTHE_COMPILE_DIRECT
00044 #include "error.h"
00045 #else
00046 #include "scythestat/error.h"
00047 #endif
00048
00049 namespace scythe {
00050
00051 namespace {
00052 typedef unsigned int uint;
00053 }
00054
00061 template <typename T_type>
00062 class DataBlock {
00063 public:
00064
00065
00066
00067
00068
00069
00070 DataBlock ()
00071 : data_ (0),
00072 size_ (0),
00073 refs_ (0)
00074 {}
00075
00076
00077
00078
00079 explicit
00080 DataBlock (uint size)
00081 : data_ (0),
00082 size_ (0),
00083 refs_ (0)
00084 {
00085 resize(size);
00086 SCYTHE_DEBUG_MSG("Constructed new " << size << "(" << size_
00087 << ") DataBlock at address " << data_);
00088 }
00089
00090
00091
00092
00093 DataBlock (const DataBlock<T_type>& b)
00094 : data_ (b.data_),
00095 size_ (b.size_),
00096 refs_ (b.refs_)
00097 {}
00098
00099
00100
00101 ~DataBlock ()
00102 {
00103 SCYTHE_DEBUG_MSG("Destructing block at " << data_);
00104 deallocate();
00105 }
00106
00107
00108
00109 inline uint addReference ()
00110 {
00111 SCYTHE_DEBUG_MSG("Added reference to DataBlock at address "
00112 << data_);
00113 return ++refs_;
00114 }
00115
00116 inline uint removeReference ()
00117 {
00118 SCYTHE_DEBUG_MSG("Removed reference to DataBlock at address "
00119 << data_);
00120 return --refs_ ;
00121 }
00122
00123 inline uint references ()
00124 {
00125 return refs_;
00126 }
00127
00128
00129
00130 inline T_type* data()
00131 {
00132 return data_;
00133 }
00134
00135 inline const T_type* data() const
00136 {
00137 return data_;
00138 }
00139
00140 inline uint size () const
00141 {
00142 return size_;
00143 }
00144
00145 protected:
00146
00147
00148
00149 inline void allocate (uint size)
00150 {
00151
00152
00153
00154 if (data_ != 0)
00155 deallocate();
00156
00157 data_ = new (std::nothrow) T_type[size];
00158
00159 SCYTHE_CHECK_10(data_ == 0, scythe_alloc_error,
00160 "Failure allocating DataBlock of size " << size);
00161 }
00162
00163
00164 inline void deallocate ()
00165 {
00166 SCYTHE_DEBUG_MSG(" Deallocating DataBlock of size " << size_
00167 << " at address " << data_);
00168 delete[] data_;
00169 data_ = 0;
00170 }
00171
00172 public:
00173
00174
00175
00176 void resize (uint newsize)
00177 {
00178 if (newsize > size_)
00179 grow(newsize);
00180 else if (newsize < size_ / 4)
00181 shrink();
00182 }
00183
00184 protected:
00185
00186
00187 inline void grow (uint newsize)
00188 {
00189 size_ = size_ ? size_ : 1;
00190
00191
00192
00193
00194 while (size_ < newsize)
00195 size_ <<= 1;
00196
00197 allocate(size_);
00198 }
00199
00200
00201 inline void shrink ()
00202 {
00203 size_ >>= 1;
00204 allocate(size_);
00205 }
00206
00207 private:
00208
00209 T_type *data_;
00210 uint size_;
00211 uint refs_;
00212 };
00213
00218 template <class T_type>
00219 class NullDataBlock : public DataBlock<T_type>
00220 {
00221 typedef DataBlock<T_type> T_base;
00222 public:
00223
00224 NullDataBlock ()
00225 : DataBlock<T_type> ()
00226 {
00227
00228 T_base::addReference();
00229 SCYTHE_DEBUG_MSG("Constructed NULL datablock");
00230 }
00231
00232 ~NullDataBlock ()
00233 {}
00234
00235 };
00236
00237
00245 template <class T_type>
00246 class DataBlockReference {
00247 public:
00248
00249
00250
00251
00252 DataBlockReference ()
00253 : data_ (0),
00254 block_ (&nullBlock_)
00255 {
00256 block_->addReference();
00257 }
00258
00259
00260
00261 explicit
00262 DataBlockReference (uint size)
00263 : data_ (0),
00264 block_ (0)
00265 {
00266 block_ = new (std::nothrow) DataBlock<T_type> (size);
00267 SCYTHE_CHECK_10 (block_ == 0, scythe_alloc_error,
00268 "Could not allocate DataBlock object");
00269
00270 data_ = block_->data();
00271 block_->addReference();
00272 }
00273
00274
00275
00276 DataBlockReference (const DataBlockReference<T_type>& reference,
00277 uint offset = 0)
00278 : data_ (reference.data_ + offset),
00279 block_ (reference.block_)
00280 {
00281 block_->addReference();
00282 }
00283
00284
00285
00286
00287
00288 virtual ~DataBlockReference ()
00289 {
00290 withdrawReference();
00291 }
00292
00293 protected:
00294
00295
00296 void referenceOther (const DataBlockReference<T_type>& ref,
00297 uint offset = 0)
00298 {
00299 withdrawReference ();
00300 block_ = ref.block_;
00301 block_->addReference();
00302 data_ = ref.data_ + offset;
00303 }
00304
00305 void referenceNew (uint size)
00306 {
00307
00308
00309
00310
00311 if (block_->references() == 1) {
00312 block_->resize(size);
00313 data_ = block_->data();
00314
00315
00316 } else {
00317 withdrawReference();
00318 block_ = 0;
00319 block_ = new (std::nothrow) DataBlock<T_type> (size);
00320 SCYTHE_CHECK_10(block_ == 0, scythe_alloc_error,
00321 "Could not allocate new data block");
00322 data_ = block_->data();
00323 block_->addReference();
00324 }
00325 }
00326
00327 private:
00328
00329 void withdrawReference ()
00330 {
00331 if (block_->removeReference() == 0
00332 && block_ != &nullBlock_)
00333 delete block_;
00334 }
00335
00336 void referenceNull ()
00337 {
00338 withdrawReference();
00339 block_ = &nullBlock_;
00340 block_->addReference();
00341 data_ = 0;
00342 }
00343
00344
00345
00346 protected:
00347 T_type* data_;
00348
00349 private:
00350 DataBlock<T_type>* block_;
00351 static NullDataBlock<T_type> nullBlock_;
00352
00353 };
00354
00355
00356 template <typename T>
00357 NullDataBlock<T> DataBlockReference<T>::nullBlock_;
00358
00359 }
00360
00361 #endif