-
Notifications
You must be signed in to change notification settings - Fork 22
/
range_enc.h
162 lines (137 loc) · 3.77 KB
/
range_enc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
* Bitwise range encoder by Igor Pavlov
* Modified by Conor McCarthy
*
* Public domain
*/
#ifndef RANGE_ENCODER_H
#define RANGE_ENCODER_H
#include "mem.h"
#include "compiler.h"
#if defined (__cplusplus)
extern "C" {
#endif
#ifdef LZMA_ENC_PROB32
typedef U32 LZMA2_prob;
#else
typedef U16 LZMA2_prob;
#endif
#define kNumTopBits 24U
#define kTopValue (1UL << kNumTopBits)
#define kNumBitModelTotalBits 11U
#define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5U
#define kProbInitValue (kBitModelTotal >> 1U)
#define kNumMoveReducingBits 4U
#define kNumBitPriceShiftBits 5U
#define kPriceTableSize (kBitModelTotal >> kNumMoveReducingBits)
extern BYTE price_table[2][kPriceTableSize];
#if 0
void RC_printPriceTable();
#endif
typedef struct
{
BYTE *out_buffer;
size_t out_index;
U64 cache_size;
U64 low;
U32 range;
BYTE cache;
} RC_encoder;
void RC_reset(RC_encoder* const rc);
void RC_setOutputBuffer(RC_encoder* const rc, BYTE *const out_buffer);
void FORCE_NOINLINE RC_shiftLow(RC_encoder* const rc);
void RC_encodeBitTree(RC_encoder* const rc, LZMA2_prob *const probs, unsigned bit_count, unsigned symbol);
void RC_encodeBitTreeReverse(RC_encoder* const rc, LZMA2_prob *const probs, unsigned bit_count, unsigned symbol);
void FORCE_NOINLINE RC_encodeDirect(RC_encoder* const rc, unsigned value, unsigned bit_count);
HINT_INLINE
void RC_encodeBit0(RC_encoder* const rc, LZMA2_prob *const rprob)
{
unsigned prob = *rprob;
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
prob += (kBitModelTotal - prob) >> kNumMoveBits;
*rprob = (LZMA2_prob)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
RC_shiftLow(rc);
}
}
HINT_INLINE
void RC_encodeBit1(RC_encoder* const rc, LZMA2_prob *const rprob)
{
unsigned prob = *rprob;
U32 new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
rc->low += new_bound;
rc->range -= new_bound;
prob -= prob >> kNumMoveBits;
*rprob = (LZMA2_prob)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
RC_shiftLow(rc);
}
}
HINT_INLINE
void RC_encodeBit(RC_encoder* const rc, LZMA2_prob *const rprob, unsigned const bit)
{
unsigned prob = *rprob;
if (bit != 0) {
U32 const new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
rc->low += new_bound;
rc->range -= new_bound;
prob -= prob >> kNumMoveBits;
}
else {
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
prob += (kBitModelTotal - prob) >> kNumMoveBits;
}
*rprob = (LZMA2_prob)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
RC_shiftLow(rc);
}
}
#define GET_PRICE(prob, symbol) \
price_table[symbol][(prob) >> kNumMoveReducingBits]
#define GET_PRICE_0(prob) price_table[0][(prob) >> kNumMoveReducingBits]
#define GET_PRICE_1(prob) price_table[1][(prob) >> kNumMoveReducingBits]
#define kMinLitPrice 8U
HINT_INLINE
unsigned RC_getTreePrice(const LZMA2_prob* const prob_table, unsigned bit_count, size_t symbol)
{
unsigned price = 0;
symbol |= ((size_t)1 << bit_count);
do {
size_t const next_symbol = symbol >> 1;
unsigned prob = prob_table[next_symbol];
size_t bit = symbol & 1;
price += GET_PRICE(prob, bit);
symbol = next_symbol;
} while (symbol != 1);
return price;
}
HINT_INLINE
unsigned RC_getReverseTreePrice(const LZMA2_prob* const prob_table, unsigned bit_count, size_t symbol)
{
unsigned prob = prob_table[1];
size_t bit = symbol & 1;
unsigned price = GET_PRICE(prob, bit);
size_t m = 1;
while (--bit_count != 0) {
m = (m << 1) | bit;
symbol >>= 1;
prob = prob_table[m];
bit = symbol & 1;
price += GET_PRICE(prob, bit);
}
return price;
}
HINT_INLINE
void RC_flush(RC_encoder* const rc)
{
for (int i = 0; i < 5; ++i)
RC_shiftLow(rc);
}
#if defined (__cplusplus)
}
#endif
#endif /* RANGE_ENCODER_H */