123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- /****************************************************************************
- * This file is part of PPMd project *
- * Written and distributed to public domain by Dmitry Shkarin 1997, *
- * 1999-2000 *
- * Contents: memory allocation routines *
- ****************************************************************************/
- static const uint UNIT_SIZE=Max(sizeof(RARPPM_CONTEXT),sizeof(RARPPM_MEM_BLK));
- static const uint FIXED_UNIT_SIZE=12;
- SubAllocator::SubAllocator()
- {
- Clean();
- }
- void SubAllocator::Clean()
- {
- SubAllocatorSize=0;
- }
- inline void SubAllocator::InsertNode(void* p,int indx)
- {
- ((RAR_NODE*) p)->next=FreeList[indx].next;
- FreeList[indx].next=(RAR_NODE*) p;
- }
- inline void* SubAllocator::RemoveNode(int indx)
- {
- RAR_NODE* RetVal=FreeList[indx].next;
- FreeList[indx].next=RetVal->next;
- return RetVal;
- }
- inline uint SubAllocator::U2B(int NU)
- {
- // We calculate the size of units in bytes based on real UNIT_SIZE.
- // In original implementation it was 8*NU+4*NU.
- return UNIT_SIZE*NU;
- }
- // Calculate RARPPM_MEM_BLK+Items address. Real RARPPM_MEM_BLK size must be
- // equal to UNIT_SIZE, so we cannot just add Items to RARPPM_MEM_BLK address.
- inline RARPPM_MEM_BLK* SubAllocator::MBPtr(RARPPM_MEM_BLK *BasePtr,int Items)
- {
- return((RARPPM_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
- }
- inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx)
- {
- int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx];
- byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]);
- if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff)
- {
- InsertNode(p,--i);
- p += U2B(i=Indx2Units[i]);
- UDiff -= i;
- }
- InsertNode(p,Units2Indx[UDiff-1]);
- }
- void SubAllocator::StopSubAllocator()
- {
- if ( SubAllocatorSize )
- {
- SubAllocatorSize=0;
- free(HeapStart);
- }
- }
- bool SubAllocator::StartSubAllocator(int SASize)
- {
- uint t=SASize << 20;
- if (SubAllocatorSize == t)
- return true;
- StopSubAllocator();
- // Original algorithm expects FIXED_UNIT_SIZE, but actual structure size
- // can be larger. So let's recalculate the allocated size and add two more
- // units: one as reserve for HeapEnd overflow checks and another
- // to provide the space to correctly align UnitsStart.
- uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE;
- if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
- {
- ErrHandler.MemoryError();
- return false;
- }
- // HeapEnd did not present in original algorithm. We added it to control
- // invalid memory access attempts when processing corrupt archived data.
- HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
- SubAllocatorSize=t;
- return true;
- }
- void SubAllocator::InitSubAllocator()
- {
- int i, k;
- memset(FreeList,0,sizeof(FreeList));
- pText=HeapStart;
- // Original algorithm operates with 12 byte FIXED_UNIT_SIZE, but actual
- // size of RARPPM_MEM_BLK and RARPPM_CONTEXT structures can exceed this value
- // because of alignment and larger pointer fields size.
- // So we define UNIT_SIZE for this larger size and adjust memory
- // pointers accordingly.
- // Size2 is (HiUnit-LoUnit) memory area size to allocate as originally
- // supposed by compression algorithm. It is 7/8 of total allocated size.
- uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7);
- // RealSize2 is the real adjusted size of (HiUnit-LoUnit) memory taking
- // into account that our UNIT_SIZE can be larger than FIXED_UNIT_SIZE.
- uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
- // Size1 is the size of memory area from HeapStart to FakeUnitsStart
- // as originally supposed by compression algorithm. This area can contain
- // different data types, both single symbols and structures.
- uint Size1=SubAllocatorSize-Size2;
- // Real size of this area. We correct it according to UNIT_SIZE vs
- // FIXED_UNIT_SIZE difference. Also we add one more UNIT_SIZE
- // to compensate a possible reminder from Size1/FIXED_UNIT_SIZE,
- // which would be lost otherwise. We add UNIT_SIZE instead of
- // this Size1%FIXED_UNIT_SIZE reminder, because it allows to align
- // UnitsStart easily and adding more than reminder is ok for algorithm.
- uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE;
- // RealSize1 must be divided by UNIT_SIZE without a reminder, so UnitsStart
- // is aligned to UNIT_SIZE. It is important for those architectures,
- // where a proper memory alignment is mandatory. Since we produce RealSize1
- // multiplying by UNIT_SIZE, this condition is always true. So LoUnit,
- // UnitsStart, HeapStart are properly aligned,
- LoUnit=UnitsStart=HeapStart+RealSize1;
- // When we reach FakeUnitsStart, we restart the model. It is where
- // the original algorithm expected to see UnitsStart. Real UnitsStart
- // can have a larger value.
- FakeUnitsStart=HeapStart+Size1;
- HiUnit=LoUnit+RealSize2;
- for (i=0,k=1;i < N1 ;i++,k += 1)
- Indx2Units[i]=k;
- for (k++;i < N1+N2 ;i++,k += 2)
- Indx2Units[i]=k;
- for (k++;i < N1+N2+N3 ;i++,k += 3)
- Indx2Units[i]=k;
- for (k++;i < N1+N2+N3+N4;i++,k += 4)
- Indx2Units[i]=k;
- for (GlueCount=k=i=0;k < 128;k++)
- {
- i += (Indx2Units[i] < k+1);
- Units2Indx[k]=i;
- }
- }
- inline void SubAllocator::GlueFreeBlocks()
- {
- RARPPM_MEM_BLK s0, * p, * p1;
- int i, k, sz;
- if (LoUnit != HiUnit)
- *LoUnit=0;
- for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++)
- while ( FreeList[i].next )
- {
- p=(RARPPM_MEM_BLK*)RemoveNode(i);
- p->insertAt(&s0);
- p->Stamp=0xFFFF;
- p->NU=Indx2Units[i];
- }
- for (p=s0.next;p != &s0;p=p->next)
- while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000)
- {
- p1->remove();
- p->NU += p1->NU;
- }
- while ((p=s0.next) != &s0)
- {
- for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128))
- InsertNode(p,N_INDEXES-1);
- if (Indx2Units[i=Units2Indx[sz-1]] != sz)
- {
- k=sz-Indx2Units[--i];
- InsertNode(MBPtr(p,sz-k),k-1);
- }
- InsertNode(p,i);
- }
- }
- void* SubAllocator::AllocUnitsRare(int indx)
- {
- if ( !GlueCount )
- {
- GlueCount = 255;
- GlueFreeBlocks();
- if ( FreeList[indx].next )
- return RemoveNode(indx);
- }
- int i=indx;
- do
- {
- if (++i == N_INDEXES)
- {
- GlueCount--;
- i=U2B(Indx2Units[indx]);
- int j=FIXED_UNIT_SIZE*Indx2Units[indx];
- if (FakeUnitsStart - pText > j)
- {
- FakeUnitsStart -= j;
- UnitsStart -= i;
- return UnitsStart;
- }
- return NULL;
- }
- } while ( !FreeList[i].next );
- void* RetVal=RemoveNode(i);
- SplitBlock(RetVal,i,indx);
- return RetVal;
- }
- inline void* SubAllocator::AllocUnits(int NU)
- {
- int indx=Units2Indx[NU-1];
- if ( FreeList[indx].next )
- return RemoveNode(indx);
- void* RetVal=LoUnit;
- LoUnit += U2B(Indx2Units[indx]);
- if (LoUnit <= HiUnit)
- return RetVal;
- LoUnit -= U2B(Indx2Units[indx]);
- return AllocUnitsRare(indx);
- }
- void* SubAllocator::AllocContext()
- {
- if (HiUnit != LoUnit)
- return (HiUnit -= UNIT_SIZE);
- if ( FreeList->next )
- return RemoveNode(0);
- return AllocUnitsRare(0);
- }
- void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU)
- {
- int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1];
- if (i0 == i1)
- return OldPtr;
- void* ptr=AllocUnits(OldNU+1);
- if ( ptr )
- {
- memcpy(ptr,OldPtr,U2B(OldNU));
- InsertNode(OldPtr,i0);
- }
- return ptr;
- }
- void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU)
- {
- int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1];
- if (i0 == i1)
- return OldPtr;
- if ( FreeList[i1].next )
- {
- void* ptr=RemoveNode(i1);
- memcpy(ptr,OldPtr,U2B(NewNU));
- InsertNode(OldPtr,i0);
- return ptr;
- }
- else
- {
- SplitBlock(OldPtr,i0,i1);
- return OldPtr;
- }
- }
- void SubAllocator::FreeUnits(void* ptr,int OldNU)
- {
- InsertNode(ptr,Units2Indx[OldNU-1]);
- }
|