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