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 // 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_