Eneboo - Documentación para desarrolladores
|
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_