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