blob: bd51f4927d4d11a68972c108fe4b19c020094a86 [file] [log] [blame]
Yann Colletb1f3f4b2015-10-18 22:18:32 +01001/* ******************************************************************
Nick Terrellac58c8d2020-03-26 15:19:05 -07002 * bitstream
3 * Part of FSE library
4 * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
5 *
6 * You can contact the author at :
7 * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
8 *
9 * This source code is licensed under both the BSD-style license (found in the
10 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
11 * in the COPYING file in the root directory of this source tree).
12 * You may select, at your option, one of the above-listed licenses.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010013****************************************************************** */
14#ifndef BITSTREAM_H_MODULE
15#define BITSTREAM_H_MODULE
16
17#if defined (__cplusplus)
18extern "C" {
19#endif
Yann Colletb1f3f4b2015-10-18 22:18:32 +010020/*
Yann Collet01e5b952016-03-19 14:14:31 +010021* This API consists of small unitary functions, which must be inlined for best performance.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010022* Since link-time-optimization is not available for all compilers,
23* these functions are defined into a .h to be included.
24*/
25
Yann Colletae7aa062016-02-03 02:46:46 +010026/*-****************************************
27* Dependencies
Yann Colletb1f3f4b2015-10-18 22:18:32 +010028******************************************/
Yann Collet977f1f32016-01-21 15:38:47 +010029#include "mem.h" /* unaligned access routines */
Nick Terrell718f00f2019-11-25 18:26:19 -080030#include "compiler.h" /* UNLIKELY() */
Yann Colletfa41bcc2018-06-13 14:59:26 -040031#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
Yann Collet977f1f32016-01-21 15:38:47 +010032#include "error_private.h" /* error codes and messages */
Yann Colletb1f3f4b2015-10-18 22:18:32 +010033
34
Yann Collet74bd1192016-03-26 17:50:26 +010035/*=========================================
36* Target specific
37=========================================*/
38#if defined(__BMI__) && defined(__GNUC__)
39# include <immintrin.h> /* support for bextr (experimental) */
Joseph Chen3855bc42019-07-29 15:20:37 +080040#elif defined(__ICCARM__)
41# include <intrinsics.h>
Yann Collet74bd1192016-03-26 17:50:26 +010042#endif
43
Sean Purcelld44703d2017-03-01 14:36:25 -080044#define STREAM_ACCUMULATOR_MIN_32 25
45#define STREAM_ACCUMULATOR_MIN_64 57
46#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
Yann Collet74bd1192016-03-26 17:50:26 +010047
Yann Collet8c910d22017-06-03 01:15:02 -070048
Yann Colletae7aa062016-02-03 02:46:46 +010049/*-******************************************
50* bitStream encoding API (write forward)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010051********************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +010052/* bitStream can mix input from multiple sources.
Yann Colletb71363b2017-07-19 01:05:40 -070053 * A critical property of these streams is that they encode and decode in **reverse** direction.
54 * So the first bit sequence you add will be the last to be read, like a LIFO stack.
55 */
Yann Colletfa41bcc2018-06-13 14:59:26 -040056typedef struct {
Yann Colletb1f3f4b2015-10-18 22:18:32 +010057 size_t bitContainer;
Yann Colletf39a6732017-05-01 09:56:03 -070058 unsigned bitPos;
Yann Colletb1f3f4b2015-10-18 22:18:32 +010059 char* startPtr;
60 char* ptr;
61 char* endPtr;
62} BIT_CStream_t;
63
Yann Colletae7aa062016-02-03 02:46:46 +010064MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
Yann Colletb1f3f4b2015-10-18 22:18:32 +010065MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
66MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
67MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
68
Yann Collet01e5b952016-03-19 14:14:31 +010069/* Start with initCStream, providing the size of buffer to write into.
70* bitStream will never write outside of this buffer.
Yann Collet1032fbe2016-05-11 18:30:24 +020071* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010072*
Yann Collet01e5b952016-03-19 14:14:31 +010073* bits are first added to a local register.
74* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
75* Writing data into memory is an explicit operation, performed by the flushBits function.
76* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
77* After a flushBits, a maximum of 7 bits might still be stored into local register.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010078*
Yann Collet01e5b952016-03-19 14:14:31 +010079* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010080*
Yann Collet01e5b952016-03-19 14:14:31 +010081* Last operation is to close the bitStream.
82* The function returns the final size of CStream in bytes.
83* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010084*/
85
86
Yann Colletae7aa062016-02-03 02:46:46 +010087/*-********************************************
88* bitStream decoding API (read backward)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010089**********************************************/
Yann Colletfa41bcc2018-06-13 14:59:26 -040090typedef struct {
Yann Colletb1f3f4b2015-10-18 22:18:32 +010091 size_t bitContainer;
92 unsigned bitsConsumed;
93 const char* ptr;
94 const char* start;
Yann Colletf39a6732017-05-01 09:56:03 -070095 const char* limitPtr;
Yann Colletb1f3f4b2015-10-18 22:18:32 +010096} BIT_DStream_t;
97
98typedef enum { BIT_DStream_unfinished = 0,
99 BIT_DStream_endOfBuffer = 1,
100 BIT_DStream_completed = 2,
101 BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
102 /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
103
104MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
105MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
106MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
107MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
108
109
Yann Collet01e5b952016-03-19 14:14:31 +0100110/* Start by invoking BIT_initDStream().
111* A chunk of the bitStream is then stored into a local register.
112* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
113* You can then retrieve bitFields stored into the local register, **in reverse order**.
114* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
Yann Collet1032fbe2016-05-11 18:30:24 +0200115* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
Yann Collet01e5b952016-03-19 14:14:31 +0100116* Otherwise, it can be less than that, so proceed accordingly.
Yann Colletb21ce152016-03-24 01:27:55 +0100117* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100118*/
119
120
Yann Colletae7aa062016-02-03 02:46:46 +0100121/*-****************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100122* unsafe API
123******************************************/
124MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
125/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
126
127MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
128/* unsafe version; does not check buffer overflow */
129
130MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
131/* faster, but works only if nbBits >= 1 */
132
133
134
Yann Colletae7aa062016-02-03 02:46:46 +0100135/*-**************************************************************
Yann Collet6cf45da2016-03-23 14:18:37 +0100136* Internal functions
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100137****************************************************************/
Yann Colletc173dbd2017-12-04 17:57:42 -0800138MEM_STATIC unsigned BIT_highbit32 (U32 val)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100139{
Stella Laue50ed1f2017-08-22 11:55:42 -0700140 assert(val != 0);
141 {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100142# if defined(_MSC_VER) /* Visual */
Niadb493fd402020-07-28 02:52:15 -0600143# if STATIC_BMI2 == 1
144 return _lzcnt_u32(val) ^ 31;
145# else
146 unsigned long r = 0;
147 return _BitScanReverse(&r, val) ? (unsigned)r : 0;
148# endif
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100149# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
Dávid Bolvanský1f7228c2019-09-23 21:23:09 +0200150 return __builtin_clz (val) ^ 31;
Joseph Chen3855bc42019-07-29 15:20:37 +0800151# elif defined(__ICCARM__) /* IAR Intrinsic */
152 return 31 - __CLZ(val);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100153# else /* Software version */
Stella Laue50ed1f2017-08-22 11:55:42 -0700154 static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
155 11, 14, 16, 18, 22, 25, 3, 30,
156 8, 12, 20, 28, 15, 17, 24, 7,
157 19, 27, 23, 6, 26, 5, 4, 31 };
158 U32 v = val;
159 v |= v >> 1;
160 v |= v >> 2;
161 v |= v >> 4;
162 v |= v >> 8;
163 v |= v >> 16;
164 return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100165# endif
Stella Laue50ed1f2017-08-22 11:55:42 -0700166 }
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100167}
168
Yann Collet6cf45da2016-03-23 14:18:37 +0100169/*===== Local Constants =====*/
Nick Terrell74718d72017-09-15 17:44:09 -0700170static const unsigned BIT_mask[] = {
171 0, 1, 3, 7, 0xF, 0x1F,
172 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
173 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
174 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
175 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
176 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
177#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100178
Yann Colletae7aa062016-02-03 02:46:46 +0100179/*-**************************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100180* bitStream encoding
181****************************************************************/
Yann Collet01e5b952016-03-19 14:14:31 +0100182/*! BIT_initCStream() :
Yann Colletf39a6732017-05-01 09:56:03 -0700183 * `dstCapacity` must be > sizeof(size_t)
Yann Collet01e5b952016-03-19 14:14:31 +0100184 * @return : 0 if success,
Yann Colletb71363b2017-07-19 01:05:40 -0700185 * otherwise an error code (can be tested using ERR_isError()) */
Yann Colletf39a6732017-05-01 09:56:03 -0700186MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
Yann Collet33c38b02017-05-01 11:12:30 -0700187 void* startPtr, size_t dstCapacity)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100188{
189 bitC->bitContainer = 0;
190 bitC->bitPos = 0;
191 bitC->startPtr = (char*)startPtr;
192 bitC->ptr = bitC->startPtr;
Yann Colletf39a6732017-05-01 09:56:03 -0700193 bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
194 if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100195 return 0;
196}
197
Yann Collet01e5b952016-03-19 14:14:31 +0100198/*! BIT_addBits() :
Nick Terrell74718d72017-09-15 17:44:09 -0700199 * can add up to 31 bits into `bitC`.
Yann Colletb71363b2017-07-19 01:05:40 -0700200 * Note : does not check for register overflow ! */
Yann Colletf39a6732017-05-01 09:56:03 -0700201MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
Yann Collet33c38b02017-05-01 11:12:30 -0700202 size_t value, unsigned nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100203{
Nick Terrell74718d72017-09-15 17:44:09 -0700204 MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
205 assert(nbBits < BIT_MASK_SIZE);
206 assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
Yann Collet6cf45da2016-03-23 14:18:37 +0100207 bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100208 bitC->bitPos += nbBits;
209}
210
Yann Colletd1d210f2016-03-19 12:12:07 +0100211/*! BIT_addBitsFast() :
Yann Colletfa41bcc2018-06-13 14:59:26 -0400212 * works only if `value` is _clean_,
213 * meaning all high bits above nbBits are 0 */
Yann Colletf39a6732017-05-01 09:56:03 -0700214MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
Yann Collet33c38b02017-05-01 11:12:30 -0700215 size_t value, unsigned nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100216{
Yann Collet202082f2017-04-28 16:56:39 -0700217 assert((value>>nbBits) == 0);
Nick Terrell74718d72017-09-15 17:44:09 -0700218 assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100219 bitC->bitContainer |= value << bitC->bitPos;
220 bitC->bitPos += nbBits;
221}
222
Yann Colletd1d210f2016-03-19 12:12:07 +0100223/*! BIT_flushBitsFast() :
Yann Colletf39a6732017-05-01 09:56:03 -0700224 * assumption : bitContainer has not overflowed
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100225 * unsafe version; does not check buffer overflow */
226MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
227{
Yann Colletd64f4352016-03-21 00:07:42 +0100228 size_t const nbBytes = bitC->bitPos >> 3;
Nick Terrell74718d72017-09-15 17:44:09 -0700229 assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
Bimba Shrestha43da5bf2019-09-12 14:43:50 -0700230 assert(bitC->ptr <= bitC->endPtr);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100231 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
232 bitC->ptr += nbBytes;
233 bitC->bitPos &= 7;
Yann Colletf39a6732017-05-01 09:56:03 -0700234 bitC->bitContainer >>= nbBytes*8;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100235}
236
Yann Collet01e5b952016-03-19 14:14:31 +0100237/*! BIT_flushBits() :
Yann Colletf39a6732017-05-01 09:56:03 -0700238 * assumption : bitContainer has not overflowed
Yann Collet01e5b952016-03-19 14:14:31 +0100239 * safe version; check for buffer overflow, and prevents it.
Yann Collet33c38b02017-05-01 11:12:30 -0700240 * note : does not signal buffer overflow.
241 * overflow will be revealed later on using BIT_closeCStream() */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100242MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
243{
Yann Colletd64f4352016-03-21 00:07:42 +0100244 size_t const nbBytes = bitC->bitPos >> 3;
Nick Terrell74718d72017-09-15 17:44:09 -0700245 assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
Bimba Shresthafe9af332019-09-12 15:35:27 -0700246 assert(bitC->ptr <= bitC->endPtr);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100247 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
248 bitC->ptr += nbBytes;
249 if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
250 bitC->bitPos &= 7;
Yann Collet33c38b02017-05-01 11:12:30 -0700251 bitC->bitContainer >>= nbBytes*8;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100252}
253
Yann Colletd1d210f2016-03-19 12:12:07 +0100254/*! BIT_closeCStream() :
Yann Collet01e5b952016-03-19 14:14:31 +0100255 * @return : size of CStream, in bytes,
Yann Colletb71363b2017-07-19 01:05:40 -0700256 * or 0 if it could not fit into dstBuffer */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100257MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
258{
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100259 BIT_addBitsFast(bitC, 1, 1); /* endMark */
260 BIT_flushBits(bitC);
Yann Collet33c38b02017-05-01 11:12:30 -0700261 if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
Yann Collet01e5b952016-03-19 14:14:31 +0100262 return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100263}
264
265
Yann Colletae7aa062016-02-03 02:46:46 +0100266/*-********************************************************
Yann Colletb71363b2017-07-19 01:05:40 -0700267* bitStream decoding
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100268**********************************************************/
Yann Collet01e5b952016-03-19 14:14:31 +0100269/*! BIT_initDStream() :
Yann Colletb71363b2017-07-19 01:05:40 -0700270 * Initialize a BIT_DStream_t.
271 * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
272 * `srcSize` must be the *exact* size of the bitStream, in bytes.
273 * @return : size of stream (== srcSize), or an errorCode if a problem is detected
274 */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100275MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
276{
277 if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
278
Yann Colletf39a6732017-05-01 09:56:03 -0700279 bitD->start = (const char*)srcBuffer;
280 bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
281
Yann Collet1032fbe2016-05-11 18:30:24 +0200282 if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
Yann Collet1032fbe2016-05-11 18:30:24 +0200283 bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100284 bitD->bitContainer = MEM_readLEST(bitD->ptr);
Yann Colletb21ce152016-03-24 01:27:55 +0100285 { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
Yann Collet5397a662016-12-13 15:21:06 +0100286 bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
Yann Collet18c8f792016-06-12 22:51:52 +0200287 if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
Yann Colletae7aa062016-02-03 02:46:46 +0100288 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100289 bitD->ptr = bitD->start;
Yann Collet1ceb5a92016-05-12 13:50:13 +0200290 bitD->bitContainer = *(const BYTE*)(bitD->start);
291 switch(srcSize)
292 {
Yann Colletb71363b2017-07-19 01:05:40 -0700293 case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
294 /* fall-through */
Jos Collin05286fd2017-05-09 08:36:05 +0530295
Yann Colletb71363b2017-07-19 01:05:40 -0700296 case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
297 /* fall-through */
Yann Collet58e8d792017-06-02 18:20:48 -0700298
Yann Colletb71363b2017-07-19 01:05:40 -0700299 case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
300 /* fall-through */
Yann Collet58e8d792017-06-02 18:20:48 -0700301
Yann Colletb71363b2017-07-19 01:05:40 -0700302 case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
303 /* fall-through */
Yann Collet58e8d792017-06-02 18:20:48 -0700304
Yann Colletb71363b2017-07-19 01:05:40 -0700305 case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
306 /* fall-through */
Yann Collet58e8d792017-06-02 18:20:48 -0700307
Yann Colletb71363b2017-07-19 01:05:40 -0700308 case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
309 /* fall-through */
Yann Collet58e8d792017-06-02 18:20:48 -0700310
Yann Colletb71363b2017-07-19 01:05:40 -0700311 default: break;
Yann Collet1ceb5a92016-05-12 13:50:13 +0200312 }
Yann Colletb71363b2017-07-19 01:05:40 -0700313 { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
314 bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
315 if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
316 }
Yann Collet1032fbe2016-05-11 18:30:24 +0200317 bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100318 }
319
320 return srcSize;
321}
322
Niadba8ebc142020-07-28 11:17:04 -0600323MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
Yann Collet3c017862016-03-23 14:09:51 +0100324{
Yann Collet1032fbe2016-05-11 18:30:24 +0200325 return bitContainer >> start;
Yann Collet3c017862016-03-23 14:09:51 +0100326}
327
Niadba8ebc142020-07-28 11:17:04 -0600328MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
Yann Collet3c017862016-03-23 14:09:51 +0100329{
Yann Collet6ed3b522018-10-10 18:26:44 -0700330 U32 const regMask = sizeof(bitContainer)*8 - 1;
331 /* if start > regMask, bitstream is corrupted, and result is undefined */
Nick Terrell74718d72017-09-15 17:44:09 -0700332 assert(nbBits < BIT_MASK_SIZE);
Yann Collet6ed3b522018-10-10 18:26:44 -0700333 return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
Yann Collet3c017862016-03-23 14:09:51 +0100334}
335
Niadba8ebc142020-07-28 11:17:04 -0600336MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
Yann Colletafab0202016-03-23 13:57:49 +0100337{
Niadb493fd402020-07-28 02:52:15 -0600338#if STATIC_BMI2
339 return _bzhi_u64(bitContainer, nbBits);
340#else
Nick Terrell74718d72017-09-15 17:44:09 -0700341 assert(nbBits < BIT_MASK_SIZE);
Yann Collet1032fbe2016-05-11 18:30:24 +0200342 return bitContainer & BIT_mask[nbBits];
Niadb493fd402020-07-28 02:52:15 -0600343#endif
Yann Colletafab0202016-03-23 13:57:49 +0100344}
345
Yann Collet01e5b952016-03-19 14:14:31 +0100346/*! BIT_lookBits() :
347 * Provides next n bits from local register.
Yann Collet1032fbe2016-05-11 18:30:24 +0200348 * local register is not modified.
Yann Collet01e5b952016-03-19 14:14:31 +0100349 * On 32-bits, maxNbBits==24.
350 * On 64-bits, maxNbBits==56.
Yann Colletb71363b2017-07-19 01:05:40 -0700351 * @return : value extracted */
Niadba8ebc142020-07-28 11:17:04 -0600352MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100353{
Yann Collet7791f192018-10-10 16:36:11 -0700354 /* arbitrate between double-shift and shift+mask */
Yann Colletd3ec2332018-10-10 15:48:43 -0700355#if 1
Yann Collet7791f192018-10-10 16:36:11 -0700356 /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
357 * bitstream is likely corrupted, and result is undefined */
Yann Collet1032fbe2016-05-11 18:30:24 +0200358 return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
Yann Collet862a8592016-03-23 18:45:23 +0100359#else
Yann Collet7791f192018-10-10 16:36:11 -0700360 /* this code path is slower on my os-x laptop */
Yann Colletf39a6732017-05-01 09:56:03 -0700361 U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
362 return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
Yann Collet862a8592016-03-23 18:45:23 +0100363#endif
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100364}
365
Yann Collet01e5b952016-03-19 14:14:31 +0100366/*! BIT_lookBitsFast() :
Yann Collet202082f2017-04-28 16:56:39 -0700367 * unsafe version; only works if nbBits >= 1 */
Yann Colletadd08d62016-03-23 01:32:41 +0100368MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100369{
Yann Colletf39a6732017-05-01 09:56:03 -0700370 U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
Yann Collet202082f2017-04-28 16:56:39 -0700371 assert(nbBits >= 1);
Yann Colletf39a6732017-05-01 09:56:03 -0700372 return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100373}
374
Niadba8ebc142020-07-28 11:17:04 -0600375MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100376{
377 bitD->bitsConsumed += nbBits;
378}
379
Yann Collet01e5b952016-03-19 14:14:31 +0100380/*! BIT_readBits() :
Yann Colletb21ce152016-03-24 01:27:55 +0100381 * Read (consume) next n bits from local register and update.
382 * Pay attention to not read more than nbBits contained into local register.
Yann Colletb71363b2017-07-19 01:05:40 -0700383 * @return : extracted value. */
Niadba8ebc142020-07-28 11:17:04 -0600384MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100385{
Yann Colletafab0202016-03-23 13:57:49 +0100386 size_t const value = BIT_lookBits(bitD, nbBits);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100387 BIT_skipBits(bitD, nbBits);
388 return value;
389}
390
Yann Collet01e5b952016-03-19 14:14:31 +0100391/*! BIT_readBitsFast() :
Yann Colletb71363b2017-07-19 01:05:40 -0700392 * unsafe version; only works only if nbBits >= 1 */
Yann Colletededcfc2018-12-21 16:19:44 -0800393MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100394{
Yann Colletafab0202016-03-23 13:57:49 +0100395 size_t const value = BIT_lookBitsFast(bitD, nbBits);
Yann Collet202082f2017-04-28 16:56:39 -0700396 assert(nbBits >= 1);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100397 BIT_skipBits(bitD, nbBits);
398 return value;
399}
400
Nick Terrell718f00f2019-11-25 18:26:19 -0800401/*! BIT_reloadDStreamFast() :
402 * Similar to BIT_reloadDStream(), but with two differences:
403 * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
404 * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
405 * point you must use BIT_reloadDStream() to reload.
406 */
407MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
408{
409 if (UNLIKELY(bitD->ptr < bitD->limitPtr))
410 return BIT_DStream_overflow;
411 assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
412 bitD->ptr -= bitD->bitsConsumed >> 3;
413 bitD->bitsConsumed &= 7;
414 bitD->bitContainer = MEM_readLEST(bitD->ptr);
415 return BIT_DStream_unfinished;
416}
417
Yann Collet01e5b952016-03-19 14:14:31 +0100418/*! BIT_reloadDStream() :
Yann Colletb71363b2017-07-19 01:05:40 -0700419 * Refill `bitD` from buffer previously set in BIT_initDStream() .
420 * This function is safe, it guarantees it will not read beyond src buffer.
421 * @return : status of `BIT_DStream_t` internal register.
Baldur Karlsson430a2fe2018-03-13 20:02:21 +0000422 * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100423MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
424{
Yann Colletf39a6732017-05-01 09:56:03 -0700425 if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
Nick Terrell5152fb22017-03-29 18:51:58 -0700426 return BIT_DStream_overflow;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100427
Yann Colletf39a6732017-05-01 09:56:03 -0700428 if (bitD->ptr >= bitD->limitPtr) {
Nick Terrell718f00f2019-11-25 18:26:19 -0800429 return BIT_reloadDStreamFast(bitD);
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100430 }
Yann Colletae7aa062016-02-03 02:46:46 +0100431 if (bitD->ptr == bitD->start) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100432 if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
433 return BIT_DStream_completed;
434 }
Yann Colletf39a6732017-05-01 09:56:03 -0700435 /* start < ptr < limitPtr */
Yann Collet01e5b952016-03-19 14:14:31 +0100436 { U32 nbBytes = bitD->bitsConsumed >> 3;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100437 BIT_DStream_status result = BIT_DStream_unfinished;
Yann Colletae7aa062016-02-03 02:46:46 +0100438 if (bitD->ptr - nbBytes < bitD->start) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100439 nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
440 result = BIT_DStream_endOfBuffer;
441 }
442 bitD->ptr -= nbBytes;
443 bitD->bitsConsumed -= nbBytes*8;
Yann Colletf39a6732017-05-01 09:56:03 -0700444 bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100445 return result;
446 }
447}
448
Yann Colletd1d210f2016-03-19 12:12:07 +0100449/*! BIT_endOfDStream() :
Yann Colletb71363b2017-07-19 01:05:40 -0700450 * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
451 */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100452MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
453{
454 return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
455}
456
457#if defined (__cplusplus)
458}
459#endif
460
461#endif /* BITSTREAM_H_MODULE */