Merge bitwriter

This commit is contained in:
Meredith L. Patterson 2012-07-27 15:27:36 -07:00
commit b698e02b0c
5 changed files with 125 additions and 2 deletions

2
NOTES
View file

@ -35,4 +35,4 @@ what the comments say.
TODO: implement datastructure linearization func TODO: implement datastructure linearization func
TODO: implement free func for parsers TODO: implement free func for parsers
TODO: Reimplement GSequence et al for use with arena allocator. (*&%$#@ Glib doesn't allow per-datastructure allocators) TODO: Remove glib dependency (i.e., GQueue and GHashtable)

View file

@ -25,6 +25,7 @@ PARSERS := \
OUTPUTS := bitreader.o \ OUTPUTS := bitreader.o \
hammer.o \ hammer.o \
bitwriter.o \
libhammer.a \ libhammer.a \
pprint.o \ pprint.o \
allocator.o \ allocator.o \
@ -42,7 +43,7 @@ all: libhammer.a test_suite
test_suite: test_suite.o libhammer.a test_suite: test_suite.o libhammer.a
$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o \ libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o bitwriter.o \
$(PARSERS:%=parsers/%.o) $(PARSERS:%=parsers/%.o)
bitreader.o: test_suite.h bitreader.o: test_suite.h

93
src/bitwriter.c Normal file
View file

@ -0,0 +1,93 @@
#include <string.h>
#include <assert.h>
#include "hammer.h"
#include "internal.h"
// This file provides the logical inverse of bitreader.c
struct HBitWriter_ {
uint8_t* buf;
size_t index;
size_t capacity;
char bit_offset; // unlike in bit_reader, this is always the number
// of used bits in the current byte. i.e., 0 always
// means that 8 bits are available for use.
char flags;
};
// h_bit_writer_
HBitWriter *h_bit_writer_new() {
HBitWriter *writer = g_new0(HBitWriter, 1);
writer->buf = g_malloc0(writer->capacity = 8);
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) {
w->buf = g_realloc(w->buf, w->capacity *= 2);
}
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;
}
}
uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
// TESTS BELOW HERE

View file

@ -44,6 +44,7 @@ static HCachedResult *cached_result(const HParseState *state, HParseResult *resu
// Really library-internal tool to perform an uncached parse, and handle any common error-handling. // Really library-internal tool to perform an uncached parse, and handle any common error-handling.
static inline HParseResult* perform_lowlevel_parse(HParseState *state, const HParser *parser) { static inline HParseResult* perform_lowlevel_parse(HParseState *state, const HParser *parser) {
// TODO(thequux): these nested conditions are ugly. Factor this appropriately, so that it is clear which codes is executed when.
HParseResult *tmp_res; HParseResult *tmp_res;
if (parser) { if (parser) {
HInputStream bak = state->input_stream; HInputStream bak = state->input_stream;

View file

@ -79,6 +79,12 @@ typedef struct HParseResult_ {
HArena * arena; HArena * arena;
} HParseResult; } HParseResult;
/**
* TODO: document me.
* Relevant functions: h_bit_writer_new, h_bit_writer_put, h_bit_writer_get_buffer, h_bit_writer_free
*/
typedef struct HBitWriter_ HBitWriter;
/** /**
* Type of an action to apply to an AST, used in the action() parser. * Type of an action to apply to an AST, used in the action() parser.
* It can be any (user-defined) function that takes a HParseResult* * It can be any (user-defined) function that takes a HParseResult*
@ -454,4 +460,26 @@ char* h_write_result_unamb(const HParsedToken* tok);
*/ */
void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta); void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta);
/**
* TODO: Document me
*/
HBitWriter *h_bit_writer_new(void);
/**
* TODO: Document me
*/
void h_bit_writer_put(HBitWriter* w, unsigned long long data, size_t nbits);
/**
* TODO: Document me
* Must not free [w] until you're done with the result.
* [len] is in bytes.
*/
uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
/**
* TODO: Document me
*/
void h_bit_writer_free(HBitWriter* w);
#endif // #ifndef HAMMER_HAMMER__H #endif // #ifndef HAMMER_HAMMER__H