00001 /*
00002 This product contains certain software code or other information
00003 ("AT&T Software") proprietary to AT&T Corp. ("AT&T"). The AT&T
00004 Software is provided to you "AS IS". YOU ASSUME TOTAL RESPONSIBILITY
00005 AND RISK FOR USE OF THE AT&T SOFTWARE. AT&T DOES NOT MAKE, AND
00006 EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
00007 WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
00008 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
00009 TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
00010 WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
00011 PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
00012 WILL MEET YOUR REQUIREMENTS.
00013
00014 Unless you accept a license to use the AT&T Software, you shall not
00015 reverse compile, disassemble or otherwise reverse engineer this
00016 product to ascertain the source code for any AT&T Software.
00017
00018 (c) AT&T Corp. All rights reserved. AT&T is a registered trademark of AT&T Corp.
00019
00020 ***********************************************************************
00021
00022 History:
00023
00024 24/11/99 - initial release by Hartmut Liefke, liefke@seas.upenn.edu
00025 Dan Suciu, suciu@research.att.com
00026 */
00027
00028 //**************************************************************************
00029 //**************************************************************************
00030
00031 // This module contains the memory streamer class
00032 // The memory streamer represents a sequence of memory blocks
00033 // that grows over time. The blocks at the beginning are small, while
00034 // later, larger blocks are allocated.
00035 // The memory streamer is the core of the container implementation
00036
00037 #ifndef STREAMMEM_HPP
00038 #define STREAMMEM_HPP
00039
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043
00044 #include "Types.hpp"
00045
00046 #include "MemMan.hpp" // The global memory manager
00047
00048 //**********************************************************************************
00049
00050 // For the MemStreamer, the block size increase slowly in 16 steps.
00051 // 'blocksizeidxs' contains the block size indices for each step
00052
00053 #define BLOCKSIZE_IDXNUM 16
00054 extern unsigned char blocksizeidxs[];
00055
00056 class Output;
00057
00058 struct MemStreamBlock
00059 // Defines one single data block
00060 {
00061 MemStreamBlock *next; // The next data block of the same streamer
00062 unsigned long blocksize:28; // The size of this block
00063 unsigned long blocksizeidxidx:4;// The block size index (i.e. the index within blocksizeidxs)
00064 unsigned long cursize; // The current number of bytes in this block
00065
00066 // MemStreamBlock *myprev,*mynext; // Previous and next block
00067 // unsigned long idx;
00068
00069 char data[1]; // The first byte of the data
00070 // (The other data comes DIRECTLY afterwards)
00071 };
00072
00073 //extern MemStreamBlock *blocklist;
00074 // The list of all blocks
00075
00076 struct MemStreamMarker
00077 // Represents a marker in the memory stream
00078 // Markers are used so that everything appended to the Streamer
00079 // after the marker can be deleted
00080 // Several markers can exist in the Streamer and they are
00081 // in backwards references in a single-chained list.
00082 {
00083 MemStreamBlock *block; // The block of the previous marker,
00084 MemStreamMarker *pos; // The pointer to the previous marker
00085 // The pointers are NULL, if there is no previous marker
00086 };
00087
00088 class MemStreamer
00089 {
00090 MemStreamBlock *firstblock; // The first block of the streamer
00091 MemStreamBlock *curblock; // The current block, which is also the last block
00092 unsigned long overallsize:28; // The overall size of the memory streamer
00093 unsigned long curblocksizeidxidx:4;
00094 MemStreamMarker curmarker; // The position of the current marker is stored here
00095 // If there is no marker, then both pointers are NULL
00096
00097 void ReleaseBlock(MemStreamBlock *block)
00098 // Releases the block from the mem streamer
00099 // Typically, this is the last block in the chain - but it could
00100 // also be in the middle
00101 {
00102 /*
00103 if(block->myprev!=NULL)
00104 block->myprev->mynext=block->mynext;
00105 else
00106 blocklist=block->mynext;
00107 if(block->mynext!=NULL)
00108 block->mynext->myprev=block->myprev;
00109 */
00110 // memset(block->data,0xcd,block->cursize);
00111 FreeBlock((char *)block,blocksizeidxs[block->blocksizeidxidx]);
00112 }
00113
00114 MemStreamBlock *AllocateNewBlock()
00115 // Allocates a new block
00116 // The size is determined by the next index in blocksizeidxs
00117 {
00118 MemStreamBlock *newblock;
00119
00120 // Let's get the new block
00121 newblock=(MemStreamBlock *)AllocateBlock(blocksizeidxs[curblocksizeidxidx]);
00122
00123 // The usable data size is the block size - the size of the header
00124 newblock->blocksize=GetBlockSize(blocksizeidxs[curblocksizeidxidx])-(sizeof(MemStreamBlock)-1);
00125 newblock->blocksizeidxidx=curblocksizeidxidx;
00126
00127 // Do we still have more steps to go in the block size increase?
00128 // => Go to next step
00129 if(curblocksizeidxidx<BLOCKSIZE_IDXNUM-1)
00130 curblocksizeidxidx++;
00131
00132 newblock->next=NULL;
00133 newblock->cursize=0;
00134 /*
00135 // Let's insert the block at the end of the block-chain
00136 newblock->mynext=blocklist;
00137 if(blocklist!=NULL)
00138 blocklist->myprev=newblock;
00139 newblock->myprev=NULL;
00140 blocklist=newblock;
00141 */
00142 return newblock;
00143 }
00144
00145 public:
00146
00147 void Initialize(unsigned long firstblocksizeidx=0)
00148 // Initializes the memstreamer and sets the first block index step
00149 {
00150 if(firstblocksizeidx>=BLOCKSIZE_IDXNUM)
00151 firstblocksizeidx=BLOCKSIZE_IDXNUM-1;
00152
00153 curblocksizeidxidx=firstblocksizeidx;
00154 overallsize=0;
00155
00156 curmarker.block=NULL;
00157 curmarker.pos=NULL;
00158
00159 firstblock=curblock=NULL;
00160 }
00161
00162 MemStreamer(unsigned long firstblocksizeidx=0)
00163 {
00164 Initialize(firstblocksizeidx);
00165 }
00166
00167 ~MemStreamer()
00168 {
00169 ReleaseMemory(0);
00170 }
00171
00172 int GetSize() { return overallsize; }
00173
00174 MemStreamBlock *GetFirstBlock() { return firstblock; }
00175
00176 void WordAlign()
00177 // Allocated 1 to 3 bytes to align the current memory pointer
00178 // to an address divisible by 4.
00179 {
00180 if(curblock==NULL)
00181 return;
00182
00183 int addsize=3-((curblock->cursize+3)&3);
00184 if(addsize>0)
00185 {
00186 curblock->cursize+=addsize;
00187 overallsize+=addsize;
00188 }
00189 }
00190
00191 char *GetByteBlock(unsigned len)
00192 // The main function for allocated more memory of size 'len'.
00193 // The function checks the current block and if there is not enough space,
00194 // the function 'AllocateNewBlock' is called.
00195 {
00196 if(len+sizeof(MemStreamBlock)-1>LARGEBLOCK_SIZE) // Is the requested size larger than the biggest possible block?
00197 {
00198 char str[100];
00199 sprintf(str,"Could not allocate %lu bytes (largest possible block size=%lu bytes) !",
00200 sizeof(MemStreamBlock)-1+len,
00201 LARGEBLOCK_SIZE);
00202 Error(str);
00203 Exit();
00204 }
00205
00206 if(curblock==NULL)
00207 // We don't have a block yet ?
00208 firstblock=curblock=AllocateNewBlock();
00209
00210 if(curblock->blocksize-curblock->cursize>=len)
00211 // Enough space in current block?
00212 {
00213 char *ptr=curblock->data+curblock->cursize;
00214 curblock->cursize+=len;
00215 overallsize+=len;
00216 return ptr;
00217 }
00218 else // We add a new block at the end
00219 {
00220 do
00221 {
00222 curblock->next=AllocateNewBlock();
00223 curblock=curblock->next;
00224 }
00225 while(curblock->blocksize<len); // If we don't have enough space,
00226 // we simply create a bigger one!
00227
00228 curblock->cursize=len;
00229 overallsize+=len;
00230
00231 return curblock->data;
00232 }
00233 }
00234
00235 void ReleaseByteBlock(unsigned len)
00236 // Removes 'len' bytes from the current block
00237 {
00238 // If the current block is smaller than the data to be removed,
00239 // then there is something really wrong!
00240 if(curblock->cursize<len)
00241 {
00242 Error("Fatal error in ReleaseBlock !\n");
00243 Exit();
00244 }
00245
00246 curblock->cursize-=len;
00247 overallsize-=len;
00248
00249 #ifdef RELEASEMEM_SAFE
00250 memset(curblock->data+curblock->cursize,0xcd,len);
00251 #endif
00252 }
00253
00254 //******************************************************************************
00255
00256 void StoreData(char *data,unsigned len)
00257 // Stores the a sequence of bytes in the memory streamer
00258 // The bytes can be distributed over many blocks
00259 {
00260 if(curblock==NULL)
00261 // We don't have a block yet ?
00262 firstblock=curblock=AllocateNewBlock();
00263
00264 while(len>curblock->blocksize-curblock->cursize)
00265 // There is not enough space in the current block ?
00266 // ==> We fill the current block as much as possible
00267 {
00268 mymemcpy(curblock->data+curblock->cursize,data,
00269 curblock->blocksize-curblock->cursize);
00270
00271 data +=curblock->blocksize-curblock->cursize;
00272 overallsize +=curblock->blocksize-curblock->cursize;
00273 len -=curblock->blocksize-curblock->cursize;
00274 curblock->cursize=curblock->blocksize;
00275
00276 curblock->next=AllocateNewBlock();
00277
00278 curblock=curblock->next;
00279 }
00280 mymemcpy(curblock->data+curblock->cursize,data,len);
00281 curblock->cursize+=len;
00282 overallsize+=len;
00283 }
00284
00285 //******************************************************************************
00286
00287 // The following auxiliary functions allow the easy storage of simple data values
00288
00289 void StoreChar(unsigned char c)
00290 // Stores one single character
00291 {
00292 if(curblock==NULL)
00293 // We don't have a block yet ?
00294 firstblock=curblock=AllocateNewBlock();
00295 else
00296 {
00297 if(curblock->blocksize-curblock->cursize==0)
00298 // The block is completely full? ==> Get a new one
00299 {
00300 curblock->next=AllocateNewBlock();
00301 curblock=curblock->next;
00302 }
00303 }
00304 curblock->data[curblock->cursize]=c;
00305 curblock->cursize++;
00306 overallsize++;
00307 }
00308
00309 void StoreCompressedUInt(unsigned long val,unsigned char offs=0)
00310 // Stores a compressed unsigned integer
00311 // The values below the offset threshold are reserved for other use.
00312 // Hence, the offset is basically added to 'val'.
00313 // The offset *must* be smaller than 128
00314 {
00315 if(val<128-(unsigned)offs)
00316 StoreChar((unsigned char)val+offs);
00317 else
00318 {
00319 if(val<16384)
00320 {
00321 StoreChar((unsigned char)(val>>8)+128);
00322 StoreChar((unsigned char)val);
00323 }
00324 else
00325 {
00326 StoreChar((unsigned char)(val>>24)+192);
00327 StoreChar((unsigned char)(val>>16));
00328 StoreChar((unsigned char)(val>>8));
00329 StoreChar((unsigned char)(val));
00330 }
00331 }
00332 }
00333
00334 void StoreCompressedSInt(char isneg,unsigned long val)
00335 // Stores a signed integer in compressed format
00336 // The sign is in 'isneg' and 'val' is the basis
00337 {
00338 if(val<64)
00339 StoreChar((unsigned char)val+(isneg ? 64 : 0));
00340 else
00341 {
00342 if(val<8192)
00343 {
00344 StoreChar((unsigned char)(val>>8)+(isneg ? (128+32) : 128));
00345 StoreChar((unsigned char)val);
00346 }
00347 else
00348 {
00349 StoreChar((unsigned char)(val>>24)+(isneg ? (192+32) : 192));
00350 StoreChar((unsigned char)(val>>16));
00351 StoreChar((unsigned char)(val>>8));
00352 StoreChar((unsigned char)val);
00353 }
00354 }
00355 }
00356
00357 void StoreCompressedSInt(long val)
00358 // Stores a signed integer in compressed format
00359 {
00360 if(val&0x80000000L)
00361 StoreCompressedSInt(1,-(long)val);
00362 else
00363 StoreCompressedSInt(0,val);
00364 }
00365
00366 void StoreUInt32(unsigned long val)
00367 // Stores a unsigned integer in compressed format
00368 {
00369 StoreCompressedUInt(val);
00370 }
00371
00372 void StoreSInt32(char isneg,unsigned long val)
00373 // Stores a signed integer in compressed format
00374 {
00375 StoreCompressedSInt(isneg,val);
00376 }
00377
00378 //**********************************************************************************
00379 //**********************************************************************************
00380
00381 void StartNewMemBlock()
00382 // Creates a new marker on the memory streamer
00383 {
00384 MemStreamMarker *newmarker=(MemStreamMarker *)GetByteBlock(sizeof(MemStreamMarker));
00385
00386 *newmarker=curmarker; // We copy previous marker
00387
00388 // We save the new marker position
00389 curmarker.block=curblock;
00390 curmarker.pos=newmarker;
00391 }
00392
00393 void RemoveLastMemBlock()
00394 // Removes a the data up to the last memory marker
00395 {
00396 MemStreamBlock *block,*nextblock;
00397 int newsize;
00398
00399 // We remove all blocks after the block of the last marker
00400
00401 block=curmarker.block->next;
00402
00403 while(block!=NULL)
00404 {
00405 overallsize-=block->cursize;
00406 nextblock=block->next;
00407 ReleaseBlock(block);
00408 block=nextblock;
00409 }
00410 curmarker.block->next=NULL;
00411
00412 // We save block pointer -> This block will be truncated to size 'newsize'
00413 block=curblock=curmarker.block;
00414
00415 // The remaining size
00416 newsize=(char *)curmarker.pos-block->data;
00417
00418 // We set the marker
00419 curmarker=*(curmarker.pos);
00420
00421 #ifdef RELEASEMEM_SAFE
00422 // We overwrite the empty space ==> Just for protection
00423 // We can take this out later
00424 memset(block->data+newsize,0xcd,block->cursize-newsize);
00425 #endif
00426
00427 overallsize-=(block->cursize-newsize);
00428 block->cursize=newsize;
00429
00430 if(block->blocksizeidxidx<BLOCKSIZE_IDXNUM-1)
00431 // Not the largest block size?
00432 curblocksizeidxidx=block->blocksizeidxidx+1;
00433 else
00434 curblocksizeidxidx=block->blocksizeidxidx;
00435 }
00436
00437 void ReleaseMemory(unsigned long firstblocksizeidx)
00438 // Releases the entire memory of the memstreamer
00439 {
00440 MemStreamBlock *block=firstblock,
00441 *nextblock;
00442 while(block!=NULL)
00443 {
00444 nextblock=block->next;
00445 ReleaseBlock(block);
00446 block=nextblock;
00447 }
00448 Initialize(firstblocksizeidx);
00449 }
00450
00451 void *operator new(size_t size, MemStreamer *mem) { return mem->GetByteBlock(size); }
00452 void operator delete(void *ptr) {}
00453 };
00454
00455 //*********************************************************************
00456 //*********************************************************************
00457
00458 // For the decompressor, we implement an additional memory management
00459
00460 /*
00461 #ifdef XDEMILL
00462
00463 extern MemStreamer blockmem;
00464
00465 #define MEMBLOCK_THRESHOLD 8000
00466
00467 extern unsigned char *memoryalloc_buf;
00468 extern unsigned char *memoryalloc_curptr;
00469 extern unsigned long memoryalloc_bufsize;
00470
00471 inline void SetMemoryAllocationSize(unsigned long allocsize)
00472 {
00473 if(memoryalloc_bufsize<allocsize)
00474 {
00475 if(memoryalloc_buf!=NULL)
00476 free(memoryalloc_buf);
00477
00478 memoryalloc_buf=(unsigned char *)malloc(allocsize);
00479 if(memoryalloc_buf==NULL)
00480 ExitNoMem();
00481
00482 memoryalloc_curptr=memoryalloc_buf;
00483
00484 memoryalloc_bufsize=allocsize;
00485 }
00486 else
00487 memoryalloc_curptr=memoryalloc_buf;
00488
00489 }
00490
00491 inline void WordAlignMemBlock()
00492 {
00493 memoryalloc_curptr=
00494 (unsigned char *)
00495 (((unsigned long)memoryalloc_curptr+3)&0xFFFFFFFCL);
00496 }
00497
00498 inline unsigned char *AllocateMemBlock(unsigned long size)
00499 {
00500 memoryalloc_curptr+=size;
00501 if(memoryalloc_curptr>memoryalloc_buf+memoryalloc_bufsize)
00502 {
00503 Error("Fatal Error!");
00504 Exit();
00505 }
00506 return memoryalloc_curptr-size;
00507 }
00508
00509 inline void FreeMemBlock(void *ptr,unsigned long size)
00510 {
00511 }
00512 */
00513 //#endif
00514
00515 #endif
1.2.11.1 written by Dimitri van Heesch,
© 1997-2001