xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/BitlDecoder.h (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // BitlDecoder.h -- the Least Significant Bit of byte is First
2 
3 #ifndef ZIP7_INC_BITL_DECODER_H
4 #define ZIP7_INC_BITL_DECODER_H
5 
6 #include "../../../C/CpuArch.h"
7 
8 #include "../IStream.h"
9 
10 namespace NBitl {
11 
12 const unsigned kNumBigValueBits = 8 * 4;
13 const unsigned kNumValueBytes = 3;
14 const unsigned kNumValueBits = 8 * kNumValueBytes;
15 const UInt32 kMask = (1 << kNumValueBits) - 1;
16 
17 #if !defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
18 #if 1 && defined(MY_CPU_ARM_OR_ARM64) \
19     && (defined(MY_CPU_ARM64) || defined(__ARM_ARCH_6T2__) \
20        || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \
21     && (defined(__GNUC__) && (__GNUC__ >= 4) \
22        || defined(__clang__) && (__clang_major__ >= 4))
23   #define Z7_BITL_USE_REVERSE_BITS_INSTRUCTION
24 #elif 1
25   #define Z7_BITL_USE_REVERSE_BITS_TABLE
26 #endif
27 #endif
28 
29 #if defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
30 extern Byte kReverseTable[256];
31 #endif
32 
ReverseBits8(unsigned i)33 inline unsigned ReverseBits8(unsigned i)
34 {
35 #if defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
36   return kReverseTable[i];
37 #elif defined(Z7_BITL_USE_REVERSE_BITS_INSTRUCTION)
38   // rbit is available in ARMv6T2 and above
39   asm ("rbit "
40 #if defined(MY_CPU_ARM)
41     "%0,%0"   // it uses default register size,
42               // but we need 32-bit register here.
43               // we must use it only if default register size is 32-bit.
44               // it will work incorrectly for ARM64.
45 #else
46     "%w0,%w0" // it uses 32-bit registers in ARM64.
47               // compiler for (MY_CPU_ARM) can't compile it.
48 #endif
49     : "+r" (i));
50   return i >> 24;
51 #else
52   unsigned
53       x = ((i & 0x55) << 1) | ((i >> 1) & 0x55);
54       x = ((x & 0x33) << 2) | ((x >> 2) & 0x33);
55   return  ((x & 0x0f) << 4) |  (x >> 4);
56 #endif
57 }
58 
59 
60 /* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream
61    TInByte::ReadByte() returns 0xFF after the end of stream
62    TInByte::NumExtraBytes contains the number "Extra Bytes"
63 
64    Bitl decoder can read up to 4 bytes ahead to internal buffer. */
65 
66 template<class TInByte>
67 class CBaseDecoder
68 {
69 protected:
70   unsigned _bitPos;
71   UInt32 _value;
72   TInByte _stream;
73 public:
Create(UInt32 bufSize)74   bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
SetStream(ISequentialInStream * inStream)75   void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); }
ClearStreamPtr()76   void ClearStreamPtr() { _stream.ClearStreamPtr(); }
Init()77   void Init()
78   {
79     _stream.Init();
80     _bitPos = kNumBigValueBits;
81     _value = 0;
82   }
83 
84   // the size of portion data in real stream that was already read from this object.
85   // it doesn't include unused data in BitStream object buffer (up to 4 bytes)
86   // it doesn't include unused data in TInByte buffers
87   // it doesn't include virtual Extra bytes after the end of real stream data
GetStreamSize()88   UInt64 GetStreamSize() const
89   {
90     return ExtraBitsWereRead() ?
91         _stream.GetStreamSize():
92         GetProcessedSize();
93   }
94 
95   // the size of virtual data that was read from this object.
GetProcessedSize()96   UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
97 
ThereAreDataInBitsBuffer()98   bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; }
99 
100   Z7_FORCE_INLINE
Normalize()101   void Normalize()
102   {
103     for (; _bitPos >= 8; _bitPos -= 8)
104       _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value;
105   }
106 
107   Z7_FORCE_INLINE
ReadBits(unsigned numBits)108   UInt32 ReadBits(unsigned numBits)
109   {
110     Normalize();
111     UInt32 res = _value & ((1 << numBits) - 1);
112     _bitPos += numBits;
113     _value >>= numBits;
114     return res;
115   }
116 
ExtraBitsWereRead()117   bool ExtraBitsWereRead() const
118   {
119     return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
120   }
121 
ExtraBitsWereRead_Fast()122   bool ExtraBitsWereRead_Fast() const
123   {
124     // full version is not inlined in vc6.
125     // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
126 
127     // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that
128     // it doesn't return true, if small number of extra bits were read.
129     return (_stream.NumExtraBytes > 4);
130   }
131 
132   // it must be fixed !!! with extra bits
133   // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; }
134 };
135 
136 template<class TInByte>
137 class CDecoder: public CBaseDecoder<TInByte>
138 {
139   UInt32 _normalValue;
140 
141 public:
Init()142   void Init()
143   {
144     CBaseDecoder<TInByte>::Init();
145     _normalValue = 0;
146   }
147 
148   Z7_FORCE_INLINE
Normalize()149   void Normalize()
150   {
151     for (; this->_bitPos >= 8; this->_bitPos -= 8)
152     {
153       const unsigned b = this->_stream.ReadByte();
154       _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue;
155       this->_value = (this->_value << 8) | ReverseBits8(b);
156     }
157   }
158 
159   Z7_FORCE_INLINE
GetValue(unsigned numBits)160   UInt32 GetValue(unsigned numBits)
161   {
162     Normalize();
163     return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
164   }
165 
166   Z7_FORCE_INLINE
GetValue_InHigh32bits()167   UInt32 GetValue_InHigh32bits()
168   {
169     Normalize();
170     return this->_value << this->_bitPos;
171   }
172 
173   Z7_FORCE_INLINE
MovePos(size_t numBits)174   void MovePos(size_t numBits)
175   {
176     this->_bitPos += (unsigned)numBits;
177     _normalValue >>= numBits;
178   }
179 
180   Z7_FORCE_INLINE
ReadBits(unsigned numBits)181   UInt32 ReadBits(unsigned numBits)
182   {
183     Normalize();
184     UInt32 res = _normalValue & ((1 << numBits) - 1);
185     MovePos(numBits);
186     return res;
187   }
188 
AlignToByte()189   void AlignToByte() { MovePos((32 - this->_bitPos) & 7); }
190 
191   Z7_FORCE_INLINE
ReadDirectByte()192   Byte ReadDirectByte() { return this->_stream.ReadByte(); }
193 
194   Z7_FORCE_INLINE
ReadDirectBytesPart(Byte * buf,size_t size)195   size_t ReadDirectBytesPart(Byte *buf, size_t size) { return this->_stream.ReadBytesPart(buf, size); }
196 
197   Z7_FORCE_INLINE
ReadAlignedByte()198   Byte ReadAlignedByte()
199   {
200     if (this->_bitPos == kNumBigValueBits)
201       return this->_stream.ReadByte();
202     Byte b = (Byte)(_normalValue & 0xFF);
203     MovePos(8);
204     return b;
205   }
206 
207   // call it only if the object is aligned for byte.
208   Z7_FORCE_INLINE
ReadAlignedByte_FromBuf(Byte & b)209   bool ReadAlignedByte_FromBuf(Byte &b)
210   {
211     if (this->_stream.NumExtraBytes != 0)
212       if (this->_stream.NumExtraBytes >= 4
213           || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3))
214         return false;
215     if (this->_bitPos == kNumBigValueBits)
216       return this->_stream.ReadByte_FromBuf(b);
217     b = (Byte)(_normalValue & 0xFF);
218     MovePos(8);
219     return true;
220   }
221 };
222 
223 }
224 
225 #endif
226