blosc2-sys 0.4.0+2.15.2

Bindings to C Blosc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
/*
High-speed in-memory bit stream I/O that supports reading and writing between
0 and 64 bits at a time.  The implementation, which relies heavily on bit
shifts, has been carefully written to ensure that all shifts are between
zero and one less the width of the type being shifted to avoid undefined
behavior.  This occasionally causes somewhat convoluted code.

The following assumptions and restrictions apply:

1. The user must allocate a memory buffer large enough to hold the bit stream,
   whether for reading, writing, or both.  This buffer is associated with the
   bit stream via stream_open(buffer, bytes), which allocates and returns a
   pointer to an opaque bit stream struct.  Call stream_close(stream) to
   deallocate this struct.

2. The stream is either in a read or write state (or, initially, in both
   states).  When done writing, call stream_flush(stream) before entering
   read mode to ensure any buffered bits are output.  To enter read mode,
   call stream_rewind(stream) or stream_rseek(stream, offset) to position
   the stream at the beginning or at a particular bit offset.  Conversely,
   stream_rewind(stream) or stream_wseek(stream, offset) positions the
   stream for writing.  In read mode, the following functions may be called:

     size_t stream_size(stream);
     size_t stream_rtell(stream);
     void stream_rewind(stream);
     void stream_rseek(stream, offset);
     void stream_skip(stream, uint n);
     size_t stream_align(stream);
     uint stream_read_bit(stream);
     uint64 stream_read_bits(stream, n);

   Each of the above read calls has a corresponding write call:

     size_t stream_size(stream);
     size_t stream_wtell(stream);
     void stream_rewind(stream);
     void stream_wseek(stream, offset);
     void stream_pad(stream, n);
     size_t stream_flush(stream);
     uint stream_write_bit(stream, bit);
     uint64 stream_write_bits(stream, value, n);

3. The stream buffer is an unsigned integer of a user-specified type given
   by the BIT_STREAM_WORD_TYPE macro.  Bits are read and written in units of
   this integer word type.  Supported types are 8, 16, 32, or 64 bits wide.
   The bit width of the buffer is denoted by 'wsize' and can be accessed via
   the global constant stream_word_bits.  A small wsize allows for fine
   granularity reads and writes, and may be preferable when working with many
   small blocks of data that require non-sequential access.  The default
   maximum size of 64 bits ensures maximum speed.  Note that even when
   wsize < 64, it is still possible to read and write up to 64 bits at a time
   using stream_read_bits() and stream_write_bits().

4. If BIT_STREAM_STRIDED is defined, words read from or written to the stream
   may be accessed noncontiguously by setting a power-of-two block size (which
   by default is one word) and a block stride (defaults to zero blocks).  The
   word pointer is always incremented by one word each time a word is accessed.
   Once advanced past a block boundary, the word pointer is also advanced by
   the stride to the next block.  This feature may be used to store blocks of
   data interleaved, e.g. for progressive coding or for noncontiguous parallel
   access to the bit stream  Note that the block size is measured in words,
   while the stride is measured in multiples of the block size.  Strided access
   can have a significant performance penalty.

5. Multiple bits are read and written in order of least to most significant
   bit.  Thus, the statement

       value = stream_write_bits(stream, value, n);

   is essentially equivalent to (but faster than)

       for (i = 0; i < n; i++, value >>= 1)
         stream_write_bit(value & 1);

   when 0 <= n <= 64.  The same holds for read calls, and thus

       value = stream_read_bits(stream, n);

   is essentially equivalent to

       for (i = 0, value = 0; i < n; i++)
         value += (uint64)stream_read_bit() << i;

   Note that it is possible to write fewer bits than the argument 'value'
   holds (possibly even no bits), in which case any unwritten bits are
   returned.

6. Although the stream_wseek(stream, offset) call allows positioning the
   stream for writing at any bit offset without any data loss (i.e. all
   previously written bits preceding the offset remain valid), for efficiency
   the stream_flush(stream) operation will zero all bits up to the next
   multiple of wsize bits, thus overwriting bits that were previously stored
   at that location.  Consequently, random write access is effectively
   supported only at wsize granularity.  For sequential access, the largest
   possible wsize is preferred due to higher speed.

7. It is up to the user to adhere to these rules.  For performance reasons,
   no error checking is done, and in particular buffer overruns are not
   caught.
*/

#include <limits.h>
#include <stdlib.h>

#ifndef inline_
  #define inline_
#endif

/* satisfy compiler when args unused */
#define unused_(x) ((void)(x))

/* bit stream word/buffer type; granularity of stream I/O operations */
#ifdef BIT_STREAM_WORD_TYPE
  /* may be 8-, 16-, 32-, or 64-bit unsigned integer type */
  typedef BIT_STREAM_WORD_TYPE word;
#else
  /* use maximum word size by default for highest speed */
  typedef uint64 word;
#endif

/* number of bits in a buffered word */
#define wsize ((uint)(CHAR_BIT * sizeof(word)))

/* bit stream structure (opaque to caller) */
struct bitstream {
  uint bits;   /* number of buffered bits (0 <= bits < wsize) */
  word buffer; /* buffer for incoming/outgoing bits (buffer < 2^bits) */
  word* ptr;   /* pointer to next word to be read/written */
  word* begin; /* beginning of stream */
  word* end;   /* end of stream (currently unused) */
#ifdef BIT_STREAM_STRIDED
  size_t mask;     /* one less the block size in number of words */
  ptrdiff_t delta; /* number of words between consecutive blocks */
#endif
};

/* private functions ------------------------------------------------------- */

/* read a single word from memory */
static word
stream_read_word(bitstream* s)
{
  word w = *s->ptr++;
#ifdef BIT_STREAM_STRIDED
  if (!((s->ptr - s->begin) & s->mask))
    s->ptr += s->delta;
#endif
  return w;
}

/* write a single word to memory */
static void
stream_write_word(bitstream* s, word value)
{
  *s->ptr++ = value;
#ifdef BIT_STREAM_STRIDED
  if (!((s->ptr - s->begin) & s->mask))
    s->ptr += s->delta;
#endif
}

/* public functions -------------------------------------------------------- */

/* word size in bits (equals stream_word_bits) */
inline_ size_t
stream_alignment(void)
{
  return wsize;
}

/* pointer to beginning of stream */
inline_ void*
stream_data(const bitstream* s)
{
  return s->begin;
}

/* current byte size of stream (if flushed) */
inline_ size_t
stream_size(const bitstream* s)
{
  return sizeof(word) * (size_t)(s->ptr - s->begin);
}

/* byte capacity of stream */
inline_ size_t
stream_capacity(const bitstream* s)
{
  return sizeof(word) * (size_t)(s->end - s->begin);
}

/* number of words per block */
inline_ size_t
stream_stride_block(const bitstream* s)
{
#ifdef BIT_STREAM_STRIDED
  return s->mask + 1;
#else
  unused_(s);
  return 1;
#endif
}

/* number of blocks between consecutive stream blocks */
inline_ ptrdiff_t
stream_stride_delta(const bitstream* s)
{
#ifdef BIT_STREAM_STRIDED
  return s->delta / (s->mask + 1);
#else
  unused_(s);
  return 0;
#endif
}

/* read single bit (0 or 1) */
inline_ uint
stream_read_bit(bitstream* s)
{
  uint bit;
  if (!s->bits) {
    s->buffer = stream_read_word(s);
    s->bits = wsize;
  }
  s->bits--;
  bit = (uint)s->buffer & 1u;
  s->buffer >>= 1;
  return bit;
}

/* write single bit (must be 0 or 1) */
inline_ uint
stream_write_bit(bitstream* s, uint bit)
{
  s->buffer += (word)bit << s->bits;
  if (++s->bits == wsize) {
    stream_write_word(s, s->buffer);
    s->buffer = 0;
    s->bits = 0;
  }
  return bit;
}

/* read 0 <= n <= 64 bits */
inline_ uint64
stream_read_bits(bitstream* s, uint n)
{
  uint64 value = s->buffer;
  if (s->bits < n) {
    /* keep fetching wsize bits until enough bits are buffered */
    do {
      /* assert: 0 <= s->bits < n <= 64 */
      s->buffer = stream_read_word(s);
      value += (uint64)s->buffer << s->bits;
      s->bits += wsize;
    } while (sizeof(s->buffer) < sizeof(value) && s->bits < n);
    /* assert: 1 <= n <= s->bits < n + wsize */
    s->bits -= n;
    if (!s->bits) {
      /* value holds exactly n bits; no need for masking */
      s->buffer = 0;
    }
    else {
      /* assert: 1 <= s->bits < wsize */
      s->buffer >>= wsize - s->bits;
      /* assert: 1 <= n <= 64 */
      value &= ((uint64)2 << (n - 1)) - 1;
    }
  }
  else {
    /* assert: 0 <= n <= s->bits < wsize <= 64 */
    s->bits -= n;
    s->buffer >>= n;
    value &= ((uint64)1 << n) - 1;
  }
  return value;
}

/* write 0 <= n <= 64 low bits of value and return remaining bits */
inline_ uint64
stream_write_bits(bitstream* s, uint64 value, uint n)
{
  /* append bit string to buffer */
  s->buffer += (word)(value << s->bits);
  s->bits += n;
  /* is buffer full? */
  if (s->bits >= wsize) {
    /* 1 <= n <= 64; decrement n to ensure valid right shifts below */
    value >>= 1;
    n--;
    /* assert: 0 <= n < 64; wsize <= s->bits <= wsize + n */
    do {
      /* output wsize bits while buffer is full */
      s->bits -= wsize;
      /* assert: 0 <= s->bits <= n */
      stream_write_word(s, s->buffer);
      /* assert: 0 <= n - s->bits < 64 */
      s->buffer = (word)(value >> (n - s->bits));
    } while (sizeof(s->buffer) < sizeof(value) && s->bits >= wsize);
  }
  /* assert: 0 <= s->bits < wsize */
  s->buffer &= ((word)1 << s->bits) - 1;
  /* assert: 0 <= n < 64 */
  return value >> n;
}

/* return bit offset to next bit to be read */
inline_ size_t
stream_rtell(const bitstream* s)
{
  return wsize * (size_t)(s->ptr - s->begin) - s->bits;
}

/* return bit offset to next bit to be written */
inline_ size_t
stream_wtell(const bitstream* s)
{
  return wsize * (size_t)(s->ptr - s->begin) + s->bits;
}

/* position stream for reading or writing at beginning */
inline_ void
stream_rewind(bitstream* s)
{
  s->ptr = s->begin;
  s->buffer = 0;
  s->bits = 0;
}

/* position stream for reading at given bit offset */
inline_ void
stream_rseek(bitstream* s, size_t offset)
{
  uint n = offset % wsize;
  s->ptr = s->begin + offset / wsize;
  if (n) {
    s->buffer = stream_read_word(s) >> n;
    s->bits = wsize - n;
  }
  else {
    s->buffer = 0;
    s->bits = 0;
  }
}

/* position stream for writing at given bit offset */
inline_ void
stream_wseek(bitstream* s, size_t offset)
{
  uint n = offset % wsize;
  s->ptr = s->begin + offset / wsize;
  if (n) {
    word buffer = *s->ptr;
    buffer &= ((word)1 << n) - 1;
    s->buffer = buffer;
    s->bits = n;
  }
  else {
    s->buffer = 0;
    s->bits = 0;
  }
}

/* skip over the next n bits (n >= 0) */
inline_ void
stream_skip(bitstream* s, uint n)
{
  stream_rseek(s, stream_rtell(s) + n);
}

/* append n zero-bits to stream (n >= 0) */
inline_ void
stream_pad(bitstream* s, uint n)
{
  for (s->bits += n; s->bits >= wsize; s->bits -= wsize) {
    stream_write_word(s, s->buffer);
    s->buffer = 0;
  }
}

/* align stream on next word boundary */
inline_ size_t
stream_align(bitstream* s)
{
  uint bits = s->bits;
  if (bits)
    stream_skip(s, bits);
  return bits;
}

/* write any remaining buffered bits and align stream on next word boundary */
inline_ size_t
stream_flush(bitstream* s)
{
  uint bits = (wsize - s->bits) % wsize;
  if (bits)
    stream_pad(s, bits);
  return bits;
}

/* copy n bits from one bit stream to another */
inline_ void
stream_copy(bitstream* dst, bitstream* src, size_t n)
{
  while (n > wsize) {
    word w = (word)stream_read_bits(src, wsize);
    stream_write_bits(dst, w, wsize);
    n -= wsize;
  }
  if (n) {
    word w = (word)stream_read_bits(src, (uint)n);
    stream_write_bits(dst, w, (uint)n);
  }
}

#ifdef BIT_STREAM_STRIDED
/* set block size in number of words and spacing in number of blocks */
inline_ int
stream_set_stride(bitstream* s, size_t block, ptrdiff_t delta)
{
  /* ensure block size is a power of two */
  if (block & (block - 1))
    return 0;
  s->mask = block - 1;
  s->delta = delta * block;
  return 1;
}
#endif

/* allocate and initialize bit stream to user-allocated buffer */
inline_ bitstream*
stream_open(void* buffer, size_t bytes)
{
  bitstream* s = (bitstream*)malloc(sizeof(bitstream));
  if (s) {
    s->begin = (word*)buffer;
    s->end = s->begin + bytes / sizeof(word);
#ifdef BIT_STREAM_STRIDED
    stream_set_stride(s, 0, 0);
#endif
    stream_rewind(s);
  }
  return s;
}

/* close and deallocate bit stream */
inline_ void
stream_close(bitstream* s)
{
  free(s);
}

/* make a copy of bit stream to shared memory buffer */
inline_ bitstream*
stream_clone(const bitstream* s)
{
  bitstream* c = (bitstream*)malloc(sizeof(bitstream));
  if (c)
    *c = *s;
  return c;
}

#undef unused_