2012-07-27 15:22:09 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include "hammer.h"
|
|
|
|
|
#include "internal.h"
|
2012-07-27 15:47:38 -07:00
|
|
|
#include "test_suite.h"
|
2012-07-27 15:22:09 -07:00
|
|
|
|
2012-10-10 16:24:12 +02:00
|
|
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
|
|
|
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
|
|
|
|
|
2012-07-27 15:22:09 -07:00
|
|
|
// h_bit_writer_
|
2012-10-10 15:58:03 +02:00
|
|
|
HBitWriter *h_bit_writer_new(HAllocator* mm__) {
|
|
|
|
|
HBitWriter *writer = h_new(HBitWriter, 1);
|
|
|
|
|
memset(writer, 0, sizeof(*writer));
|
|
|
|
|
writer->buf = mm__->alloc(mm__, writer->capacity = 8);
|
|
|
|
|
memset(writer->buf, 0, writer->capacity);
|
|
|
|
|
writer->mm__ = mm__;
|
2012-07-27 15:22:09 -07:00
|
|
|
writer->flags = BYTE_BIG_ENDIAN | BIT_BIG_ENDIAN;
|
|
|
|
|
|
|
|
|
|
return writer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Ensure there are at least [nbits] bits available at the end of the
|
|
|
|
|
* buffer. If the buffer is expanded, the added bits should be zeroed.
|
|
|
|
|
*/
|
|
|
|
|
static void h_bit_writer_reserve(HBitWriter* w, size_t nbits) {
|
|
|
|
|
// As is, this may overshoot by a byte, e.g., nbits=9, bit_offset=1.
|
|
|
|
|
// This will assume that the last partial byte is full, and reserve
|
|
|
|
|
// 2 bytes at the end, whereas only one is necessary.
|
|
|
|
|
//
|
|
|
|
|
// That said, this guarantees the postcondition that w->buf[w->index]
|
|
|
|
|
// is valid.
|
|
|
|
|
|
|
|
|
|
// Round up to bytes
|
|
|
|
|
int nbytes = (nbits + 7) / 8 + ((w->bit_offset != 0) ? 1 : 0);
|
|
|
|
|
size_t old_capacity = w->capacity;
|
|
|
|
|
while (w->index + nbytes >= w->capacity) {
|
2012-10-10 15:58:03 +02:00
|
|
|
w->buf = w->mm__->realloc(w->mm__, w->buf, w->capacity *= 2);
|
2012-07-27 15:22:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (old_capacity != w->capacity)
|
|
|
|
|
memset(w->buf + old_capacity, 0, w->capacity - old_capacity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void h_bit_writer_put(HBitWriter* w, unsigned long long data, size_t nbits) {
|
|
|
|
|
assert(nbits > 0); // Less than or equal to zero makes complete nonsense
|
|
|
|
|
|
|
|
|
|
// expand size...
|
|
|
|
|
h_bit_writer_reserve(w, nbits);
|
|
|
|
|
|
|
|
|
|
while (nbits) {
|
|
|
|
|
size_t count = MIN((size_t)(8 - w->bit_offset), nbits);
|
|
|
|
|
|
|
|
|
|
// select the bits to be written from the source
|
|
|
|
|
uint16_t bits;
|
|
|
|
|
if (w->flags & BYTE_BIG_ENDIAN) {
|
|
|
|
|
// read from the top few bits; masking will be done later.
|
|
|
|
|
bits = data >> (nbits - count);
|
|
|
|
|
} else {
|
|
|
|
|
// just copy the bottom byte over.
|
|
|
|
|
bits = data & 0xff;
|
|
|
|
|
data >>= count; // remove the bits that have just been used.
|
|
|
|
|
}
|
|
|
|
|
// mask off the unnecessary bits.
|
|
|
|
|
bits &= (1 << count) - 1;
|
|
|
|
|
|
|
|
|
|
// Now, push those bits onto the current byte...
|
|
|
|
|
if (w->flags & BIT_BIG_ENDIAN)
|
|
|
|
|
w->buf[w->index] = (w->buf[w->index] << count) | bits;
|
|
|
|
|
else
|
|
|
|
|
w->buf[w->index] = (w->buf[w->index] | (bits << 8)) >> count;
|
|
|
|
|
|
|
|
|
|
// update index and bit_offset.
|
|
|
|
|
w->bit_offset += count;
|
|
|
|
|
if (w->bit_offset == 8) {
|
|
|
|
|
w->bit_offset = 0;
|
|
|
|
|
w->index++;
|
|
|
|
|
}
|
|
|
|
|
nbits -= count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-07-27 15:28:55 -07:00
|
|
|
const uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len) {
|
|
|
|
|
assert (len != NULL);
|
|
|
|
|
assert (w != NULL);
|
|
|
|
|
// Not entirely sure how to handle a non-integral number of bytes... make it an error for now
|
|
|
|
|
assert (w->bit_offset == 0); // BUG: change this to some sane behaviour
|
|
|
|
|
|
|
|
|
|
*len = w->index;
|
2012-07-27 15:30:16 -07:00
|
|
|
return w->buf;
|
2012-07-27 15:28:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void h_bit_writer_free(HBitWriter* w) {
|
2012-10-10 15:58:03 +02:00
|
|
|
HAllocator *mm__ = w->mm__;
|
|
|
|
|
h_free(w->buf);
|
|
|
|
|
h_free(w);
|
2012-07-27 15:28:55 -07:00
|
|
|
}
|