00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef BZ_MEMBLOCK_H
00028 #define BZ_MEMBLOCK_H
00029
00030 #include <blitz/blitz.h>
00031
00032 #include <stddef.h>
00033
00034 #ifdef BZ_THREADSAFE
00035 #include <pthread.h>
00036 #endif
00037
00038 BZ_NAMESPACE(blitz)
00039
00040 enum preexistingMemoryPolicy {
00041 duplicateData,
00042 deleteDataWhenDone,
00043 neverDeleteData
00044 };
00045
00046
00047 template<typename T_type> class MemoryBlockReference;
00048
00049
00050
00051
00052
00053 template<typename P_type>
00054 class MemoryBlock {
00055
00056 friend class MemoryBlockReference<P_type>;
00057
00058 public:
00059 typedef P_type T_type;
00060
00061 protected:
00062 MemoryBlock()
00063 {
00064 length_ = 0;
00065 data_ = 0;
00066 dataBlockAddress_ = 0;
00067 references_ = 0;
00068
00069 BZ_MUTEX_INIT(mutex)
00070 }
00071
00072 explicit MemoryBlock(size_t items)
00073 {
00074 length_ = items;
00075 allocate(length_);
00076
00077 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00078 cout << "MemoryBlock: allocated " << setw(8) << length_
00079 << " at " << ((void *)dataBlockAddress_) << endl;
00080 #endif
00081
00082 BZASSERT(dataBlockAddress_ != 0);
00083
00084 references_ = 0;
00085
00086 BZ_MUTEX_INIT(mutex)
00087 }
00088
00089 MemoryBlock(size_t length, T_type* data)
00090 {
00091 length_ = length;
00092 data_ = data;
00093 dataBlockAddress_ = data;
00094 references_ = 0;
00095 BZ_MUTEX_INIT(mutex)
00096 }
00097
00098 virtual ~MemoryBlock()
00099 {
00100 if (dataBlockAddress_)
00101 {
00102
00103 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00104 cout << "MemoryBlock: freed " << setw(8) << length_
00105 << " at " << ((void *)dataBlockAddress_) << endl;
00106 #endif
00107
00108 deallocate();
00109 }
00110
00111 BZ_MUTEX_DESTROY(mutex)
00112 }
00113
00114 void addReference()
00115 {
00116 BZ_MUTEX_LOCK(mutex)
00117 ++references_;
00118
00119 #ifdef BZ_DEBUG_LOG_REFERENCES
00120 cout << "MemoryBlock: reffed " << setw(8) << length_
00121 << " at " << ((void *)dataBlockAddress_) << " (r="
00122 << (int)references_ << ")" << endl;
00123 #endif
00124 BZ_MUTEX_UNLOCK(mutex)
00125
00126 }
00127
00128 T_type* restrict data()
00129 {
00130 return data_;
00131 }
00132
00133 const T_type* restrict data() const
00134 {
00135 return data_;
00136 }
00137
00138 T_type*& dataBlockAddress()
00139 {
00140 return dataBlockAddress_;
00141 }
00142
00143 size_t length() const
00144 {
00145 return length_;
00146 }
00147
00148 int removeReference()
00149 {
00150
00151 BZ_MUTEX_LOCK(mutex)
00152 int refcount = --references_;
00153
00154 #ifdef BZ_DEBUG_LOG_REFERENCES
00155 cout << "MemoryBlock: dereffed " << setw(8) << length_
00156 << " at " << ((void *)dataBlockAddress_) << " (r=" << (int)references_
00157 << ")" << endl;
00158 #endif
00159 BZ_MUTEX_UNLOCK(mutex)
00160 return refcount;
00161 }
00162
00163 int references() const
00164 {
00165 BZ_MUTEX_LOCK(mutex)
00166 int refcount = references_;
00167 BZ_MUTEX_UNLOCK(mutex)
00168
00169 return refcount;
00170 }
00171
00172 protected:
00173 inline void allocate(size_t length);
00174 void deallocate();
00175
00176 private:
00177 MemoryBlock(const MemoryBlock<T_type>&)
00178 { }
00179
00180 void operator=(const MemoryBlock<T_type>&)
00181 { }
00182
00183 private:
00184 T_type * restrict data_;
00185 T_type * dataBlockAddress_;
00186
00187 #ifdef BZ_DEBUG_REFERENCE_ROLLOVER
00188 volatile unsigned char references_;
00189 #else
00190 volatile int references_;
00191 #endif
00192
00193 BZ_MUTEX_DECLARE(mutex)
00194 size_t length_;
00195 };
00196
00197 template<typename P_type>
00198 class UnownedMemoryBlock : public MemoryBlock<P_type> {
00199 public:
00200 UnownedMemoryBlock(size_t length, P_type* data)
00201 : MemoryBlock<P_type>(length,data)
00202 {
00203
00204
00205 MemoryBlock<P_type>::dataBlockAddress() = 0;
00206 }
00207
00208 virtual ~UnownedMemoryBlock()
00209 {
00210 }
00211 };
00212
00213 template<typename P_type>
00214 class NullMemoryBlock : public MemoryBlock<P_type> {
00215 public:
00216 NullMemoryBlock()
00217 {
00218
00219
00220 MemoryBlock<P_type>::addReference();
00221 }
00222
00223 virtual ~NullMemoryBlock()
00224 { }
00225 };
00226
00227 template<typename P_type>
00228 class MemoryBlockReference {
00229
00230 public:
00231 typedef P_type T_type;
00232
00233 protected:
00234 T_type * restrict data_;
00235
00236 private:
00237 MemoryBlock<T_type>* block_;
00238 static NullMemoryBlock<T_type> nullBlock_;
00239
00240 public:
00241
00242 MemoryBlockReference()
00243 {
00244 block_ = &nullBlock_;
00245 block_->addReference();
00246 data_ = 0;
00247 }
00248
00249 MemoryBlockReference(MemoryBlockReference<T_type>& ref, size_t offset=0)
00250 {
00251 block_ = ref.block_;
00252 block_->addReference();
00253 data_ = ref.data_ + offset;
00254 }
00255
00256 MemoryBlockReference(size_t length, T_type* data,
00257 preexistingMemoryPolicy deletionPolicy)
00258 {
00259
00260
00261
00262
00263
00264
00265
00266 if ((deletionPolicy == neverDeleteData)
00267 || (deletionPolicy == duplicateData))
00268 block_ = new UnownedMemoryBlock<T_type>(length, data);
00269 else if (deletionPolicy == deleteDataWhenDone)
00270 block_ = new MemoryBlock<T_type>(length, data);
00271 block_->addReference();
00272
00273 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00274 cout << "MemoryBlockReference: created MemoryBlock at "
00275 << ((void*)block_) << endl;
00276 #endif
00277
00278 data_ = data;
00279 }
00280
00281 explicit MemoryBlockReference(size_t items)
00282 {
00283 block_ = new MemoryBlock<T_type>(items);
00284 block_->addReference();
00285 data_ = block_->data();
00286
00287 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00288 cout << "MemoryBlockReference: created MemoryBlock at "
00289 << ((void*)block_) << endl;
00290 #endif
00291
00292 }
00293
00294 void blockRemoveReference()
00295 {
00296 int refcount = block_->removeReference();
00297 if ((refcount == 0) && (block_ != &nullBlock_))
00298 {
00299 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00300 cout << "MemoryBlock: no more refs, delete MemoryBlock object at "
00301 << ((void*)block_) << endl;
00302 #endif
00303
00304 delete block_;
00305 }
00306 }
00307
00308 ~MemoryBlockReference()
00309 {
00310 blockRemoveReference();
00311 }
00312
00313 int numReferences() const
00314 {
00315 return block_->references();
00316 }
00317
00318
00319 protected:
00320
00321 void changeToNullBlock()
00322 {
00323 blockRemoveReference();
00324 block_ = &nullBlock_;
00325 block_->addReference();
00326 data_ = 0;
00327 }
00328
00329 void changeBlock(MemoryBlockReference<T_type>& ref, size_t offset=0)
00330 {
00331 blockRemoveReference();
00332 block_ = ref.block_;
00333 block_->addReference();
00334 data_ = ref.data_ + offset;
00335 }
00336
00337 void newBlock(size_t items)
00338 {
00339 blockRemoveReference();
00340 block_ = new MemoryBlock<T_type>(items);
00341 block_->addReference();
00342 data_ = block_->data();
00343
00344 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
00345 cout << "MemoryBlockReference: created MemoryBlock at "
00346 << ((void*)block_) << endl;
00347 #endif
00348 }
00349
00350 private:
00351 void operator=(const MemoryBlockReference<T_type>&)
00352 { }
00353 };
00354
00355
00356 BZ_NAMESPACE_END
00357
00358 #include <blitz/memblock.cc>
00359
00360 #endif // BZ_MEMBLOCK_H