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