suballoc.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /****************************************************************************
  2. * This file is part of PPMd project *
  3. * Written and distributed to public domain by Dmitry Shkarin 1997, *
  4. * 1999-2000 *
  5. * Contents: memory allocation routines *
  6. ****************************************************************************/
  7. SubAllocator::SubAllocator()
  8. {
  9. Clean();
  10. }
  11. void SubAllocator::Clean()
  12. {
  13. SubAllocatorSize=0;
  14. }
  15. inline void SubAllocator::InsertNode(void* p,int indx)
  16. {
  17. ((RAR_NODE*) p)->next=FreeList[indx].next;
  18. FreeList[indx].next=(RAR_NODE*) p;
  19. }
  20. inline void* SubAllocator::RemoveNode(int indx)
  21. {
  22. RAR_NODE* RetVal=FreeList[indx].next;
  23. FreeList[indx].next=RetVal->next;
  24. return RetVal;
  25. }
  26. inline uint SubAllocator::U2B(int NU)
  27. {
  28. // We calculate the size of units in bytes based on real UNIT_SIZE.
  29. // In original implementation it was 8*NU+4*NU.
  30. return UNIT_SIZE*NU;
  31. }
  32. // Calculate RAR_MEM_BLK+Items address. Real RAR_MEM_BLK size must be
  33. // equal to UNIT_SIZE, so we cannot just add Items to RAR_MEM_BLK address.
  34. inline RAR_MEM_BLK* SubAllocator::MBPtr(RAR_MEM_BLK *BasePtr,int Items)
  35. {
  36. return((RAR_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
  37. }
  38. inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx)
  39. {
  40. int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx];
  41. byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]);
  42. if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff)
  43. {
  44. InsertNode(p,--i);
  45. p += U2B(i=Indx2Units[i]);
  46. UDiff -= i;
  47. }
  48. InsertNode(p,Units2Indx[UDiff-1]);
  49. }
  50. void SubAllocator::StopSubAllocator()
  51. {
  52. if ( SubAllocatorSize )
  53. {
  54. SubAllocatorSize=0;
  55. free(HeapStart);
  56. }
  57. }
  58. bool SubAllocator::StartSubAllocator(int SASize)
  59. {
  60. uint t=SASize << 20;
  61. if (SubAllocatorSize == t)
  62. return TRUE;
  63. StopSubAllocator();
  64. // Original algorithm expects FIXED_UNIT_SIZE, but actual structure size
  65. // can be larger. So let's recalculate the allocated size and add two more
  66. // units: one as reserve for HeapEnd overflow checks and another
  67. // to provide the space to correctly align UnitsStart.
  68. uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE;
  69. if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
  70. {
  71. ErrHandler.MemoryError();
  72. return FALSE;
  73. }
  74. // HeapEnd did not present in original algorithm. We added it to control
  75. // invalid memory access attempts when processing corrupt archived data.
  76. HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
  77. SubAllocatorSize=t;
  78. return TRUE;
  79. }
  80. void SubAllocator::InitSubAllocator()
  81. {
  82. int i, k;
  83. memset(FreeList,0,sizeof(FreeList));
  84. pText=HeapStart;
  85. // Original algorithm operates with 12 byte FIXED_UNIT_SIZE, but actual
  86. // size of RAR_MEM_BLK and PPM_CONTEXT structures can exceed this value
  87. // because of alignment and larger pointer fields size.
  88. // So we define UNIT_SIZE for this larger size and adjust memory
  89. // pointers accordingly.
  90. // Size2 is (HiUnit-LoUnit) memory area size to allocate as originally
  91. // supposed by compression algorithm. It is 7/8 of total allocated size.
  92. uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7);
  93. // RealSize2 is the real adjusted size of (HiUnit-LoUnit) memory taking
  94. // into account that our UNIT_SIZE can be larger than FIXED_UNIT_SIZE.
  95. uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
  96. // Size1 is the size of memory area from HeapStart to FakeUnitsStart
  97. // as originally supposed by compression algorithm. This area can contain
  98. // different data types, both single symbols and structures.
  99. uint Size1=SubAllocatorSize-Size2;
  100. // Real size of this area. We correct it according to UNIT_SIZE vs
  101. // FIXED_UNIT_SIZE difference. Also we add one more UNIT_SIZE
  102. // to compensate a possible reminder from Size1/FIXED_UNIT_SIZE,
  103. // which would be lost otherwise. We add UNIT_SIZE instead of
  104. // this Size1%FIXED_UNIT_SIZE reminder, because it allows to align
  105. // UnitsStart easily and adding more than reminder is ok for algorithm.
  106. uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE;
  107. // RealSize1 must be divided by UNIT_SIZE without a reminder, so UnitsStart
  108. // is aligned to UNIT_SIZE. It is important for those architectures,
  109. // where a proper memory alignment is mandatory. Since we produce RealSize1
  110. // multiplying by UNIT_SIZE, this condition is always true. So LoUnit,
  111. // UnitsStart, HeapStart are properly aligned,
  112. LoUnit=UnitsStart=HeapStart+RealSize1;
  113. // When we reach FakeUnitsStart, we restart the model. It is where
  114. // the original algorithm expected to see UnitsStart. Real UnitsStart
  115. // can have a larger value.
  116. FakeUnitsStart=HeapStart+Size1;
  117. HiUnit=LoUnit+RealSize2;
  118. for (i=0,k=1;i < N1 ;i++,k += 1)
  119. Indx2Units[i]=k;
  120. for (k++;i < N1+N2 ;i++,k += 2)
  121. Indx2Units[i]=k;
  122. for (k++;i < N1+N2+N3 ;i++,k += 3)
  123. Indx2Units[i]=k;
  124. for (k++;i < N1+N2+N3+N4;i++,k += 4)
  125. Indx2Units[i]=k;
  126. for (GlueCount=k=i=0;k < 128;k++)
  127. {
  128. i += (Indx2Units[i] < k+1);
  129. Units2Indx[k]=i;
  130. }
  131. }
  132. inline void SubAllocator::GlueFreeBlocks()
  133. {
  134. RAR_MEM_BLK s0, * p, * p1;
  135. int i, k, sz;
  136. if (LoUnit != HiUnit)
  137. *LoUnit=0;
  138. for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++)
  139. while ( FreeList[i].next )
  140. {
  141. p=(RAR_MEM_BLK*)RemoveNode(i);
  142. p->insertAt(&s0);
  143. p->Stamp=0xFFFF;
  144. p->NU=Indx2Units[i];
  145. }
  146. for (p=s0.next;p != &s0;p=p->next)
  147. while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000)
  148. {
  149. p1->remove();
  150. p->NU += p1->NU;
  151. }
  152. while ((p=s0.next) != &s0)
  153. {
  154. for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128))
  155. InsertNode(p,N_INDEXES-1);
  156. if (Indx2Units[i=Units2Indx[sz-1]] != sz)
  157. {
  158. k=sz-Indx2Units[--i];
  159. InsertNode(MBPtr(p,sz-k),k-1);
  160. }
  161. InsertNode(p,i);
  162. }
  163. }
  164. void* SubAllocator::AllocUnitsRare(int indx)
  165. {
  166. if ( !GlueCount )
  167. {
  168. GlueCount = 255;
  169. GlueFreeBlocks();
  170. if ( FreeList[indx].next )
  171. return RemoveNode(indx);
  172. }
  173. int i=indx;
  174. do
  175. {
  176. if (++i == N_INDEXES)
  177. {
  178. GlueCount--;
  179. i=U2B(Indx2Units[indx]);
  180. int j=FIXED_UNIT_SIZE*Indx2Units[indx];
  181. if (FakeUnitsStart-pText > j)
  182. {
  183. FakeUnitsStart-=j;
  184. UnitsStart -= i;
  185. return(UnitsStart);
  186. }
  187. return(NULL);
  188. }
  189. } while ( !FreeList[i].next );
  190. void* RetVal=RemoveNode(i);
  191. SplitBlock(RetVal,i,indx);
  192. return RetVal;
  193. }
  194. inline void* SubAllocator::AllocUnits(int NU)
  195. {
  196. int indx=Units2Indx[NU-1];
  197. if ( FreeList[indx].next )
  198. return RemoveNode(indx);
  199. void* RetVal=LoUnit;
  200. LoUnit += U2B(Indx2Units[indx]);
  201. if (LoUnit <= HiUnit)
  202. return RetVal;
  203. LoUnit -= U2B(Indx2Units[indx]);
  204. return AllocUnitsRare(indx);
  205. }
  206. void* SubAllocator::AllocContext()
  207. {
  208. if (HiUnit != LoUnit)
  209. return (HiUnit -= UNIT_SIZE);
  210. if ( FreeList->next )
  211. return RemoveNode(0);
  212. return AllocUnitsRare(0);
  213. }
  214. void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU)
  215. {
  216. int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1];
  217. if (i0 == i1)
  218. return OldPtr;
  219. void* ptr=AllocUnits(OldNU+1);
  220. if ( ptr )
  221. {
  222. memcpy(ptr,OldPtr,U2B(OldNU));
  223. InsertNode(OldPtr,i0);
  224. }
  225. return ptr;
  226. }
  227. void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU)
  228. {
  229. int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1];
  230. if (i0 == i1)
  231. return OldPtr;
  232. if ( FreeList[i1].next )
  233. {
  234. void* ptr=RemoveNode(i1);
  235. memcpy(ptr,OldPtr,U2B(NewNU));
  236. InsertNode(OldPtr,i0);
  237. return ptr;
  238. }
  239. else
  240. {
  241. SplitBlock(OldPtr,i0,i1);
  242. return OldPtr;
  243. }
  244. }
  245. void SubAllocator::FreeUnits(void* ptr,int OldNU)
  246. {
  247. InsertNode(ptr,Units2Indx[OldNU-1]);
  248. }