@@ -90,19 +90,20 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
90
90
/*-********************************************
91
91
* bitStream decoding API (read backward)
92
92
**********************************************/
93
+ typedef size_t BitContainerType ;
93
94
typedef struct {
94
- size_t bitContainer ;
95
+ BitContainerType bitContainer ;
95
96
unsigned bitsConsumed ;
96
97
const char * ptr ;
97
98
const char * start ;
98
99
const char * limitPtr ;
99
100
} BIT_DStream_t ;
100
101
101
- typedef enum { BIT_DStream_unfinished = 0 ,
102
- BIT_DStream_endOfBuffer = 1 ,
103
- BIT_DStream_completed = 2 ,
104
- BIT_DStream_overflow = 3 } BIT_DStream_status ; /* result of BIT_reloadDStream() */
105
- /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
102
+ typedef enum { BIT_DStream_unfinished = 0 , /* fully refilled */
103
+ BIT_DStream_endOfBuffer = 1 , /* still some bits left in bitstream */
104
+ BIT_DStream_completed = 2 , /* bitstream entirely consumed, bit-exact */
105
+ BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */
106
+ } BIT_DStream_status ; /* result of BIT_reloadDStream() */
106
107
107
108
MEM_STATIC size_t BIT_initDStream (BIT_DStream_t * bitD , const void * srcBuffer , size_t srcSize );
108
109
MEM_STATIC size_t BIT_readBits (BIT_DStream_t * bitD , unsigned nbBits );
@@ -112,7 +113,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
112
113
113
114
/* Start by invoking BIT_initDStream().
114
115
* A chunk of the bitStream is then stored into a local register.
115
- * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t ).
116
+ * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType ).
116
117
* You can then retrieve bitFields stored into the local register, **in reverse order**.
117
118
* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
118
119
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
@@ -162,7 +163,7 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
162
163
return 0 ;
163
164
}
164
165
165
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits (size_t bitContainer , U32 const nbBits )
166
+ FORCE_INLINE_TEMPLATE size_t BIT_getLowerBits (size_t bitContainer , U32 const nbBits )
166
167
{
167
168
#if defined(STATIC_BMI2 ) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS )
168
169
return _bzhi_u64 (bitContainer , nbBits );
@@ -267,22 +268,22 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
267
268
bitD -> bitContainer = * (const BYTE * )(bitD -> start );
268
269
switch (srcSize )
269
270
{
270
- case 7 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[6 ]) << (sizeof (bitD -> bitContainer )* 8 - 16 );
271
+ case 7 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[6 ]) << (sizeof (bitD -> bitContainer )* 8 - 16 );
271
272
ZSTD_FALLTHROUGH ;
272
273
273
- case 6 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[5 ]) << (sizeof (bitD -> bitContainer )* 8 - 24 );
274
+ case 6 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[5 ]) << (sizeof (bitD -> bitContainer )* 8 - 24 );
274
275
ZSTD_FALLTHROUGH ;
275
276
276
- case 5 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[4 ]) << (sizeof (bitD -> bitContainer )* 8 - 32 );
277
+ case 5 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[4 ]) << (sizeof (bitD -> bitContainer )* 8 - 32 );
277
278
ZSTD_FALLTHROUGH ;
278
279
279
- case 4 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[3 ]) << 24 ;
280
+ case 4 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[3 ]) << 24 ;
280
281
ZSTD_FALLTHROUGH ;
281
282
282
- case 3 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[2 ]) << 16 ;
283
+ case 3 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[2 ]) << 16 ;
283
284
ZSTD_FALLTHROUGH ;
284
285
285
- case 2 : bitD -> bitContainer += (size_t )(((const BYTE * )(srcBuffer ))[1 ]) << 8 ;
286
+ case 2 : bitD -> bitContainer += (BitContainerType )(((const BYTE * )(srcBuffer ))[1 ]) << 8 ;
286
287
ZSTD_FALLTHROUGH ;
287
288
288
289
default : break ;
@@ -297,12 +298,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
297
298
return srcSize ;
298
299
}
299
300
300
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits (size_t bitContainer , U32 const start )
301
+ FORCE_INLINE_TEMPLATE size_t BIT_getUpperBits (BitContainerType bitContainer , U32 const start )
301
302
{
302
303
return bitContainer >> start ;
303
304
}
304
305
305
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits (size_t bitContainer , U32 const start , U32 const nbBits )
306
+ FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits (BitContainerType bitContainer , U32 const start , U32 const nbBits )
306
307
{
307
308
U32 const regMask = sizeof (bitContainer )* 8 - 1 ;
308
309
/* if start > regMask, bitstream is corrupted, and result is undefined */
@@ -325,7 +326,7 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 c
325
326
* On 32-bits, maxNbBits==24.
326
327
* On 64-bits, maxNbBits==56.
327
328
* @return : value extracted */
328
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits (const BIT_DStream_t * bitD , U32 nbBits )
329
+ FORCE_INLINE_TEMPLATE size_t BIT_lookBits (const BIT_DStream_t * bitD , U32 nbBits )
329
330
{
330
331
/* arbitrate between double-shift and shift+mask */
331
332
#if 1
@@ -348,7 +349,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
348
349
return (bitD -> bitContainer << (bitD -> bitsConsumed & regMask )) >> (((regMask + 1 )- nbBits ) & regMask );
349
350
}
350
351
351
- MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits (BIT_DStream_t * bitD , U32 nbBits )
352
+ FORCE_INLINE_TEMPLATE void BIT_skipBits (BIT_DStream_t * bitD , U32 nbBits )
352
353
{
353
354
bitD -> bitsConsumed += nbBits ;
354
355
}
@@ -357,7 +358,7 @@ MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
357
358
* Read (consume) next n bits from local register and update.
358
359
* Pay attention to not read more than nbBits contained into local register.
359
360
* @return : extracted value. */
360
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits (BIT_DStream_t * bitD , unsigned nbBits )
361
+ FORCE_INLINE_TEMPLATE size_t BIT_readBits (BIT_DStream_t * bitD , unsigned nbBits )
361
362
{
362
363
size_t const value = BIT_lookBits (bitD , nbBits );
363
364
BIT_skipBits (bitD , nbBits );
@@ -374,6 +375,21 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
374
375
return value ;
375
376
}
376
377
378
+ /*! BIT_reloadDStream_internal() :
379
+ * Simple variant of BIT_reloadDStream(), with two conditions:
380
+ * 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8
381
+ * 2. look window is valid after shifted down : bitD->ptr >= bitD->start
382
+ */
383
+ MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal (BIT_DStream_t * bitD )
384
+ {
385
+ assert (bitD -> bitsConsumed <= sizeof (bitD -> bitContainer )* 8 );
386
+ bitD -> ptr -= bitD -> bitsConsumed >> 3 ;
387
+ assert (bitD -> ptr >= bitD -> start );
388
+ bitD -> bitsConsumed &= 7 ;
389
+ bitD -> bitContainer = MEM_readLEST (bitD -> ptr );
390
+ return BIT_DStream_unfinished ;
391
+ }
392
+
377
393
/*! BIT_reloadDStreamFast() :
378
394
* Similar to BIT_reloadDStream(), but with two differences:
379
395
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
@@ -384,31 +400,35 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
384
400
{
385
401
if (UNLIKELY (bitD -> ptr < bitD -> limitPtr ))
386
402
return BIT_DStream_overflow ;
387
- assert (bitD -> bitsConsumed <= sizeof (bitD -> bitContainer )* 8 );
388
- bitD -> ptr -= bitD -> bitsConsumed >> 3 ;
389
- bitD -> bitsConsumed &= 7 ;
390
- bitD -> bitContainer = MEM_readLEST (bitD -> ptr );
391
- return BIT_DStream_unfinished ;
403
+ return BIT_reloadDStream_internal (bitD );
392
404
}
393
405
394
406
/*! BIT_reloadDStream() :
395
407
* Refill `bitD` from buffer previously set in BIT_initDStream() .
396
- * This function is safe, it guarantees it will not read beyond src buffer.
408
+ * This function is safe, it guarantees it will not never beyond src buffer.
397
409
* @return : status of `BIT_DStream_t` internal register.
398
410
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
399
- MEM_STATIC FORCE_INLINE_ATTR BIT_DStream_status BIT_reloadDStream (BIT_DStream_t * bitD )
411
+ FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream (BIT_DStream_t * bitD )
400
412
{
401
- if (bitD -> bitsConsumed > (sizeof (bitD -> bitContainer )* 8 )) /* overflow detected, like end of stream */
413
+ /* note : once in overflow mode, a bitstream remains in this mode until it's reset */
414
+ if (UNLIKELY (bitD -> bitsConsumed > (sizeof (bitD -> bitContainer )* 8 ))) {
415
+ static const BitContainerType zeroFilled = 0 ;
416
+ bitD -> ptr = (const char * )& zeroFilled ; /* aliasing is allowed for char */
417
+ /* overflow detected, erroneous scenario or end of stream: no update */
402
418
return BIT_DStream_overflow ;
419
+ }
420
+
421
+ assert (bitD -> ptr >= bitD -> start );
403
422
404
423
if (bitD -> ptr >= bitD -> limitPtr ) {
405
- return BIT_reloadDStreamFast (bitD );
424
+ return BIT_reloadDStream_internal (bitD );
406
425
}
407
426
if (bitD -> ptr == bitD -> start ) {
427
+ /* reached end of bitStream => no update */
408
428
if (bitD -> bitsConsumed < sizeof (bitD -> bitContainer )* 8 ) return BIT_DStream_endOfBuffer ;
409
429
return BIT_DStream_completed ;
410
430
}
411
- /* start < ptr < limitPtr */
431
+ /* start < ptr < limitPtr => cautious update */
412
432
{ U32 nbBytes = bitD -> bitsConsumed >> 3 ;
413
433
BIT_DStream_status result = BIT_DStream_unfinished ;
414
434
if (bitD -> ptr - nbBytes < bitD -> start ) {
0 commit comments