blitz Version 0.10
blitz/memblock.h
Go to the documentation of this file.
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
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines