blitz Version 0.9
|
00001 // -*- C++ -*- 00002 /*************************************************************************** 00003 * blitz/memblock.h MemoryBlock<T> and MemoryBlockReference<T> 00004 * 00005 * $Id: memblock.h,v 1.18 2005/10/11 21:54:57 julianc Exp $ 00006 * 00007 * Copyright (C) 1997-1999 Todd Veldhuizen <tveldhui@oonumerics.org> 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU General Public License 00011 * as published by the Free Software Foundation; either version 2 00012 * of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * Suggestions: blitz-dev@oonumerics.org 00020 * Bugs: blitz-bugs@oonumerics.org 00021 * 00022 * For more information, please see the Blitz++ Home Page: 00023 * http://oonumerics.org/blitz/ 00024 * 00025 ***************************************************************************/ 00026 00027 #ifndef BZ_MEMBLOCK_H 00028 #define BZ_MEMBLOCK_H 00029 00030 #include <blitz/blitz.h> 00031 00032 #include <stddef.h> // ptrdiff_t 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 // Forward declaration of MemoryBlockReference 00047 template<typename T_type> class MemoryBlockReference; 00048 00049 // Class MemoryBlock provides a reference-counted block of memory. This block 00050 // may be referred to by multiple vector, matrix and array objects. The memory 00051 // is automatically deallocated when the last referring object is destructed. 00052 // MemoryBlock may be subclassed to provide special allocators. 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: // Disabled member functions 00177 MemoryBlock(const MemoryBlock<T_type>&) 00178 { } 00179 00180 void operator=(const MemoryBlock<T_type>&) 00181 { } 00182 00183 private: // Data members 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 // This ensures that MemoryBlock destructor will not 00204 // attempt to delete data 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 // This ensures that the delete operator will not be invoked 00219 // on an instance of NullMemoryBlock in removeReference(). 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 // Create a memory block using already allocated memory. 00260 00261 // Note: if the deletionPolicy is duplicateData, this must 00262 // be handled by the leaf class. In MemoryBlockReference, 00263 // this is treated as neverDeleteData; the leaf class (e.g. Array) 00264 // must duplicate the data. 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