Eneboo - Documentación para desarrolladores
src/hoard/src/heaplayers/obstackheap.h
Ir a la documentación de este archivo.
00001 /* -*- C++ -*- */
00002 
00003 /*
00004 
00005   Heap Layers: An Extensible Memory Allocation Infrastructure
00006   
00007   Copyright (C) 2000-2003 by Emery Berger
00008   http://www.cs.umass.edu/~emery
00009   emery@cs.umass.edu
00010   
00011   This program is free software; you can redistribute it and/or modify
00012   it under the terms of the GNU General Public License as published by
00013   the Free Software Foundation; either version 2 of the License, or
00014   (at your option) any later version.
00015   
00016   This program 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 General Public License for more details.
00020   
00021   You should have received a copy of the GNU General Public License
00022   along with this program; if not, write to the Free Software
00023   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025 */
00026 
00027 // An "Obstack".
00028 
00029 #ifndef _HLOBSTACK_H_
00030 #define _HLOBSTACK_H_
00031 
00032 #ifdef __cplusplus
00033 
00034 #include <assert.h>
00035 #include <new>
00036 
00037 namespace HL {
00038 
00039 template <int ChunkSize, class SuperHeap>
00040 class ObstackHeap : public SuperHeap {
00041 public:
00042 
00043   ObstackHeap (void)
00044   {
00045     // Get one chunk and set the current position marker.
00046     currentChunk = makeChunk (NULL, ChunkSize);
00047     currentBase = nextPos = (char *) (currentChunk + 1);
00048     assert (isValid());
00049   }
00050 
00051   ~ObstackHeap (void) {
00052     // Free every chunk.
00053     assert (isValid());
00054     ChunkHeader * ch = currentChunk;
00055     while (ch != NULL) {
00056       ChunkHeader * pch = ch->getPrevChunk();
00057       // cout << "Freeing chunk " << ch << endl;
00058       SuperHeap::free (ch);
00059       ch = pch;
00060     }
00061   }
00062 
00063   // "Grow" the current object.
00064   // Returns a point in the object just before the current "grow".
00065   inline void * grow (size_t sz) {
00066     // If we've grown beyond the confines of this chunk,
00067     // get a new one.
00068     assert (isValid());
00069     if ((int) ((char *) currentChunk->getLimit() - (char *) nextPos) < sz) {
00070       ChunkHeader * newCurrent = copyToNew(sz);
00071       if (newCurrent == NULL)
00072         return NULL;
00073 #if 0
00074       // Now delete the previous chunk if this was the only object in it.
00075       if (deleteChunk != NULL) {
00076         SuperHeap::free (deleteChunk);
00077       }
00078 #endif
00079       assert (isValid());
00080     }
00081     assert (((int) ((char *) currentChunk->getLimit() - (char *) nextPos) >= sz));
00082     assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
00083     // Bump the pointer for the next object.
00084     void * prevNextPos = nextPos;
00085     nextPos += sz;
00086     assert (isValid());
00087     return prevNextPos;
00088   }
00089 
00090 
00091   inline void * malloc (size_t sz) {
00092     assert (isValid());
00093     if (currentChunk == NULL) {
00094       return NULL;
00095     }
00096     //sz = align(sz > 0 ? sz : 1);
00097     // If this object can't fit in the current chunk,
00098     // get another one.
00099     if ((int) ((char *) currentChunk->getLimit() - (char *) nextPos) < sz) {
00100       // Allocate a chunk that's large enough to hold the requested size.
00101       currentChunk = makeChunk (currentChunk, sz);
00102       if (currentChunk == NULL) {
00103         return NULL;
00104       }
00105       currentBase = nextPos = (char *) (currentChunk + 1);
00106       assert (isValid());
00107     }
00108     assert (((int) ((char *) currentChunk->getLimit() - (char *) nextPos) >= sz));
00109     assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
00110     // Bump the pointers forward.
00111     currentBase = nextPos;
00112     nextPos += sz;
00113     void * ptr = currentBase;
00114     finalize();
00115     assert (isValid());
00116     return (void *) ptr;
00117   }
00118 
00119   // Free everything allocated "after" ptr.
00120   // NB: Freeing NULL safely empties the entire obstack.
00121   inline void free (void * ptr) {
00122     assert (isValid());
00123     // Free every chunk until we find the one that this pointer is in.
00124     // Then reset the current position to ptr.
00125     while (currentChunk != NULL &&
00126            (((char *) currentChunk > (char *) ptr) ||
00127             ((char *) currentChunk->getLimit() < (char *) ptr))) {
00128       ChunkHeader * pch = currentChunk;
00129       currentChunk = currentChunk->getPrevChunk();
00130       SuperHeap::free (pch);
00131     }
00132     if (currentChunk != NULL) {
00133       currentBase = nextPos = (char *) ptr;
00134       assert (isValid());
00135     } else {
00136       if (ptr != NULL) {
00137         // Something bad has happened -- we tried to free an item that
00138         // wasn't in any chunk.
00139         abort();
00140       } else {
00141         // Get one chunk.
00142         currentChunk = makeChunk (NULL, ChunkSize);
00143         currentBase = nextPos = (char *) (currentChunk + 1);
00144         assert (isValid());
00145       }
00146     }
00147   }
00148 
00149 
00150   inline void * getObjectBase (void) {
00151     assert (isValid());
00152     return currentBase;
00153   }
00154 
00155 
00156   inline void finalize (void) {
00157     assert (isValid());
00158     nextPos = (char *) align((int) nextPos);
00159     currentBase = nextPos;
00160     assert (isValid());
00161   }
00162 
00163 
00164 private:
00165 
00166 
00167   inline int objectSize (void) {
00168     int diff = (int) (nextPos - currentBase);
00169     assert (diff >= 0);
00170     return diff;
00171   }
00172 
00173 
00174   int isValid (void) {
00175     // Verify class invariants.
00176 #ifndef NDEBUG
00177     bool c1 = (currentBase <= nextPos);
00178     assert (c1);
00179     bool c2 = (nextPos <= currentChunk->getLimit());
00180     assert (c2);
00181     bool c3 = ((char *) currentChunk <= currentChunk->getLimit());
00182     assert (c3);
00183     bool c4 = ((char *) currentChunk <= currentBase);
00184     assert (c4);
00185     bool c5 = (currentChunk != currentChunk->getPrevChunk());
00186     assert (c5);
00187     bool c6 = (objectSize() >= 0);
00188     assert (c6);
00189     return (c1 && c2 && c3 && c4 && c5 && c6);
00190 #else
00191     return 1;
00192 #endif
00193   }
00194 
00195   // The header for every chunk.
00196   class ChunkHeader {
00197   public:
00198     inline ChunkHeader (ChunkHeader * prev, size_t sz)
00199       : _pastEnd ((char *) (this + 1) + sz),
00200         _prevChunk (prev)
00201     {}
00202 
00203     // Return the end of the current chunk.
00204     inline char * getLimit (void) { return _pastEnd; }
00205 
00206     // Return the previous chunk.
00207     inline ChunkHeader * getPrevChunk (void) { return _prevChunk; }
00208 
00209   private:
00210     // Just past the end of this chunk.
00211     char * _pastEnd;
00212 
00213     // Address of prior chunk.
00214     ChunkHeader * _prevChunk;
00215   };
00216 
00217 
00218   inline static size_t align (int sz) {
00219     return (sz + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
00220   }
00221 
00222   // Make a new chunk of at least sz bytes.
00223   inline ChunkHeader * makeChunk (ChunkHeader * ch, size_t sz) {
00224     // Round up the allocation size to at least one chunk.
00225     size_t allocSize
00226       = align((sz > ChunkSize - sizeof(ChunkHeader)) ? sz : ChunkSize - sizeof(ChunkHeader));
00227     // Make a new chunk.
00228     void * ptr = SuperHeap::malloc (sizeof(ChunkHeader) + allocSize);
00229     if (ptr == NULL) {
00230       return NULL;
00231     }
00232     ChunkHeader * newChunk 
00233       = new (ptr) ChunkHeader (ch, allocSize);
00234     return newChunk;
00235   }
00236 
00237 
00238   // Copy the current object to a new chunk.
00239   // sz = the minimum amount of extra space we need.
00240   inline ChunkHeader * copyToNew (size_t sz) {
00241     size_t obj_size = objectSize();
00242     size_t new_size = obj_size + sz + (obj_size >> 3) + 100;
00243     //size_t new_size = 2 * (obj_size + sz);
00244     ChunkHeader * newChunk;
00245 #if 0
00246     // This variable will hold the chunk to be deleted (if any).
00247     ChunkHeader * deleteChunk = NULL;
00248     // If this object was the only one in the chunk,
00249     // link back past this chunk.
00250     if (currentBase == (char *) (currentChunk + 1)) {
00251       newChunk = makeChunk (currentChunk->getPrevChunk(), new_size);
00252       deleteChunk = currentChunk;
00253     } else {
00254       newChunk = makeChunk (currentChunk, new_size);
00255     }
00256 #else
00257     newChunk = makeChunk (currentChunk, new_size);
00258 #endif
00259     if (newChunk == NULL) {
00260       currentChunk = NULL;
00261       return NULL;
00262     }
00263     // Copy the current object to the new chunk.
00264     memcpy ((char *) (newChunk + 1), currentBase, obj_size);
00265     currentChunk = newChunk;
00266     currentBase = (char *) (currentChunk + 1);
00267     nextPos = currentBase + obj_size;
00268 #if 0
00269     if (deleteChunk != NULL) {
00270       SuperHeap::free (deleteChunk);
00271     }
00272 #endif
00273     return currentChunk;
00274   }
00275 
00276 
00277   // Current position in the current chunk.
00278   char * currentBase;
00279 
00280   // Where to add the next character to the current object.
00281   char * nextPos;
00282 
00283   // My current chunk.
00284   ChunkHeader * currentChunk;
00285 
00286 };
00287 
00288 };
00289 
00290 #endif // __cplusplus
00291 
00292 #endif // _HLOBSTACK_H_
 Todo Clases Namespaces Archivos Funciones Variables 'typedefs' Enumeraciones Valores de enumeraciones Propiedades Amigas 'defines'