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