xref: /linux/lib/zstd/common/bitstream.h (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1e0c1b49fSNick Terrell /* ******************************************************************
2e0c1b49fSNick Terrell  * bitstream
3e0c1b49fSNick Terrell  * Part of FSE library
4e0c1b49fSNick Terrell  * Copyright (c) Yann Collet, Facebook, Inc.
5e0c1b49fSNick Terrell  *
6e0c1b49fSNick Terrell  * You can contact the author at :
7e0c1b49fSNick Terrell  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
8e0c1b49fSNick Terrell  *
9e0c1b49fSNick Terrell  * This source code is licensed under both the BSD-style license (found in the
10e0c1b49fSNick Terrell  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
11e0c1b49fSNick Terrell  * in the COPYING file in the root directory of this source tree).
12e0c1b49fSNick Terrell  * You may select, at your option, one of the above-listed licenses.
13e0c1b49fSNick Terrell ****************************************************************** */
14e0c1b49fSNick Terrell #ifndef BITSTREAM_H_MODULE
15e0c1b49fSNick Terrell #define BITSTREAM_H_MODULE
16e0c1b49fSNick Terrell 
17e0c1b49fSNick Terrell /*
18e0c1b49fSNick Terrell *  This API consists of small unitary functions, which must be inlined for best performance.
19e0c1b49fSNick Terrell *  Since link-time-optimization is not available for all compilers,
20e0c1b49fSNick Terrell *  these functions are defined into a .h to be included.
21e0c1b49fSNick Terrell */
22e0c1b49fSNick Terrell 
23e0c1b49fSNick Terrell /*-****************************************
24e0c1b49fSNick Terrell *  Dependencies
25e0c1b49fSNick Terrell ******************************************/
26e0c1b49fSNick Terrell #include "mem.h"            /* unaligned access routines */
27e0c1b49fSNick Terrell #include "compiler.h"       /* UNLIKELY() */
28e0c1b49fSNick Terrell #include "debug.h"          /* assert(), DEBUGLOG(), RAWLOG() */
29e0c1b49fSNick Terrell #include "error_private.h"  /* error codes and messages */
30e0c1b49fSNick Terrell 
31e0c1b49fSNick Terrell 
32e0c1b49fSNick Terrell /*=========================================
33e0c1b49fSNick Terrell *  Target specific
34e0c1b49fSNick Terrell =========================================*/
35e0c1b49fSNick Terrell 
36e0c1b49fSNick Terrell #define STREAM_ACCUMULATOR_MIN_32  25
37e0c1b49fSNick Terrell #define STREAM_ACCUMULATOR_MIN_64  57
38e0c1b49fSNick Terrell #define STREAM_ACCUMULATOR_MIN    ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
39e0c1b49fSNick Terrell 
40e0c1b49fSNick Terrell 
41e0c1b49fSNick Terrell /*-******************************************
42e0c1b49fSNick Terrell *  bitStream encoding API (write forward)
43e0c1b49fSNick Terrell ********************************************/
44e0c1b49fSNick Terrell /* bitStream can mix input from multiple sources.
45e0c1b49fSNick Terrell  * A critical property of these streams is that they encode and decode in **reverse** direction.
46e0c1b49fSNick Terrell  * So the first bit sequence you add will be the last to be read, like a LIFO stack.
47e0c1b49fSNick Terrell  */
48e0c1b49fSNick Terrell typedef struct {
49e0c1b49fSNick Terrell     size_t bitContainer;
50e0c1b49fSNick Terrell     unsigned bitPos;
51e0c1b49fSNick Terrell     char*  startPtr;
52e0c1b49fSNick Terrell     char*  ptr;
53e0c1b49fSNick Terrell     char*  endPtr;
54e0c1b49fSNick Terrell } BIT_CStream_t;
55e0c1b49fSNick Terrell 
56e0c1b49fSNick Terrell MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
57e0c1b49fSNick Terrell MEM_STATIC void   BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
58e0c1b49fSNick Terrell MEM_STATIC void   BIT_flushBits(BIT_CStream_t* bitC);
59e0c1b49fSNick Terrell MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
60e0c1b49fSNick Terrell 
61e0c1b49fSNick Terrell /* Start with initCStream, providing the size of buffer to write into.
62e0c1b49fSNick Terrell *  bitStream will never write outside of this buffer.
63e0c1b49fSNick Terrell *  `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
64e0c1b49fSNick Terrell *
65e0c1b49fSNick Terrell *  bits are first added to a local register.
66e0c1b49fSNick Terrell *  Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
67e0c1b49fSNick Terrell *  Writing data into memory is an explicit operation, performed by the flushBits function.
68e0c1b49fSNick Terrell *  Hence keep track how many bits are potentially stored into local register to avoid register overflow.
69e0c1b49fSNick Terrell *  After a flushBits, a maximum of 7 bits might still be stored into local register.
70e0c1b49fSNick Terrell *
71e0c1b49fSNick Terrell *  Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
72e0c1b49fSNick Terrell *
73e0c1b49fSNick Terrell *  Last operation is to close the bitStream.
74e0c1b49fSNick Terrell *  The function returns the final size of CStream in bytes.
75e0c1b49fSNick Terrell *  If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
76e0c1b49fSNick Terrell */
77e0c1b49fSNick Terrell 
78e0c1b49fSNick Terrell 
79e0c1b49fSNick Terrell /*-********************************************
80e0c1b49fSNick Terrell *  bitStream decoding API (read backward)
81e0c1b49fSNick Terrell **********************************************/
82e0c1b49fSNick Terrell typedef struct {
83e0c1b49fSNick Terrell     size_t   bitContainer;
84e0c1b49fSNick Terrell     unsigned bitsConsumed;
85e0c1b49fSNick Terrell     const char* ptr;
86e0c1b49fSNick Terrell     const char* start;
87e0c1b49fSNick Terrell     const char* limitPtr;
88e0c1b49fSNick Terrell } BIT_DStream_t;
89e0c1b49fSNick Terrell 
90e0c1b49fSNick Terrell typedef enum { BIT_DStream_unfinished = 0,
91e0c1b49fSNick Terrell                BIT_DStream_endOfBuffer = 1,
92e0c1b49fSNick Terrell                BIT_DStream_completed = 2,
93e0c1b49fSNick Terrell                BIT_DStream_overflow = 3 } BIT_DStream_status;  /* result of BIT_reloadDStream() */
94e0c1b49fSNick Terrell                /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
95e0c1b49fSNick Terrell 
96e0c1b49fSNick Terrell MEM_STATIC size_t   BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
97e0c1b49fSNick Terrell MEM_STATIC size_t   BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
98e0c1b49fSNick Terrell MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
99e0c1b49fSNick Terrell MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
100e0c1b49fSNick Terrell 
101e0c1b49fSNick Terrell 
102e0c1b49fSNick Terrell /* Start by invoking BIT_initDStream().
103e0c1b49fSNick Terrell *  A chunk of the bitStream is then stored into a local register.
104e0c1b49fSNick Terrell *  Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
105e0c1b49fSNick Terrell *  You can then retrieve bitFields stored into the local register, **in reverse order**.
106e0c1b49fSNick Terrell *  Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
107e0c1b49fSNick Terrell *  A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
108e0c1b49fSNick Terrell *  Otherwise, it can be less than that, so proceed accordingly.
109e0c1b49fSNick Terrell *  Checking if DStream has reached its end can be performed with BIT_endOfDStream().
110e0c1b49fSNick Terrell */
111e0c1b49fSNick Terrell 
112e0c1b49fSNick Terrell 
113e0c1b49fSNick Terrell /*-****************************************
114e0c1b49fSNick Terrell *  unsafe API
115e0c1b49fSNick Terrell ******************************************/
116e0c1b49fSNick Terrell MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
117e0c1b49fSNick Terrell /* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
118e0c1b49fSNick Terrell 
119e0c1b49fSNick Terrell MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
120e0c1b49fSNick Terrell /* unsafe version; does not check buffer overflow */
121e0c1b49fSNick Terrell 
122e0c1b49fSNick Terrell MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
123e0c1b49fSNick Terrell /* faster, but works only if nbBits >= 1 */
124e0c1b49fSNick Terrell 
125e0c1b49fSNick Terrell 
126e0c1b49fSNick Terrell 
127e0c1b49fSNick Terrell /*-**************************************************************
128e0c1b49fSNick Terrell *  Internal functions
129e0c1b49fSNick Terrell ****************************************************************/
BIT_highbit32(U32 val)130e0c1b49fSNick Terrell MEM_STATIC unsigned BIT_highbit32 (U32 val)
131e0c1b49fSNick Terrell {
132e0c1b49fSNick Terrell     assert(val != 0);
133e0c1b49fSNick Terrell     {
134e0c1b49fSNick Terrell #   if (__GNUC__ >= 3)   /* Use GCC Intrinsic */
135e0c1b49fSNick Terrell         return __builtin_clz (val) ^ 31;
136e0c1b49fSNick Terrell #   else   /* Software version */
137e0c1b49fSNick Terrell         static const unsigned DeBruijnClz[32] = { 0,  9,  1, 10, 13, 21,  2, 29,
138e0c1b49fSNick Terrell                                                  11, 14, 16, 18, 22, 25,  3, 30,
139e0c1b49fSNick Terrell                                                   8, 12, 20, 28, 15, 17, 24,  7,
140e0c1b49fSNick Terrell                                                  19, 27, 23,  6, 26,  5,  4, 31 };
141e0c1b49fSNick Terrell         U32 v = val;
142e0c1b49fSNick Terrell         v |= v >> 1;
143e0c1b49fSNick Terrell         v |= v >> 2;
144e0c1b49fSNick Terrell         v |= v >> 4;
145e0c1b49fSNick Terrell         v |= v >> 8;
146e0c1b49fSNick Terrell         v |= v >> 16;
147e0c1b49fSNick Terrell         return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
148e0c1b49fSNick Terrell #   endif
149e0c1b49fSNick Terrell     }
150e0c1b49fSNick Terrell }
151e0c1b49fSNick Terrell 
152e0c1b49fSNick Terrell /*=====    Local Constants   =====*/
153e0c1b49fSNick Terrell static const unsigned BIT_mask[] = {
154e0c1b49fSNick Terrell     0,          1,         3,         7,         0xF,       0x1F,
155e0c1b49fSNick Terrell     0x3F,       0x7F,      0xFF,      0x1FF,     0x3FF,     0x7FF,
156e0c1b49fSNick Terrell     0xFFF,      0x1FFF,    0x3FFF,    0x7FFF,    0xFFFF,    0x1FFFF,
157e0c1b49fSNick Terrell     0x3FFFF,    0x7FFFF,   0xFFFFF,   0x1FFFFF,  0x3FFFFF,  0x7FFFFF,
158e0c1b49fSNick Terrell     0xFFFFFF,   0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
159e0c1b49fSNick Terrell     0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
160e0c1b49fSNick Terrell #define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
161e0c1b49fSNick Terrell 
162e0c1b49fSNick Terrell /*-**************************************************************
163e0c1b49fSNick Terrell *  bitStream encoding
164e0c1b49fSNick Terrell ****************************************************************/
165e0c1b49fSNick Terrell /*! BIT_initCStream() :
166e0c1b49fSNick Terrell  *  `dstCapacity` must be > sizeof(size_t)
167e0c1b49fSNick Terrell  *  @return : 0 if success,
168e0c1b49fSNick Terrell  *            otherwise an error code (can be tested using ERR_isError()) */
BIT_initCStream(BIT_CStream_t * bitC,void * startPtr,size_t dstCapacity)169e0c1b49fSNick Terrell MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
170e0c1b49fSNick Terrell                                   void* startPtr, size_t dstCapacity)
171e0c1b49fSNick Terrell {
172e0c1b49fSNick Terrell     bitC->bitContainer = 0;
173e0c1b49fSNick Terrell     bitC->bitPos = 0;
174e0c1b49fSNick Terrell     bitC->startPtr = (char*)startPtr;
175e0c1b49fSNick Terrell     bitC->ptr = bitC->startPtr;
176e0c1b49fSNick Terrell     bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
177e0c1b49fSNick Terrell     if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
178e0c1b49fSNick Terrell     return 0;
179e0c1b49fSNick Terrell }
180e0c1b49fSNick Terrell 
181e0c1b49fSNick Terrell /*! BIT_addBits() :
182e0c1b49fSNick Terrell  *  can add up to 31 bits into `bitC`.
183e0c1b49fSNick Terrell  *  Note : does not check for register overflow ! */
BIT_addBits(BIT_CStream_t * bitC,size_t value,unsigned nbBits)184e0c1b49fSNick Terrell MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
185e0c1b49fSNick Terrell                             size_t value, unsigned nbBits)
186e0c1b49fSNick Terrell {
187e0c1b49fSNick Terrell     DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
188e0c1b49fSNick Terrell     assert(nbBits < BIT_MASK_SIZE);
189e0c1b49fSNick Terrell     assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
190e0c1b49fSNick Terrell     bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
191e0c1b49fSNick Terrell     bitC->bitPos += nbBits;
192e0c1b49fSNick Terrell }
193e0c1b49fSNick Terrell 
194e0c1b49fSNick Terrell /*! BIT_addBitsFast() :
195e0c1b49fSNick Terrell  *  works only if `value` is _clean_,
196e0c1b49fSNick Terrell  *  meaning all high bits above nbBits are 0 */
BIT_addBitsFast(BIT_CStream_t * bitC,size_t value,unsigned nbBits)197e0c1b49fSNick Terrell MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
198e0c1b49fSNick Terrell                                 size_t value, unsigned nbBits)
199e0c1b49fSNick Terrell {
200e0c1b49fSNick Terrell     assert((value>>nbBits) == 0);
201e0c1b49fSNick Terrell     assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
202e0c1b49fSNick Terrell     bitC->bitContainer |= value << bitC->bitPos;
203e0c1b49fSNick Terrell     bitC->bitPos += nbBits;
204e0c1b49fSNick Terrell }
205e0c1b49fSNick Terrell 
206e0c1b49fSNick Terrell /*! BIT_flushBitsFast() :
207e0c1b49fSNick Terrell  *  assumption : bitContainer has not overflowed
208e0c1b49fSNick Terrell  *  unsafe version; does not check buffer overflow */
BIT_flushBitsFast(BIT_CStream_t * bitC)209e0c1b49fSNick Terrell MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
210e0c1b49fSNick Terrell {
211e0c1b49fSNick Terrell     size_t const nbBytes = bitC->bitPos >> 3;
212e0c1b49fSNick Terrell     assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
213e0c1b49fSNick Terrell     assert(bitC->ptr <= bitC->endPtr);
214e0c1b49fSNick Terrell     MEM_writeLEST(bitC->ptr, bitC->bitContainer);
215e0c1b49fSNick Terrell     bitC->ptr += nbBytes;
216e0c1b49fSNick Terrell     bitC->bitPos &= 7;
217e0c1b49fSNick Terrell     bitC->bitContainer >>= nbBytes*8;
218e0c1b49fSNick Terrell }
219e0c1b49fSNick Terrell 
220e0c1b49fSNick Terrell /*! BIT_flushBits() :
221e0c1b49fSNick Terrell  *  assumption : bitContainer has not overflowed
222e0c1b49fSNick Terrell  *  safe version; check for buffer overflow, and prevents it.
223e0c1b49fSNick Terrell  *  note : does not signal buffer overflow.
224e0c1b49fSNick Terrell  *  overflow will be revealed later on using BIT_closeCStream() */
BIT_flushBits(BIT_CStream_t * bitC)225e0c1b49fSNick Terrell MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
226e0c1b49fSNick Terrell {
227e0c1b49fSNick Terrell     size_t const nbBytes = bitC->bitPos >> 3;
228e0c1b49fSNick Terrell     assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
229e0c1b49fSNick Terrell     assert(bitC->ptr <= bitC->endPtr);
230e0c1b49fSNick Terrell     MEM_writeLEST(bitC->ptr, bitC->bitContainer);
231e0c1b49fSNick Terrell     bitC->ptr += nbBytes;
232e0c1b49fSNick Terrell     if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
233e0c1b49fSNick Terrell     bitC->bitPos &= 7;
234e0c1b49fSNick Terrell     bitC->bitContainer >>= nbBytes*8;
235e0c1b49fSNick Terrell }
236e0c1b49fSNick Terrell 
237e0c1b49fSNick Terrell /*! BIT_closeCStream() :
238e0c1b49fSNick Terrell  *  @return : size of CStream, in bytes,
239e0c1b49fSNick Terrell  *            or 0 if it could not fit into dstBuffer */
BIT_closeCStream(BIT_CStream_t * bitC)240e0c1b49fSNick Terrell MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
241e0c1b49fSNick Terrell {
242e0c1b49fSNick Terrell     BIT_addBitsFast(bitC, 1, 1);   /* endMark */
243e0c1b49fSNick Terrell     BIT_flushBits(bitC);
244e0c1b49fSNick Terrell     if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
245e0c1b49fSNick Terrell     return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
246e0c1b49fSNick Terrell }
247e0c1b49fSNick Terrell 
248e0c1b49fSNick Terrell 
249e0c1b49fSNick Terrell /*-********************************************************
250e0c1b49fSNick Terrell *  bitStream decoding
251e0c1b49fSNick Terrell **********************************************************/
252e0c1b49fSNick Terrell /*! BIT_initDStream() :
253e0c1b49fSNick Terrell  *  Initialize a BIT_DStream_t.
254e0c1b49fSNick Terrell  * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
255e0c1b49fSNick Terrell  * `srcSize` must be the *exact* size of the bitStream, in bytes.
256e0c1b49fSNick Terrell  * @return : size of stream (== srcSize), or an errorCode if a problem is detected
257e0c1b49fSNick Terrell  */
BIT_initDStream(BIT_DStream_t * bitD,const void * srcBuffer,size_t srcSize)258e0c1b49fSNick Terrell MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
259e0c1b49fSNick Terrell {
260e0c1b49fSNick Terrell     if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
261e0c1b49fSNick Terrell 
262e0c1b49fSNick Terrell     bitD->start = (const char*)srcBuffer;
263e0c1b49fSNick Terrell     bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
264e0c1b49fSNick Terrell 
265e0c1b49fSNick Terrell     if (srcSize >=  sizeof(bitD->bitContainer)) {  /* normal case */
266e0c1b49fSNick Terrell         bitD->ptr   = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
267e0c1b49fSNick Terrell         bitD->bitContainer = MEM_readLEST(bitD->ptr);
268e0c1b49fSNick Terrell         { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
269e0c1b49fSNick Terrell           bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;  /* ensures bitsConsumed is always set */
270e0c1b49fSNick Terrell           if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
271e0c1b49fSNick Terrell     } else {
272e0c1b49fSNick Terrell         bitD->ptr   = bitD->start;
273e0c1b49fSNick Terrell         bitD->bitContainer = *(const BYTE*)(bitD->start);
274e0c1b49fSNick Terrell         switch(srcSize)
275e0c1b49fSNick Terrell         {
276e0c1b49fSNick Terrell         case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
277e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
278e0c1b49fSNick Terrell 
279e0c1b49fSNick Terrell         case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
280e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
281e0c1b49fSNick Terrell 
282e0c1b49fSNick Terrell         case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
283e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
284e0c1b49fSNick Terrell 
285e0c1b49fSNick Terrell         case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
286e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
287e0c1b49fSNick Terrell 
288e0c1b49fSNick Terrell         case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
289e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
290e0c1b49fSNick Terrell 
291e0c1b49fSNick Terrell         case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) <<  8;
292e0c1b49fSNick Terrell                 ZSTD_FALLTHROUGH;
293e0c1b49fSNick Terrell 
294e0c1b49fSNick Terrell         default: break;
295e0c1b49fSNick Terrell         }
296e0c1b49fSNick Terrell         {   BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
297e0c1b49fSNick Terrell             bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
298e0c1b49fSNick Terrell             if (lastByte == 0) return ERROR(corruption_detected);  /* endMark not present */
299e0c1b49fSNick Terrell         }
300e0c1b49fSNick Terrell         bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
301e0c1b49fSNick Terrell     }
302e0c1b49fSNick Terrell 
303e0c1b49fSNick Terrell     return srcSize;
304e0c1b49fSNick Terrell }
305e0c1b49fSNick Terrell 
BIT_getUpperBits(size_t bitContainer,U32 const start)306e0c1b49fSNick Terrell MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
307e0c1b49fSNick Terrell {
308e0c1b49fSNick Terrell     return bitContainer >> start;
309e0c1b49fSNick Terrell }
310e0c1b49fSNick Terrell 
BIT_getMiddleBits(size_t bitContainer,U32 const start,U32 const nbBits)311e0c1b49fSNick Terrell MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
312e0c1b49fSNick Terrell {
313e0c1b49fSNick Terrell     U32 const regMask = sizeof(bitContainer)*8 - 1;
314e0c1b49fSNick Terrell     /* if start > regMask, bitstream is corrupted, and result is undefined */
315e0c1b49fSNick Terrell     assert(nbBits < BIT_MASK_SIZE);
316*2aa14b1aSNick Terrell     /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better
317*2aa14b1aSNick Terrell      * than accessing memory. When bmi2 instruction is not present, we consider
318*2aa14b1aSNick Terrell      * such cpus old (pre-Haswell, 2013) and their performance is not of that
319*2aa14b1aSNick Terrell      * importance.
320*2aa14b1aSNick Terrell      */
321*2aa14b1aSNick Terrell #if defined(__x86_64__) || defined(_M_X86)
322*2aa14b1aSNick Terrell     return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1);
323*2aa14b1aSNick Terrell #else
324e0c1b49fSNick Terrell     return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
325*2aa14b1aSNick Terrell #endif
326e0c1b49fSNick Terrell }
327e0c1b49fSNick Terrell 
BIT_getLowerBits(size_t bitContainer,U32 const nbBits)328e0c1b49fSNick Terrell MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
329e0c1b49fSNick Terrell {
330e0c1b49fSNick Terrell     assert(nbBits < BIT_MASK_SIZE);
331e0c1b49fSNick Terrell     return bitContainer & BIT_mask[nbBits];
332e0c1b49fSNick Terrell }
333e0c1b49fSNick Terrell 
334e0c1b49fSNick Terrell /*! BIT_lookBits() :
335e0c1b49fSNick Terrell  *  Provides next n bits from local register.
336e0c1b49fSNick Terrell  *  local register is not modified.
337e0c1b49fSNick Terrell  *  On 32-bits, maxNbBits==24.
338e0c1b49fSNick Terrell  *  On 64-bits, maxNbBits==56.
339e0c1b49fSNick Terrell  * @return : value extracted */
BIT_lookBits(const BIT_DStream_t * bitD,U32 nbBits)340e0c1b49fSNick Terrell MEM_STATIC  FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t*  bitD, U32 nbBits)
341e0c1b49fSNick Terrell {
342e0c1b49fSNick Terrell     /* arbitrate between double-shift and shift+mask */
343e0c1b49fSNick Terrell #if 1
344e0c1b49fSNick Terrell     /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
345e0c1b49fSNick Terrell      * bitstream is likely corrupted, and result is undefined */
346e0c1b49fSNick Terrell     return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
347e0c1b49fSNick Terrell #else
348e0c1b49fSNick Terrell     /* this code path is slower on my os-x laptop */
349e0c1b49fSNick Terrell     U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
350e0c1b49fSNick Terrell     return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
351e0c1b49fSNick Terrell #endif
352e0c1b49fSNick Terrell }
353e0c1b49fSNick Terrell 
354e0c1b49fSNick Terrell /*! BIT_lookBitsFast() :
355e0c1b49fSNick Terrell  *  unsafe version; only works if nbBits >= 1 */
BIT_lookBitsFast(const BIT_DStream_t * bitD,U32 nbBits)356e0c1b49fSNick Terrell MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
357e0c1b49fSNick Terrell {
358e0c1b49fSNick Terrell     U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
359e0c1b49fSNick Terrell     assert(nbBits >= 1);
360e0c1b49fSNick Terrell     return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
361e0c1b49fSNick Terrell }
362e0c1b49fSNick Terrell 
BIT_skipBits(BIT_DStream_t * bitD,U32 nbBits)363e0c1b49fSNick Terrell MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
364e0c1b49fSNick Terrell {
365e0c1b49fSNick Terrell     bitD->bitsConsumed += nbBits;
366e0c1b49fSNick Terrell }
367e0c1b49fSNick Terrell 
368e0c1b49fSNick Terrell /*! BIT_readBits() :
369e0c1b49fSNick Terrell  *  Read (consume) next n bits from local register and update.
370e0c1b49fSNick Terrell  *  Pay attention to not read more than nbBits contained into local register.
371e0c1b49fSNick Terrell  * @return : extracted value. */
BIT_readBits(BIT_DStream_t * bitD,unsigned nbBits)372e0c1b49fSNick Terrell MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
373e0c1b49fSNick Terrell {
374e0c1b49fSNick Terrell     size_t const value = BIT_lookBits(bitD, nbBits);
375e0c1b49fSNick Terrell     BIT_skipBits(bitD, nbBits);
376e0c1b49fSNick Terrell     return value;
377e0c1b49fSNick Terrell }
378e0c1b49fSNick Terrell 
379e0c1b49fSNick Terrell /*! BIT_readBitsFast() :
380e0c1b49fSNick Terrell  *  unsafe version; only works only if nbBits >= 1 */
BIT_readBitsFast(BIT_DStream_t * bitD,unsigned nbBits)381e0c1b49fSNick Terrell MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
382e0c1b49fSNick Terrell {
383e0c1b49fSNick Terrell     size_t const value = BIT_lookBitsFast(bitD, nbBits);
384e0c1b49fSNick Terrell     assert(nbBits >= 1);
385e0c1b49fSNick Terrell     BIT_skipBits(bitD, nbBits);
386e0c1b49fSNick Terrell     return value;
387e0c1b49fSNick Terrell }
388e0c1b49fSNick Terrell 
389e0c1b49fSNick Terrell /*! BIT_reloadDStreamFast() :
390e0c1b49fSNick Terrell  *  Similar to BIT_reloadDStream(), but with two differences:
391e0c1b49fSNick Terrell  *  1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
392e0c1b49fSNick Terrell  *  2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
393e0c1b49fSNick Terrell  *     point you must use BIT_reloadDStream() to reload.
394e0c1b49fSNick Terrell  */
BIT_reloadDStreamFast(BIT_DStream_t * bitD)395e0c1b49fSNick Terrell MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
396e0c1b49fSNick Terrell {
397e0c1b49fSNick Terrell     if (UNLIKELY(bitD->ptr < bitD->limitPtr))
398e0c1b49fSNick Terrell         return BIT_DStream_overflow;
399e0c1b49fSNick Terrell     assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
400e0c1b49fSNick Terrell     bitD->ptr -= bitD->bitsConsumed >> 3;
401e0c1b49fSNick Terrell     bitD->bitsConsumed &= 7;
402e0c1b49fSNick Terrell     bitD->bitContainer = MEM_readLEST(bitD->ptr);
403e0c1b49fSNick Terrell     return BIT_DStream_unfinished;
404e0c1b49fSNick Terrell }
405e0c1b49fSNick Terrell 
406e0c1b49fSNick Terrell /*! BIT_reloadDStream() :
407e0c1b49fSNick Terrell  *  Refill `bitD` from buffer previously set in BIT_initDStream() .
408e0c1b49fSNick Terrell  *  This function is safe, it guarantees it will not read beyond src buffer.
409e0c1b49fSNick Terrell  * @return : status of `BIT_DStream_t` internal register.
410e0c1b49fSNick Terrell  *           when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
BIT_reloadDStream(BIT_DStream_t * bitD)411e0c1b49fSNick Terrell MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
412e0c1b49fSNick Terrell {
413e0c1b49fSNick Terrell     if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))  /* overflow detected, like end of stream */
414e0c1b49fSNick Terrell         return BIT_DStream_overflow;
415e0c1b49fSNick Terrell 
416e0c1b49fSNick Terrell     if (bitD->ptr >= bitD->limitPtr) {
417e0c1b49fSNick Terrell         return BIT_reloadDStreamFast(bitD);
418e0c1b49fSNick Terrell     }
419e0c1b49fSNick Terrell     if (bitD->ptr == bitD->start) {
420e0c1b49fSNick Terrell         if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
421e0c1b49fSNick Terrell         return BIT_DStream_completed;
422e0c1b49fSNick Terrell     }
423e0c1b49fSNick Terrell     /* start < ptr < limitPtr */
424e0c1b49fSNick Terrell     {   U32 nbBytes = bitD->bitsConsumed >> 3;
425e0c1b49fSNick Terrell         BIT_DStream_status result = BIT_DStream_unfinished;
426e0c1b49fSNick Terrell         if (bitD->ptr - nbBytes < bitD->start) {
427e0c1b49fSNick Terrell             nbBytes = (U32)(bitD->ptr - bitD->start);  /* ptr > start */
428e0c1b49fSNick Terrell             result = BIT_DStream_endOfBuffer;
429e0c1b49fSNick Terrell         }
430e0c1b49fSNick Terrell         bitD->ptr -= nbBytes;
431e0c1b49fSNick Terrell         bitD->bitsConsumed -= nbBytes*8;
432e0c1b49fSNick Terrell         bitD->bitContainer = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
433e0c1b49fSNick Terrell         return result;
434e0c1b49fSNick Terrell     }
435e0c1b49fSNick Terrell }
436e0c1b49fSNick Terrell 
437e0c1b49fSNick Terrell /*! BIT_endOfDStream() :
438e0c1b49fSNick Terrell  * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
439e0c1b49fSNick Terrell  */
BIT_endOfDStream(const BIT_DStream_t * DStream)440e0c1b49fSNick Terrell MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
441e0c1b49fSNick Terrell {
442e0c1b49fSNick Terrell     return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
443e0c1b49fSNick Terrell }
444e0c1b49fSNick Terrell 
445e0c1b49fSNick Terrell 
446e0c1b49fSNick Terrell #endif /* BITSTREAM_H_MODULE */
447