1// Compress/RangeCoder/RangeCoderBit.h
2
3#ifndef __COMPRESS_RANGECODER_BIT_H
4#define __COMPRESS_RANGECODER_BIT_H
5
6#include "RangeCoder.h"
7
8namespace NCompress {
9namespace NRangeCoder {
10
11const int kNumBitModelTotalBits  = 11;
12const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
13
14const int kNumMoveReducingBits = 2;
15
16const int kNumBitPriceShiftBits = 6;
17const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
18
19class CPriceTables
20{
21public:
22  static UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
23  static void Init();
24  CPriceTables();
25};
26
27template <int numMoveBits>
28class CBitModel
29{
30public:
31  UInt32 Prob;
32  void UpdateModel(UInt32 symbol)
33  {
34    /*
35    Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
36    Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
37    */
38    if (symbol == 0)
39      Prob += (kBitModelTotal - Prob) >> numMoveBits;
40    else
41      Prob -= (Prob) >> numMoveBits;
42  }
43public:
44  void Init() { Prob = kBitModelTotal / 2; }
45};
46
47template <int numMoveBits>
48class CBitEncoder: public CBitModel<numMoveBits>
49{
50public:
51  void Encode(CEncoder *encoder, UInt32 symbol)
52  {
53    /*
54    encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
55    this->UpdateModel(symbol);
56    */
57    UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
58    if (symbol == 0)
59    {
60      encoder->Range = newBound;
61      this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
62    }
63    else
64    {
65      encoder->Low += newBound;
66      encoder->Range -= newBound;
67      this->Prob -= (this->Prob) >> numMoveBits;
68    }
69    if (encoder->Range < kTopValue)
70    {
71      encoder->Range <<= 8;
72      encoder->ShiftLow();
73    }
74  }
75  UInt32 GetPrice(UInt32 symbol) const
76  {
77    return CPriceTables::ProbPrices[
78      (((this->Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
79  }
80  UInt32 GetPrice0() const { return CPriceTables::ProbPrices[this->Prob >> kNumMoveReducingBits]; }
81  UInt32 GetPrice1() const { return CPriceTables::ProbPrices[(kBitModelTotal - this->Prob) >> kNumMoveReducingBits]; }
82};
83
84
85template <int numMoveBits>
86class CBitDecoder: public CBitModel<numMoveBits>
87{
88public:
89  UInt32 Decode(CDecoder *decoder)
90  {
91    UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
92    if (decoder->Code < newBound)
93    {
94      decoder->Range = newBound;
95      this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
96      if (decoder->Range < kTopValue)
97      {
98        decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
99        decoder->Range <<= 8;
100      }
101      return 0;
102    }
103    else
104    {
105      decoder->Range -= newBound;
106      decoder->Code -= newBound;
107      this->Prob -= (this->Prob) >> numMoveBits;
108      if (decoder->Range < kTopValue)
109      {
110        decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
111        decoder->Range <<= 8;
112      }
113      return 1;
114    }
115  }
116};
117
118}}
119
120#endif
121