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.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

Generated on Mon Dec 3 09:21:54 2007 for blitz by  doxygen 1.5.1