blob: 44c0241fa9f77fcc1f73a344a51e06b89e695b04 [file] [log] [blame]
Yann Colletb1f3f4b2015-10-18 22:18:32 +01001/* ******************************************************************
2 bitstream
Yann Colletae7aa062016-02-03 02:46:46 +01003 Part of FSE library
Yann Colletb1f3f4b2015-10-18 22:18:32 +01004 header file (to include)
Yann Colletae7aa062016-02-03 02:46:46 +01005 Copyright (C) 2013-2016, Yann Collet.
Yann Colletb1f3f4b2015-10-18 22:18:32 +01006
7 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are
11 met:
12
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above
16 copyright notice, this list of conditions and the following disclaimer
17 in the documentation and/or other materials provided with the
18 distribution.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 You can contact the author at :
33 - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
Yann Colletb1f3f4b2015-10-18 22:18:32 +010034****************************************************************** */
35#ifndef BITSTREAM_H_MODULE
36#define BITSTREAM_H_MODULE
37
38#if defined (__cplusplus)
39extern "C" {
40#endif
41
42
43/*
44* This API consists of small unitary functions, which highly benefit from being inlined.
45* Since link-time-optimization is not available for all compilers,
46* these functions are defined into a .h to be included.
47*/
48
Yann Colletae7aa062016-02-03 02:46:46 +010049/*-****************************************
50* Dependencies
Yann Colletb1f3f4b2015-10-18 22:18:32 +010051******************************************/
Yann Collet977f1f32016-01-21 15:38:47 +010052#include "mem.h" /* unaligned access routines */
53#include "error_private.h" /* error codes and messages */
Yann Colletb1f3f4b2015-10-18 22:18:32 +010054
55
Yann Colletae7aa062016-02-03 02:46:46 +010056/*-******************************************
57* bitStream encoding API (write forward)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010058********************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +010059/* bitStream can mix input from multiple sources.
60* A critical property of these streams is that they encode and decode in **reverse** direction.
61* So the first bit sequence you add will be the last to be read, like a LIFO stack.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010062*/
63typedef struct
64{
65 size_t bitContainer;
66 int bitPos;
67 char* startPtr;
68 char* ptr;
69 char* endPtr;
70} BIT_CStream_t;
71
Yann Colletae7aa062016-02-03 02:46:46 +010072MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
Yann Colletb1f3f4b2015-10-18 22:18:32 +010073MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
74MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
75MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
76
Yann Colletd1d210f2016-03-19 12:12:07 +010077/*Start by initCStream, providing the size of buffer to write into.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010078* bitStream will never write outside of this buffer.
Yann Colletd1d210f2016-03-19 12:12:07 +010079* `dstCapacity` must be >= sizeof(size_t), otherwise @return will be an error code.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010080*
81* bits are first added to a local register.
82* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
Yann Colletae7aa062016-02-03 02:46:46 +010083* Writing data into memory is an explicit operation, performed by the flushBits function.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010084* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
85* After a flushBits, a maximum of 7 bits might still be stored into local register.
86*
Yann Colletae7aa062016-02-03 02:46:46 +010087* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
Yann Colletb1f3f4b2015-10-18 22:18:32 +010088*
89* Last operation is to close the bitStream.
90* The function returns the final size of CStream in bytes.
Yann Colletd1d210f2016-03-19 12:12:07 +010091* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010092*/
93
94
Yann Colletae7aa062016-02-03 02:46:46 +010095/*-********************************************
96* bitStream decoding API (read backward)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010097**********************************************/
98typedef struct
99{
100 size_t bitContainer;
101 unsigned bitsConsumed;
102 const char* ptr;
103 const char* start;
104} BIT_DStream_t;
105
106typedef enum { BIT_DStream_unfinished = 0,
107 BIT_DStream_endOfBuffer = 1,
108 BIT_DStream_completed = 2,
109 BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
110 /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
111
112MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
113MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
114MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
115MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
116
117
Yann Colletd1d210f2016-03-19 12:12:07 +0100118/*Start by invoking BIT_initDStream().
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100119* A chunk of the bitStream is then stored into a local register.
120* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
121* You can then retrieve bitFields stored into the local register, **in reverse order**.
Yann Colletae7aa062016-02-03 02:46:46 +0100122* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100123* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished.
124* Otherwise, it can be less than that, so proceed accordingly.
125* Checking if DStream has reached its end can be performed with BIT_endOfDStream()
126*/
127
128
Yann Colletae7aa062016-02-03 02:46:46 +0100129/*-****************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100130* unsafe API
131******************************************/
132MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
133/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
134
135MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
136/* unsafe version; does not check buffer overflow */
137
138MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
139/* faster, but works only if nbBits >= 1 */
140
141
142
Yann Colletae7aa062016-02-03 02:46:46 +0100143/*-**************************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100144* Helper functions
145****************************************************************/
146MEM_STATIC unsigned BIT_highbit32 (register U32 val)
147{
148# if defined(_MSC_VER) /* Visual */
Yann Collet4114f952015-10-30 06:40:22 +0100149 unsigned long r=0;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100150 _BitScanReverse ( &r, val );
151 return (unsigned) r;
152# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
153 return 31 - __builtin_clz (val);
154# else /* Software version */
155 static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
156 U32 v = val;
157 unsigned r;
158 v |= v >> 1;
159 v |= v >> 2;
160 v |= v >> 4;
161 v |= v >> 8;
162 v |= v >> 16;
163 r = DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
164 return r;
165# endif
166}
167
168
Yann Colletae7aa062016-02-03 02:46:46 +0100169/*-**************************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100170* bitStream encoding
171****************************************************************/
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100172MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t maxSize)
173{
174 bitC->bitContainer = 0;
175 bitC->bitPos = 0;
176 bitC->startPtr = (char*)startPtr;
177 bitC->ptr = bitC->startPtr;
178 bitC->endPtr = bitC->startPtr + maxSize - sizeof(bitC->ptr);
179 if (maxSize < sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall);
180 return 0;
181}
182
183MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
184{
Yann Collet95cd0c22016-03-08 18:24:21 +0100185 static const unsigned mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100186 bitC->bitContainer |= (value & mask[nbBits]) << bitC->bitPos;
187 bitC->bitPos += nbBits;
188}
189
Yann Colletd1d210f2016-03-19 12:12:07 +0100190/*! BIT_addBitsFast() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100191 * works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
192MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
193{
194 bitC->bitContainer |= value << bitC->bitPos;
195 bitC->bitPos += nbBits;
196}
197
Yann Colletd1d210f2016-03-19 12:12:07 +0100198/*! BIT_flushBitsFast() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100199 * unsafe version; does not check buffer overflow */
200MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
201{
202 size_t nbBytes = bitC->bitPos >> 3;
203 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
204 bitC->ptr += nbBytes;
205 bitC->bitPos &= 7;
Yann Collet00fd7a22015-11-28 16:03:22 +0100206 bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100207}
208
209MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
210{
211 size_t nbBytes = bitC->bitPos >> 3;
212 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
213 bitC->ptr += nbBytes;
214 if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
215 bitC->bitPos &= 7;
Yann Collet00fd7a22015-11-28 16:03:22 +0100216 bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100217}
218
Yann Colletd1d210f2016-03-19 12:12:07 +0100219/*! BIT_closeCStream() :
220 * @return : size of CStream, in bytes, or 0 if it cannot fit into dstBuffer */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100221MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
222{
223 char* endPtr;
224
225 BIT_addBitsFast(bitC, 1, 1); /* endMark */
226 BIT_flushBits(bitC);
227
228 if (bitC->ptr >= bitC->endPtr) /* too close to buffer's end */
229 return 0; /* not storable */
230
231 endPtr = bitC->ptr;
232 endPtr += bitC->bitPos > 0; /* remaining bits (incomplete byte) */
233
234 return (endPtr - bitC->startPtr);
235}
236
237
Yann Colletae7aa062016-02-03 02:46:46 +0100238/*-********************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100239* bitStream decoding
240**********************************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +0100241/*!BIT_initDStream() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100242* Initialize a BIT_DStream_t.
Yann Colletd1d210f2016-03-19 12:12:07 +0100243* `bitD` : a pointer to an already allocated BIT_DStream_t structure.
244* `srcBuffer` must point at the beginning of a bitStream.
245* `srcSize` must be the exact size of the bitStream.
246* @return : size of stream (== srcSize) or an errorCode if a problem is detected
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100247*/
248MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
249{
250 if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
251
Yann Colletae7aa062016-02-03 02:46:46 +0100252 if (srcSize >= sizeof(size_t)) { /* normal case */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100253 U32 contain32;
254 bitD->start = (const char*)srcBuffer;
255 bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(size_t);
256 bitD->bitContainer = MEM_readLEST(bitD->ptr);
257 contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
258 if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */
259 bitD->bitsConsumed = 8 - BIT_highbit32(contain32);
Yann Colletae7aa062016-02-03 02:46:46 +0100260 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100261 U32 contain32;
262 bitD->start = (const char*)srcBuffer;
263 bitD->ptr = bitD->start;
264 bitD->bitContainer = *(const BYTE*)(bitD->start);
265 switch(srcSize)
266 {
267 case 7: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[6]) << (sizeof(size_t)*8 - 16);
268 case 6: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[5]) << (sizeof(size_t)*8 - 24);
269 case 5: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[4]) << (sizeof(size_t)*8 - 32);
270 case 4: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[3]) << 24;
271 case 3: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[2]) << 16;
272 case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) << 8;
273 default:;
274 }
275 contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
276 if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */
277 bitD->bitsConsumed = 8 - BIT_highbit32(contain32);
278 bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8;
279 }
280
281 return srcSize;
282}
283
Yann Colletd1d210f2016-03-19 12:12:07 +0100284/*!BIT_lookBits() :
285 * Provides next n bits from local register.
286 * local register is not modified (bits are still present for next read/look).
287 * On 32-bits, maxNbBits==24.
288 * On 64-bits, maxNbBits==56.
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100289 * @return : value extracted
290 */
291MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits)
292{
Yann Colletd1d210f2016-03-19 12:12:07 +0100293 U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100294 return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
295}
296
Yann Colletd1d210f2016-03-19 12:12:07 +0100297/*! BIT_lookBitsFast*() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100298* unsafe version; only works only if nbBits >= 1 */
299MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits)
300{
Yann Colletd1d210f2016-03-19 12:12:07 +0100301 U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100302 return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
303}
304
305MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
306{
307 bitD->bitsConsumed += nbBits;
308}
309
Yann Colletd1d210f2016-03-19 12:12:07 +0100310/*!BIT_readBits() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100311 * Read next n bits from local register.
312 * pay attention to not read more than nbBits contained into local register.
313 * @return : extracted value.
314 */
315MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
316{
317 size_t value = BIT_lookBits(bitD, nbBits);
318 BIT_skipBits(bitD, nbBits);
319 return value;
320}
321
Yann Colletd1d210f2016-03-19 12:12:07 +0100322/*!BIT_readBitsFast() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100323* unsafe version; only works only if nbBits >= 1 */
324MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
325{
326 size_t value = BIT_lookBitsFast(bitD, nbBits);
327 BIT_skipBits(bitD, nbBits);
328 return value;
329}
330
331MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
332{
333 if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */
334 return BIT_DStream_overflow;
335
Yann Colletae7aa062016-02-03 02:46:46 +0100336 if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100337 bitD->ptr -= bitD->bitsConsumed >> 3;
338 bitD->bitsConsumed &= 7;
339 bitD->bitContainer = MEM_readLEST(bitD->ptr);
340 return BIT_DStream_unfinished;
341 }
Yann Colletae7aa062016-02-03 02:46:46 +0100342 if (bitD->ptr == bitD->start) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100343 if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
344 return BIT_DStream_completed;
345 }
346 {
347 U32 nbBytes = bitD->bitsConsumed >> 3;
348 BIT_DStream_status result = BIT_DStream_unfinished;
Yann Colletae7aa062016-02-03 02:46:46 +0100349 if (bitD->ptr - nbBytes < bitD->start) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100350 nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
351 result = BIT_DStream_endOfBuffer;
352 }
353 bitD->ptr -= nbBytes;
354 bitD->bitsConsumed -= nbBytes*8;
355 bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
356 return result;
357 }
358}
359
Yann Colletd1d210f2016-03-19 12:12:07 +0100360/*! BIT_endOfDStream() :
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100361* @return Tells if DStream has reached its exact end
362*/
363MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
364{
365 return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
366}
367
368#if defined (__cplusplus)
369}
370#endif
371
372#endif /* BITSTREAM_H_MODULE */