1// Compress/RangeCoderBit.h
2// 2009-05-30 : 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
9namespace NCompress {
10namespace NRangeCoder {
11
12const int kNumBitModelTotalBits  = 11;
13const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
14
15const int kNumMoveReducingBits = 4;
16
17const int kNumBitPriceShiftBits = 4;
18const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
19
20extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
21
22template <int numMoveBits>
23class CBitModel
24{
25public:
26  UInt32 Prob;
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  }
38public:
39  void Init() { Prob = kBitModelTotal / 2; }
40};
41
42template <int numMoveBits>
43class CBitEncoder: public CBitModel<numMoveBits>
44{
45public:
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  }
70  UInt32 GetPrice(UInt32 symbol) const
71  {
72    return ProbPrices[(this->Prob ^ ((-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
73  }
74  UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; }
75  UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; }
76};
77
78
79template <int numMoveBits>
80class CBitDecoder: public CBitModel<numMoveBits>
81{
82public:
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