PpmContext.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. namespace SharpCompress.Compressors.PPMd.I1
  2. {
  3. /// <summary>
  4. /// The PPM context structure. This is tightly coupled with <see cref="Model"/>.
  5. /// </summary>
  6. /// <remarks>
  7. /// <para>
  8. /// This must be a structure rather than a class because several places in the associated code assume that
  9. /// <see cref="PpmContext"/> is a value type (meaning that assignment creates a completely new copy of
  10. /// the instance rather than just copying a reference to the same instance).
  11. /// </para>
  12. /// </remarks>
  13. internal partial class Model
  14. {
  15. /// <summary>
  16. /// The structure which represents the current PPM context. This is 12 bytes in size.
  17. /// </summary>
  18. internal struct PpmContext
  19. {
  20. public uint _address;
  21. public byte[] _memory;
  22. public static readonly PpmContext ZERO = new PpmContext(0, null);
  23. public const int SIZE = 12;
  24. /// <summary>
  25. /// Initializes a new instance of the <see cref="PpmContext"/> structure.
  26. /// </summary>
  27. public PpmContext(uint address, byte[] memory)
  28. {
  29. _address = address;
  30. _memory = memory;
  31. }
  32. /// <summary>
  33. /// Gets or sets the number statistics.
  34. /// </summary>
  35. public byte NumberStatistics { get => _memory[_address]; set => _memory[_address] = value; }
  36. /// <summary>
  37. /// Gets or sets the flags.
  38. /// </summary>
  39. public byte Flags { get => _memory[_address + 1]; set => _memory[_address + 1] = value; }
  40. /// <summary>
  41. /// Gets or sets the summary frequency.
  42. /// </summary>
  43. public ushort SummaryFrequency
  44. {
  45. get => (ushort)(_memory[_address + 2] | _memory[_address + 3] << 8);
  46. set
  47. {
  48. _memory[_address + 2] = (byte)value;
  49. _memory[_address + 3] = (byte)(value >> 8);
  50. }
  51. }
  52. /// <summary>
  53. /// Gets or sets the statistics.
  54. /// </summary>
  55. public PpmState Statistics
  56. {
  57. get => new PpmState(
  58. _memory[_address + 4] | ((uint)_memory[_address + 5]) << 8 |
  59. ((uint)_memory[_address + 6]) << 16 | ((uint)_memory[_address + 7]) << 24, _memory);
  60. set
  61. {
  62. _memory[_address + 4] = (byte)value._address;
  63. _memory[_address + 5] = (byte)(value._address >> 8);
  64. _memory[_address + 6] = (byte)(value._address >> 16);
  65. _memory[_address + 7] = (byte)(value._address >> 24);
  66. }
  67. }
  68. /// <summary>
  69. /// Gets or sets the suffix.
  70. /// </summary>
  71. public PpmContext Suffix
  72. {
  73. get => new PpmContext(
  74. _memory[_address + 8] | ((uint)_memory[_address + 9]) << 8 |
  75. ((uint)_memory[_address + 10]) << 16 | ((uint)_memory[_address + 11]) << 24, _memory);
  76. set
  77. {
  78. _memory[_address + 8] = (byte)value._address;
  79. _memory[_address + 9] = (byte)(value._address >> 8);
  80. _memory[_address + 10] = (byte)(value._address >> 16);
  81. _memory[_address + 11] = (byte)(value._address >> 24);
  82. }
  83. }
  84. /// <summary>
  85. /// The first PPM state associated with the PPM context.
  86. /// </summary>
  87. /// <remarks>
  88. /// <para>
  89. /// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members
  90. /// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and
  91. /// Successor members of PpmState, since they also add up to 6 bytes).
  92. /// </para>
  93. /// <para>
  94. /// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes)
  95. /// 1 context.NumberStatistics
  96. /// 1 context.Flags
  97. /// 2 context.SummaryFrequency
  98. /// 4 context.Statistics (pointer to PpmState)
  99. /// 4 context.Suffix (pointer to PpmContext)
  100. /// </para>
  101. /// <para>
  102. /// PpmState (total of 6 bytes)
  103. /// 1 Symbol
  104. /// 1 Frequency
  105. /// 4 Successor (pointer to PpmContext)
  106. /// </para>
  107. /// </remarks>
  108. /// <returns></returns>
  109. public PpmState FirstState => new PpmState(_address + 2, _memory);
  110. /// <summary>
  111. /// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same
  112. /// information can be obtained using the Symbol property on the PPM state provided by the
  113. /// <see cref="FirstState"/> property.
  114. /// </summary>
  115. public byte FirstStateSymbol { get => _memory[_address + 2]; set => _memory[_address + 2] = value; }
  116. /// <summary>
  117. /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same
  118. /// information can be obtained using the Frequency property on the PPM state provided by the
  119. ///context.FirstState property.
  120. /// </summary>
  121. public byte FirstStateFrequency { get => _memory[_address + 3]; set => _memory[_address + 3] = value; }
  122. /// <summary>
  123. /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same
  124. /// information can be obtained using the Successor property on the PPM state provided by the
  125. /// </summary>
  126. public PpmContext FirstStateSuccessor
  127. {
  128. get => new PpmContext(
  129. _memory[_address + 4] | ((uint)_memory[_address + 5]) << 8 |
  130. ((uint)_memory[_address + 6]) << 16 | ((uint)_memory[_address + 7]) << 24, _memory);
  131. set
  132. {
  133. _memory[_address + 4] = (byte)value._address;
  134. _memory[_address + 5] = (byte)(value._address >> 8);
  135. _memory[_address + 6] = (byte)(value._address >> 16);
  136. _memory[_address + 7] = (byte)(value._address >> 24);
  137. }
  138. }
  139. /// <summary>
  140. /// Allow a pointer to be implicitly converted to a PPM context.
  141. /// </summary>
  142. /// <param name="pointer"></param>
  143. /// <returns></returns>
  144. public static implicit operator PpmContext(Pointer pointer)
  145. {
  146. return new PpmContext(pointer._address, pointer._memory);
  147. }
  148. /// <summary>
  149. /// Allow pointer-like addition on a PPM context.
  150. /// </summary>
  151. /// <param name="context"></param>
  152. /// <param name="offset"></param>
  153. /// <returns></returns>
  154. public static PpmContext operator +(PpmContext context, int offset)
  155. {
  156. context._address = (uint)(context._address + offset * SIZE);
  157. return context;
  158. }
  159. /// <summary>
  160. /// Allow pointer-like subtraction on a PPM context.
  161. /// </summary>
  162. /// <param name="context"></param>
  163. /// <param name="offset"></param>
  164. /// <returns></returns>
  165. public static PpmContext operator -(PpmContext context, int offset)
  166. {
  167. context._address = (uint)(context._address - offset * SIZE);
  168. return context;
  169. }
  170. /// <summary>
  171. /// Compare two PPM contexts.
  172. /// </summary>
  173. /// <param name="context1"></param>
  174. /// <param name="context2"></param>
  175. /// <returns></returns>
  176. public static bool operator <=(PpmContext context1, PpmContext context2)
  177. {
  178. return context1._address <= context2._address;
  179. }
  180. /// <summary>
  181. /// Compare two PPM contexts.
  182. /// </summary>
  183. /// <param name="context1"></param>
  184. /// <param name="context2"></param>
  185. /// <returns></returns>
  186. public static bool operator >=(PpmContext context1, PpmContext context2)
  187. {
  188. return context1._address >= context2._address;
  189. }
  190. /// <summary>
  191. /// Compare two PPM contexts.
  192. /// </summary>
  193. /// <param name="context1"></param>
  194. /// <param name="context2"></param>
  195. /// <returns></returns>
  196. public static bool operator ==(PpmContext context1, PpmContext context2)
  197. {
  198. return context1._address == context2._address;
  199. }
  200. /// <summary>
  201. /// Compare two PPM contexts.
  202. /// </summary>
  203. /// <param name="context1"></param>
  204. /// <param name="context2"></param>
  205. /// <returns></returns>
  206. public static bool operator !=(PpmContext context1, PpmContext context2)
  207. {
  208. return context1._address != context2._address;
  209. }
  210. /// <summary>
  211. /// Indicates whether this instance and a specified object are equal.
  212. /// </summary>
  213. /// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
  214. /// <param name="obj">Another object to compare to.</param>
  215. public override bool Equals(object obj)
  216. {
  217. if (obj is PpmContext)
  218. {
  219. PpmContext context = (PpmContext)obj;
  220. return context._address == _address;
  221. }
  222. return base.Equals(obj);
  223. }
  224. /// <summary>
  225. /// Returns the hash code for this instance.
  226. /// </summary>
  227. /// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
  228. public override int GetHashCode()
  229. {
  230. return _address.GetHashCode();
  231. }
  232. }
  233. private void EncodeBinarySymbol(int symbol, PpmContext context)
  234. {
  235. PpmState state = context.FirstState;
  236. int index1 = _probabilities[state.Frequency - 1];
  237. int index2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess +
  238. context.Flags + ((_runLength >> 26) & 0x20);
  239. if (state.Symbol == symbol)
  240. {
  241. _foundState = state;
  242. state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
  243. _coder._lowCount = 0;
  244. _coder._highCount = _binarySummary[index1, index2];
  245. _binarySummary[index1, index2] +=
  246. (ushort)(INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2));
  247. _previousSuccess = 1;
  248. _runLength++;
  249. }
  250. else
  251. {
  252. _coder._lowCount = _binarySummary[index1, index2];
  253. _binarySummary[index1, index2] -= (ushort)Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2);
  254. _coder._highCount = BINARY_SCALE;
  255. _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10];
  256. _characterMask[state.Symbol] = _escapeCount;
  257. _previousSuccess = 0;
  258. _numberMasked = 0;
  259. _foundState = PpmState.ZERO;
  260. }
  261. }
  262. private void EncodeSymbol1(int symbol, PpmContext context)
  263. {
  264. uint lowCount;
  265. uint index = context.Statistics.Symbol;
  266. PpmState state = context.Statistics;
  267. _coder._scale = context.SummaryFrequency;
  268. if (index == symbol)
  269. {
  270. _coder._highCount = state.Frequency;
  271. _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0);
  272. _foundState = state;
  273. _foundState.Frequency += 4;
  274. context.SummaryFrequency += 4;
  275. _runLength += _previousSuccess;
  276. if (state.Frequency > MAXIMUM_FREQUENCY)
  277. {
  278. Rescale(context);
  279. }
  280. _coder._lowCount = 0;
  281. return;
  282. }
  283. lowCount = state.Frequency;
  284. index = context.NumberStatistics;
  285. _previousSuccess = 0;
  286. while ((++state).Symbol != symbol)
  287. {
  288. lowCount += state.Frequency;
  289. if (--index == 0)
  290. {
  291. _coder._lowCount = lowCount;
  292. _characterMask[state.Symbol] = _escapeCount;
  293. _numberMasked = context.NumberStatistics;
  294. index = context.NumberStatistics;
  295. _foundState = PpmState.ZERO;
  296. do
  297. {
  298. _characterMask[(--state).Symbol] = _escapeCount;
  299. }
  300. while (--index != 0);
  301. _coder._highCount = _coder._scale;
  302. return;
  303. }
  304. }
  305. _coder._highCount = (_coder._lowCount = lowCount) + state.Frequency;
  306. Update1(state, context);
  307. }
  308. private void EncodeSymbol2(int symbol, PpmContext context)
  309. {
  310. See2Context see2Context = MakeEscapeFrequency(context);
  311. uint currentSymbol;
  312. uint lowCount = 0;
  313. uint index = (uint)(context.NumberStatistics - _numberMasked);
  314. PpmState state = context.Statistics - 1;
  315. do
  316. {
  317. do
  318. {
  319. currentSymbol = state[1].Symbol;
  320. state++;
  321. }
  322. while (_characterMask[currentSymbol] == _escapeCount);
  323. _characterMask[currentSymbol] = _escapeCount;
  324. if (currentSymbol == symbol)
  325. {
  326. goto SymbolFound;
  327. }
  328. lowCount += state.Frequency;
  329. }
  330. while (--index != 0);
  331. _coder._lowCount = lowCount;
  332. _coder._scale += _coder._lowCount;
  333. _coder._highCount = _coder._scale;
  334. see2Context._summary += (ushort)_coder._scale;
  335. _numberMasked = context.NumberStatistics;
  336. return;
  337. SymbolFound:
  338. _coder._lowCount = lowCount;
  339. lowCount += state.Frequency;
  340. _coder._highCount = lowCount;
  341. for (PpmState p1 = state; --index != 0;)
  342. {
  343. do
  344. {
  345. currentSymbol = p1[1].Symbol;
  346. p1++;
  347. }
  348. while (_characterMask[currentSymbol] == _escapeCount);
  349. lowCount += p1.Frequency;
  350. }
  351. _coder._scale += lowCount;
  352. see2Context.Update();
  353. Update2(state, context);
  354. }
  355. private void DecodeBinarySymbol(PpmContext context)
  356. {
  357. PpmState state = context.FirstState;
  358. int index1 = _probabilities[state.Frequency - 1];
  359. int index2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess +
  360. context.Flags + ((_runLength >> 26) & 0x20);
  361. if (_coder.RangeGetCurrentShiftCount(TOTAL_BIT_COUNT) < _binarySummary[index1, index2])
  362. {
  363. _foundState = state;
  364. state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
  365. _coder._lowCount = 0;
  366. _coder._highCount = _binarySummary[index1, index2];
  367. _binarySummary[index1, index2] +=
  368. (ushort)(INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2));
  369. _previousSuccess = 1;
  370. _runLength++;
  371. }
  372. else
  373. {
  374. _coder._lowCount = _binarySummary[index1, index2];
  375. _binarySummary[index1, index2] -= (ushort)Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2);
  376. _coder._highCount = BINARY_SCALE;
  377. _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10];
  378. _characterMask[state.Symbol] = _escapeCount;
  379. _previousSuccess = 0;
  380. _numberMasked = 0;
  381. _foundState = PpmState.ZERO;
  382. }
  383. }
  384. private void DecodeSymbol1(PpmContext context)
  385. {
  386. uint index;
  387. uint count;
  388. uint highCount = context.Statistics.Frequency;
  389. PpmState state = context.Statistics;
  390. _coder._scale = context.SummaryFrequency;
  391. count = _coder.RangeGetCurrentCount();
  392. if (count < highCount)
  393. {
  394. _coder._highCount = highCount;
  395. _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0);
  396. _foundState = state;
  397. highCount += 4;
  398. _foundState.Frequency = (byte)highCount;
  399. context.SummaryFrequency += 4;
  400. _runLength += _previousSuccess;
  401. if (highCount > MAXIMUM_FREQUENCY)
  402. {
  403. Rescale(context);
  404. }
  405. _coder._lowCount = 0;
  406. return;
  407. }
  408. index = context.NumberStatistics;
  409. _previousSuccess = 0;
  410. while ((highCount += (++state).Frequency) <= count)
  411. {
  412. if (--index == 0)
  413. {
  414. _coder._lowCount = highCount;
  415. _characterMask[state.Symbol] = _escapeCount;
  416. _numberMasked = context.NumberStatistics;
  417. index = context.NumberStatistics;
  418. _foundState = PpmState.ZERO;
  419. do
  420. {
  421. _characterMask[(--state).Symbol] = _escapeCount;
  422. }
  423. while (--index != 0);
  424. _coder._highCount = _coder._scale;
  425. return;
  426. }
  427. }
  428. _coder._highCount = highCount;
  429. _coder._lowCount = _coder._highCount - state.Frequency;
  430. Update1(state, context);
  431. }
  432. private void DecodeSymbol2(PpmContext context)
  433. {
  434. See2Context see2Context = MakeEscapeFrequency(context);
  435. uint currentSymbol;
  436. uint count;
  437. uint highCount = 0;
  438. uint index = (uint)(context.NumberStatistics - _numberMasked);
  439. uint stateIndex = 0;
  440. PpmState state = context.Statistics - 1;
  441. do
  442. {
  443. do
  444. {
  445. currentSymbol = state[1].Symbol;
  446. state++;
  447. }
  448. while (_characterMask[currentSymbol] == _escapeCount);
  449. highCount += state.Frequency;
  450. _decodeStates[stateIndex++] = state;
  451. // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons)
  452. }
  453. while (--index != 0);
  454. _coder._scale += highCount;
  455. count = _coder.RangeGetCurrentCount();
  456. stateIndex = 0;
  457. state = _decodeStates[stateIndex];
  458. if (count < highCount)
  459. {
  460. highCount = 0;
  461. while ((highCount += state.Frequency) <= count)
  462. {
  463. state = _decodeStates[++stateIndex];
  464. }
  465. _coder._highCount = highCount;
  466. _coder._lowCount = _coder._highCount - state.Frequency;
  467. see2Context.Update();
  468. Update2(state, context);
  469. }
  470. else
  471. {
  472. _coder._lowCount = highCount;
  473. _coder._highCount = _coder._scale;
  474. index = (uint)(context.NumberStatistics - _numberMasked);
  475. _numberMasked = context.NumberStatistics;
  476. do
  477. {
  478. _characterMask[_decodeStates[stateIndex].Symbol] = _escapeCount;
  479. stateIndex++;
  480. }
  481. while (--index != 0);
  482. see2Context._summary += (ushort)_coder._scale;
  483. }
  484. }
  485. private void Update1(PpmState state, PpmContext context)
  486. {
  487. _foundState = state;
  488. _foundState.Frequency += 4;
  489. context.SummaryFrequency += 4;
  490. if (state[0].Frequency > state[-1].Frequency)
  491. {
  492. Swap(state[0], state[-1]);
  493. _foundState = --state;
  494. if (state.Frequency > MAXIMUM_FREQUENCY)
  495. {
  496. Rescale(context);
  497. }
  498. }
  499. }
  500. private void Update2(PpmState state, PpmContext context)
  501. {
  502. _foundState = state;
  503. _foundState.Frequency += 4;
  504. context.SummaryFrequency += 4;
  505. if (state.Frequency > MAXIMUM_FREQUENCY)
  506. {
  507. Rescale(context);
  508. }
  509. _escapeCount++;
  510. _runLength = _initialRunLength;
  511. }
  512. private See2Context MakeEscapeFrequency(PpmContext context)
  513. {
  514. uint numberStatistics = (uint)2 * context.NumberStatistics;
  515. See2Context see2Context;
  516. if (context.NumberStatistics != 0xff)
  517. {
  518. // Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second
  519. // dimension of the see2Contexts array is always in the range 0 .. 31).
  520. numberStatistics = context.Suffix.NumberStatistics;
  521. int index1 = _probabilities[context.NumberStatistics + 2] - 3;
  522. int index2 = ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) +
  523. ((2 * context.NumberStatistics < numberStatistics + _numberMasked) ? 2 : 0) + context.Flags;
  524. see2Context = _see2Contexts[index1, index2];
  525. _coder._scale = see2Context.Mean();
  526. }
  527. else
  528. {
  529. see2Context = _emptySee2Context;
  530. _coder._scale = 1;
  531. }
  532. return see2Context;
  533. }
  534. private void Rescale(PpmContext context)
  535. {
  536. uint oldUnitCount;
  537. int adder;
  538. uint escapeFrequency;
  539. uint index = context.NumberStatistics;
  540. byte localSymbol;
  541. byte localFrequency;
  542. PpmContext localSuccessor;
  543. PpmState p1;
  544. PpmState state;
  545. for (state = _foundState; state != context.Statistics; state--)
  546. {
  547. Swap(state[0], state[-1]);
  548. }
  549. state.Frequency += 4;
  550. context.SummaryFrequency += 4;
  551. escapeFrequency = (uint)(context.SummaryFrequency - state.Frequency);
  552. adder = (_orderFall != 0 || _method > ModelRestorationMethod.Freeze) ? 1 : 0;
  553. state.Frequency = (byte)((state.Frequency + adder) >> 1);
  554. context.SummaryFrequency = state.Frequency;
  555. do
  556. {
  557. escapeFrequency -= (++state).Frequency;
  558. state.Frequency = (byte)((state.Frequency + adder) >> 1);
  559. context.SummaryFrequency += state.Frequency;
  560. if (state[0].Frequency > state[-1].Frequency)
  561. {
  562. p1 = state;
  563. localSymbol = p1.Symbol;
  564. localFrequency = p1.Frequency;
  565. localSuccessor = p1.Successor;
  566. do
  567. {
  568. Copy(p1[0], p1[-1]);
  569. }
  570. while (localFrequency > (--p1)[-1].Frequency);
  571. p1.Symbol = localSymbol;
  572. p1.Frequency = localFrequency;
  573. p1.Successor = localSuccessor;
  574. }
  575. }
  576. while (--index != 0);
  577. if (state.Frequency == 0)
  578. {
  579. do
  580. {
  581. index++;
  582. }
  583. while ((--state).Frequency == 0);
  584. escapeFrequency += index;
  585. oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1);
  586. context.NumberStatistics -= (byte)index;
  587. if (context.NumberStatistics == 0)
  588. {
  589. localSymbol = context.Statistics.Symbol;
  590. localFrequency = context.Statistics.Frequency;
  591. localSuccessor = context.Statistics.Successor;
  592. localFrequency = (byte)((2 * localFrequency + escapeFrequency - 1) / escapeFrequency);
  593. if (localFrequency > MAXIMUM_FREQUENCY / 3)
  594. {
  595. localFrequency = (byte)(MAXIMUM_FREQUENCY / 3);
  596. }
  597. _allocator.FreeUnits(context.Statistics, oldUnitCount);
  598. context.FirstStateSymbol = localSymbol;
  599. context.FirstStateFrequency = localFrequency;
  600. context.FirstStateSuccessor = localSuccessor;
  601. context.Flags = (byte)((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00));
  602. _foundState = context.FirstState;
  603. return;
  604. }
  605. context.Statistics = _allocator.ShrinkUnits(context.Statistics, oldUnitCount,
  606. (uint)((context.NumberStatistics + 2) >> 1));
  607. context.Flags &= 0xf7;
  608. index = context.NumberStatistics;
  609. state = context.Statistics;
  610. context.Flags |= (byte)((state.Symbol >= 0x40) ? 0x08 : 0x00);
  611. do
  612. {
  613. context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00);
  614. }
  615. while (--index != 0);
  616. }
  617. escapeFrequency -= (escapeFrequency >> 1);
  618. context.SummaryFrequency += (ushort)escapeFrequency;
  619. context.Flags |= 0x04;
  620. _foundState = context.Statistics;
  621. }
  622. private void Refresh(uint oldUnitCount, bool scale, PpmContext context)
  623. {
  624. int index = context.NumberStatistics;
  625. int escapeFrequency;
  626. int scaleValue = (scale ? 1 : 0);
  627. context.Statistics = _allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((index + 2) >> 1));
  628. PpmState statistics = context.Statistics;
  629. context.Flags =
  630. (byte)((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00));
  631. escapeFrequency = context.SummaryFrequency - statistics.Frequency;
  632. statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
  633. context.SummaryFrequency = statistics.Frequency;
  634. do
  635. {
  636. escapeFrequency -= (++statistics).Frequency;
  637. statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
  638. context.SummaryFrequency += statistics.Frequency;
  639. context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00);
  640. }
  641. while (--index != 0);
  642. escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue;
  643. context.SummaryFrequency += (ushort)escapeFrequency;
  644. }
  645. private PpmContext CutOff(int order, PpmContext context)
  646. {
  647. int index;
  648. PpmState state;
  649. if (context.NumberStatistics == 0)
  650. {
  651. state = context.FirstState;
  652. if ((Pointer)state.Successor >= _allocator._baseUnit)
  653. {
  654. if (order < _modelOrder)
  655. {
  656. state.Successor = CutOff(order + 1, state.Successor);
  657. }
  658. else
  659. {
  660. state.Successor = PpmContext.ZERO;
  661. }
  662. if (state.Successor == PpmContext.ZERO && order > ORDER_BOUND)
  663. {
  664. _allocator.SpecialFreeUnits(context);
  665. return PpmContext.ZERO;
  666. }
  667. return context;
  668. }
  669. _allocator.SpecialFreeUnits(context);
  670. return PpmContext.ZERO;
  671. }
  672. uint unitCount = (uint)((context.NumberStatistics + 2) >> 1);
  673. context.Statistics = _allocator.MoveUnitsUp(context.Statistics, unitCount);
  674. index = context.NumberStatistics;
  675. for (state = context.Statistics + index; state >= context.Statistics; state--)
  676. {
  677. if (state.Successor < _allocator._baseUnit)
  678. {
  679. state.Successor = PpmContext.ZERO;
  680. Swap(state, context.Statistics[index--]);
  681. }
  682. else if (order < _modelOrder)
  683. {
  684. state.Successor = CutOff(order + 1, state.Successor);
  685. }
  686. else
  687. {
  688. state.Successor = PpmContext.ZERO;
  689. }
  690. }
  691. if (index != context.NumberStatistics && order != 0)
  692. {
  693. context.NumberStatistics = (byte)index;
  694. state = context.Statistics;
  695. if (index < 0)
  696. {
  697. _allocator.FreeUnits(state, unitCount);
  698. _allocator.SpecialFreeUnits(context);
  699. return PpmContext.ZERO;
  700. }
  701. if (index == 0)
  702. {
  703. context.Flags = (byte)((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00));
  704. Copy(context.FirstState, state);
  705. _allocator.FreeUnits(state, unitCount);
  706. context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3);
  707. }
  708. else
  709. {
  710. Refresh(unitCount, context.SummaryFrequency > 16 * index, context);
  711. }
  712. }
  713. return context;
  714. }
  715. private PpmContext RemoveBinaryContexts(int order, PpmContext context)
  716. {
  717. if (context.NumberStatistics == 0)
  718. {
  719. PpmState state = context.FirstState;
  720. if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder)
  721. {
  722. state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
  723. }
  724. else
  725. {
  726. state.Successor = PpmContext.ZERO;
  727. }
  728. if ((state.Successor == PpmContext.ZERO) &&
  729. (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff))
  730. {
  731. _allocator.FreeUnits(context, 1);
  732. return PpmContext.ZERO;
  733. }
  734. return context;
  735. }
  736. for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--)
  737. {
  738. if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder)
  739. {
  740. state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
  741. }
  742. else
  743. {
  744. state.Successor = PpmContext.ZERO;
  745. }
  746. }
  747. return context;
  748. }
  749. }
  750. }