blitz Version 0.10
|
00001 // -*- C++ -*- 00002 /*************************************************************************** 00003 * blitz/memblock.h MemoryBlock<T> and MemoryBlockReference<T> 00004 * 00005 * $Id: memblock.h,v 1.22 2011/03/25 22:41:16 julianc Exp $ 00006 * 00007 * Copyright (C) 1997-2011 Todd Veldhuizen <tveldhui@acm.org> 00008 * 00009 * This file is a part of Blitz. 00010 * 00011 * Blitz is free software: you can redistribute it and/or modify 00012 * it under the terms of the GNU Lesser General Public License 00013 * as published by the Free Software Foundation, either version 3 00014 * of the License, or (at your option) any later version. 00015 * 00016 * Blitz is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with Blitz. If not, see <http://www.gnu.org/licenses/>. 00023 * 00024 * Suggestions: blitz-devel@lists.sourceforge.net 00025 * Bugs: blitz-support@lists.sourceforge.net 00026 * 00027 * For more information, please see the Blitz++ Home Page: 00028 * https://sourceforge.net/projects/blitz/ 00029 * 00030 ***************************************************************************/ 00031 00032 #ifndef BZ_MEMBLOCK_H 00033 #define BZ_MEMBLOCK_H 00034 00035 #include <blitz/blitz.h> 00036 00037 #include <stddef.h> // diffType 00038 00039 BZ_NAMESPACE(blitz) 00040 00041 enum preexistingMemoryPolicy { 00042 duplicateData, 00043 deleteDataWhenDone, 00044 neverDeleteData 00045 }; 00046 00047 // Forward declaration of MemoryBlockReference 00048 template<typename T_type> class MemoryBlockReference; 00049 00050 // Class MemoryBlock provides a reference-counted block of memory. This block 00051 // may be referred to by multiple vector, matrix and array objects. The memory 00052 // is automatically deallocated when the last referring object is destructed. 00053 // MemoryBlock may be subclassed to provide special allocators. 00054 template<typename P_type> 00055 class MemoryBlock { 00056 00057 friend class MemoryBlockReference<P_type>; 00058 00059 public: 00060 typedef P_type T_type; 00061 00062 protected: 00063 MemoryBlock() 00064 { 00065 length_ = 0; 00066 data_ = 0; 00067 dataBlockAddress_ = 0; 00068 references_ = 0; 00069 00070 BZ_MUTEX_INIT(mutex) 00071 mutexLocking_ = true; 00072 } 00073 00074 explicit MemoryBlock(sizeType items) 00075 { 00076 length_ = items; 00077 allocate(length_); 00078 00079 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00080 cout << "MemoryBlock: allocated " << setw(8) << length_ 00081 << " at " << ((void *)dataBlockAddress_) << endl; 00082 #endif 00083 00084 BZASSERT(dataBlockAddress_ != 0); 00085 00086 references_ = 0; 00087 00088 BZ_MUTEX_INIT(mutex) 00089 mutexLocking_ = true; 00090 } 00091 00092 MemoryBlock(sizeType length, T_type* data) 00093 { 00094 length_ = length; 00095 data_ = data; 00096 dataBlockAddress_ = data; 00097 references_ = 0; 00098 BZ_MUTEX_INIT(mutex) 00099 mutexLocking_ = true; 00100 } 00101 00102 virtual ~MemoryBlock() 00103 { 00104 if (dataBlockAddress_) 00105 { 00106 00107 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00108 cout << "MemoryBlock: freed " << setw(8) << length_ 00109 << " at " << ((void *)dataBlockAddress_) << endl; 00110 #endif 00111 00112 deallocate(); 00113 } 00114 00115 BZ_MUTEX_DESTROY(mutex) 00116 } 00117 00118 // set mutex locking policy and return true if successful 00119 bool doLock(bool lockingPolicy) 00120 { 00121 if (mutexLocking_ == lockingPolicy) { // already set 00122 return true; 00123 } 00124 else if (references_ <= 1) { // no multiple references, safe to change 00125 mutexLocking_ = lockingPolicy; 00126 return true; 00127 } 00128 return false; // unsafe to change 00129 } 00130 00131 void addReference() 00132 { 00133 if (mutexLocking_) { 00134 BZ_MUTEX_LOCK(mutex) 00135 } 00136 ++references_; 00137 00138 #ifdef BZ_DEBUG_LOG_REFERENCES 00139 cout << "MemoryBlock: reffed " << setw(8) << length_ 00140 << " at " << ((void *)dataBlockAddress_) << " (r=" 00141 << (int)references_ << ")" << endl; 00142 #endif 00143 if (mutexLocking_) { 00144 BZ_MUTEX_UNLOCK(mutex) 00145 } 00146 } 00147 00148 T_type* restrict data() 00149 { 00150 return data_; 00151 } 00152 00153 const T_type* restrict data() const 00154 { 00155 return data_; 00156 } 00157 00158 T_type*& dataBlockAddress() 00159 { 00160 return dataBlockAddress_; 00161 } 00162 00163 sizeType length() const 00164 { 00165 return length_; 00166 } 00167 00168 int removeReference() 00169 { 00170 00171 if (mutexLocking_) { 00172 BZ_MUTEX_LOCK(mutex) 00173 } 00174 int refcount = --references_; 00175 00176 #ifdef BZ_DEBUG_LOG_REFERENCES 00177 cout << "MemoryBlock: dereffed " << setw(8) << length_ 00178 << " at " << ((void *)dataBlockAddress_) << " (r=" << (int)references_ 00179 << ")" << endl; 00180 #endif 00181 if (mutexLocking_) { 00182 BZ_MUTEX_UNLOCK(mutex) 00183 } 00184 return refcount; 00185 } 00186 00187 int references() const 00188 { 00189 if (mutexLocking_) { 00190 BZ_MUTEX_LOCK(mutex) 00191 } 00192 int refcount = references_; 00193 if (mutexLocking_) { 00194 BZ_MUTEX_UNLOCK(mutex) 00195 } 00196 00197 return refcount; 00198 } 00199 00200 protected: 00201 inline void allocate(sizeType length); 00202 void deallocate(); 00203 00204 private: // Disabled member functions 00205 MemoryBlock(const MemoryBlock<T_type>&) 00206 { } 00207 00208 void operator=(const MemoryBlock<T_type>&) 00209 { } 00210 00211 private: // Data members 00212 T_type * restrict data_; 00213 T_type * dataBlockAddress_; 00214 00215 #ifdef BZ_DEBUG_REFERENCE_ROLLOVER 00216 volatile unsigned char references_; 00217 #else 00218 volatile int references_; 00219 #endif 00220 00221 BZ_MUTEX_DECLARE(mutex) 00222 bool mutexLocking_; 00223 sizeType length_; 00224 }; 00225 00226 template<typename P_type> 00227 class MemoryBlockReference { 00228 00229 public: 00230 typedef P_type T_type; 00231 00232 protected: 00233 T_type * restrict data_; 00234 00235 private: 00236 MemoryBlock<T_type>* block_; 00237 00238 public: 00239 00240 MemoryBlockReference() 00241 { 00242 block_ = 0; 00243 addReference(); 00244 data_ = 0; 00245 } 00246 00247 MemoryBlockReference(MemoryBlockReference<T_type>& ref, sizeType offset=0) 00248 { 00249 block_ = ref.block_; 00250 addReference(); 00251 data_ = ref.data_ + offset; 00252 } 00253 00254 MemoryBlockReference(sizeType length, T_type* data, 00255 preexistingMemoryPolicy deletionPolicy) 00256 { 00257 // Create a memory block using already allocated memory. 00258 00259 // Note: if the deletionPolicy is duplicateData, this must 00260 // be handled by the leaf class. In MemoryBlockReference, 00261 // this is treated as neverDeleteData; the leaf class (e.g. Array) 00262 // must duplicate the data. 00263 00264 if ((deletionPolicy == neverDeleteData) 00265 || (deletionPolicy == duplicateData)) { 00266 // in this case, we do not need a MemoryBlock to ref-count the data 00267 block_ = 0; 00268 } 00269 else if (deletionPolicy == deleteDataWhenDone) { 00270 block_ = new MemoryBlock<T_type>(length, data); 00271 00272 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00273 cout << "MemoryBlockReference: created MemoryBlock at " 00274 << ((void*)block_) << endl; 00275 #endif 00276 } 00277 addReference(); 00278 00279 data_ = data; 00280 } 00281 00282 explicit MemoryBlockReference(sizeType items) 00283 { 00284 block_ = new MemoryBlock<T_type>(items); 00285 addReference(); 00286 data_ = block_->data(); 00287 00288 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00289 cout << "MemoryBlockReference: created MemoryBlock at " 00290 << ((void*)block_) << endl; 00291 #endif 00292 00293 } 00294 00295 ~MemoryBlockReference() 00296 { 00297 blockRemoveReference(); 00298 } 00299 00300 protected: 00301 00302 int numReferences() const 00303 { 00304 if (block_) 00305 return block_->references(); 00306 #ifdef BZ_DEBUG_LOG_REFERENCES 00307 cout << "Invalid reference count for data at "<< data_ << endl; 00308 #endif 00309 return -1; 00310 } 00311 00312 bool lockReferenceCount(bool lockingPolicy) const 00313 { 00314 if (block_) 00315 return block_->doLock(lockingPolicy); 00316 // if we have no block, consider request successful 00317 #ifdef BZ_DEBUG_LOG_REFERENCES 00318 cout << "No reference count locking for data at "<< data_ << endl; 00319 #endif 00320 return true; 00321 } 00322 00323 void changeToNullBlock() 00324 { 00325 blockRemoveReference(); 00326 block_ = 0; 00327 addReference(); 00328 data_ = 0; 00329 } 00330 00331 void changeBlock(MemoryBlockReference<T_type>& ref, sizeType offset=0) 00332 { 00333 blockRemoveReference(); 00334 block_ = ref.block_; 00335 addReference(); 00336 data_ = ref.data_ + offset; 00337 } 00338 00339 void newBlock(sizeType items) 00340 { 00341 blockRemoveReference(); 00342 block_ = new MemoryBlock<T_type>(items); 00343 addReference(); 00344 data_ = block_->data(); 00345 00346 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00347 cout << "MemoryBlockReference: created MemoryBlock at " 00348 << ((void*)block_) << endl; 00349 #endif 00350 } 00351 00352 private: 00353 void blockRemoveReference() 00354 { 00355 int refcount = removeReference(); 00356 if (refcount == 0) 00357 { 00358 #ifdef BZ_DEBUG_LOG_ALLOCATIONS 00359 cout << "MemoryBlock: no more refs, delete MemoryBlock object at " 00360 << ((void*)block_) << endl; 00361 #endif 00362 00363 delete block_; 00364 } 00365 } 00366 00367 void addReference() const 00368 { 00369 if (block_) { 00370 block_->addReference(); 00371 } 00372 else { 00373 #ifdef BZ_DEBUG_LOG_REFERENCES 00374 cout << "Skipping reference count for data at "<< data_ << endl; 00375 #endif 00376 } 00377 }; 00378 00379 int removeReference() const 00380 { 00381 if (block_) 00382 return block_->removeReference(); 00383 #ifdef BZ_DEBUG_LOG_REFERENCES 00384 cout << "Skipping reference count for data at "<< data_ << endl; 00385 #endif 00386 return -1; 00387 }; 00388 00389 void operator=(const MemoryBlockReference<T_type>&) 00390 { } 00391 }; 00392 00393 00394 BZ_NAMESPACE_END 00395 00396 #include <blitz/memblock.cc> 00397 00398 #endif // BZ_MEMBLOCK_H