From: Geoffrey Allott Date: Sun, 31 Jul 2022 19:27:53 +0000 (+0100) Subject: initial implementation complete X-Git-Url: https://git.pointlesshacks.com/?a=commitdiff_plain;h=70e2a49d7aa92a2b7786a959b31fb02aa9b489a5;p=tANS.git initial implementation complete --- diff --git a/Makefile b/Makefile index cedffbd..2a5b509 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -CFLAGS = -Isrc -g -Wall -Wextra -Wconversion +CFLAGS = -Isrc -g -Wall -Wextra -Wconversion -fsanitize=address -fsanitize=undefined +LDFLAGS = -lasan -lubsan OBJS = $(patsubst %.c, %.o, $(wildcard src/*.o)) TEST_OBJS = $(patsubst %.c, %.o, $(wildcard test/*.o)) @@ -19,8 +20,12 @@ test/test_tans_bit_reader.o: src/tans_buf_bit_reader.h src/tans_file_bit_reader. test/test_tans_bit_reader: src/tans_buf_bit_reader.o src/tans_file_bit_reader.o test/test_tans_bit_writer.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h test/test_tans_bit_writer: src/tans_buf_bit_writer.o +test/test_tans_bit_read_write.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h src/tans_rev_buf_bit_reader.h src/tans_bit_reader.h +test/test_tans_bit_read_write: src/tans_buf_bit_writer.o src/tans_rev_buf_bit_reader.o test/test_tans_encode_st.o: src/tans_buf_bit_writer.h src/tans_bit_writer.h src/tans_encode_st.h src/tans_symbol_tbl.h src/tans_freq_tbl.h -test/test_tans_encode_st: src/tans_buf_bit_writer.o src/tans_encode_st.o src/tans_encode_tbl.o src/tans_symbol_tbl.o +test/test_tans_encode_st: src/tans_buf_bit_writer.o src/tans_encode_st.o src/tans_encode_tbl.o src/tans_symbol_tbl.o src/tans_freq_tbl.o +test/test_tans_encode_decode.o: src/tans_rev_buf_bit_reader.h src/tans_bit_reader.h src/tans_decode_st.h src/tans_decode_tbl.h src/tans_buf_bit_writer.h src/tans_bit_writer.h src/tans_encode_st.h src/tans_encode_tbl.h src/tans_symbol_tbl.h src/tans_freq_tbl.h +test/test_tans_encode_decode: src/tans_rev_buf_bit_reader.o src/tans_decode_st.o src/tans_decode_tbl.o src/tans_buf_bit_writer.o src/tans_encode_st.o src/tans_encode_tbl.o src/tans_symbol_tbl.o src/tans_freq_tbl.o clean: rm -f $(OBJS) diff --git a/src/floor_log2.h b/src/floor_log2.h index 24c2e0e..64e1e0b 100644 --- a/src/floor_log2.h +++ b/src/floor_log2.h @@ -1,22 +1,23 @@ #pragma once +#include + static uint16_t floor_log2(uint16_t x) { - if (x <= 1) return 0; - if (x <= 2) return 1; - if (x <= 4) return 2; - if (x <= 8) return 3; - if (x <= 16) return 4; - if (x <= 32) return 5; - if (x <= 64) return 6; - if (x <= 128) return 7; - if (x <= 256) return 8; - if (x <= 512) return 9; - if (x <= 1024) return 10; - if (x <= 2048) return 11; - if (x <= 4096) return 12; - if (x <= 8192) return 13; - if (x <= 16384) return 14; - if (x <= 32768) return 15; - /*if (x <= 65536)*/ return 16; + if (x < 2) return 0; + if (x < 4) return 1; + if (x < 8) return 2; + if (x < 16) return 3; + if (x < 32) return 4; + if (x < 64) return 5; + if (x < 128) return 6; + if (x < 256) return 7; + if (x < 512) return 8; + if (x < 1024) return 9; + if (x < 2048) return 10; + if (x < 4096) return 11; + if (x < 8192) return 12; + if (x < 16384) return 13; + if (x < 32768) return 14; + /*if (x < 65536)*/ return 15; } diff --git a/src/tans_buf_bit_reader.c b/src/tans_buf_bit_reader.c index 564549e..e120ee0 100644 --- a/src/tans_buf_bit_reader.c +++ b/src/tans_buf_bit_reader.c @@ -6,7 +6,11 @@ static uint16_t tans_buf_bit_reader_read(struct tans_bit_reader *reader, uint8_t uint32_t bit = self->bit % 8; uint32_t byte = self->bit / 8; - if (bits == 0 || self->bit + bits > self->len * 8) { + if (bits == 0) { + return 0; + } + + if (self->bit + bits > self->len * 8) { return (uint16_t) -1; } diff --git a/src/tans_buf_bit_writer.c b/src/tans_buf_bit_writer.c index 20186a1..0d36ecd 100644 --- a/src/tans_buf_bit_writer.c +++ b/src/tans_buf_bit_writer.c @@ -1,5 +1,7 @@ #include "tans_buf_bit_writer.h" +#include + static uint16_t tans_buf_bit_writer_write(struct tans_bit_writer *writer, uint16_t value, uint8_t bits) { struct tans_buf_bit_writer *self = (struct tans_buf_bit_writer *) writer; @@ -14,6 +16,12 @@ static uint16_t tans_buf_bit_writer_write(struct tans_bit_writer *writer, uint16 return (uint16_t) -1; } + printf("DEBUG: writing bits "); + for (uint8_t i = 0; i < bits; i++) { + printf(value & (1 << i) ? "1" : "0"); + } + printf("\n"); + self->bit += bits; if (bit + bits <= 8) { diff --git a/src/tans_constants.h b/src/tans_constants.h index ea031f2..16a816f 100644 --- a/src/tans_constants.h +++ b/src/tans_constants.h @@ -1,4 +1,11 @@ #pragma once -#define TANS_R 10 -#define TANS_L (1 << TANS_R) +/* +#define TANS_LOG2_MAX_TBLSZ 10 +#define TANS_MAX_TBLSZ (1 << TANS_LOG2_MAX_TBLSZ) +#define TANS_MAX_SYMBOLS 256 +*/ + +#define TANS_LOG2_MAX_TBLSZ 12 +#define TANS_MAX_TBLSZ (1 << TANS_LOG2_MAX_TBLSZ) +#define TANS_MAX_SYMBOLS 256 diff --git a/src/tans_decode_st.c b/src/tans_decode_st.c index c5077fc..19e6762 100644 --- a/src/tans_decode_st.c +++ b/src/tans_decode_st.c @@ -1,5 +1,7 @@ #include "tans_decode_st.h" +#include + void tans_decode_st_init(struct tans_decode_st *self, struct tans_symbol_tbl *symbol_tbl) { tans_decode_tbl_init(&self->decode_tbl, symbol_tbl); @@ -12,9 +14,11 @@ uint16_t tans_decode_st_next(struct tans_decode_st *self, struct tans_bit_reader uint16_t read; struct tans_decode_tbl_entry t = self->decode_tbl.entries[self->x]; + printf("DEBUG: reading %d bits\n", t.nb_bits); + read = bit_reader->vtable->read(bit_reader, t.nb_bits); - if (read == -1) { - return -1; + if (read == (uint16_t) -1) { + return (uint16_t) -1; } ret = t.symbol; diff --git a/src/tans_decode_tbl.c b/src/tans_decode_tbl.c index e3feb24..784ddac 100644 --- a/src/tans_decode_tbl.c +++ b/src/tans_decode_tbl.c @@ -8,10 +8,12 @@ void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl * uint16_t x; uint8_t s; - for (i = 0; i < TANS_L; ++i) { + self->tblsz = symbol_tbl->tblsz; + + for (i = 0; i < self->tblsz; ++i) { s = self->entries[i].symbol = symbol_tbl->symbol[i]; x = symbol_tbl->entries[s].next++; - self->entries[s].nb_bits = TANS_R - floor_log2(x); - self->entries[s].new_x = (x << self->entries[s].nb_bits) - TANS_L; + self->entries[i].nb_bits = (uint8_t) (symbol_tbl->log2_tblsz - floor_log2(x)); + self->entries[i].new_x = (uint16_t) ((x << self->entries[i].nb_bits) - self->tblsz); } } diff --git a/src/tans_decode_tbl.h b/src/tans_decode_tbl.h index e191176..7c374a3 100644 --- a/src/tans_decode_tbl.h +++ b/src/tans_decode_tbl.h @@ -9,7 +9,8 @@ struct tans_decode_tbl_entry { }; struct tans_decode_tbl { - struct tans_decode_tbl_entry entries[TANS_L]; + uint16_t tblsz; + struct tans_decode_tbl_entry entries[TANS_MAX_TBLSZ]; }; void tans_decode_tbl_init(struct tans_decode_tbl *self, struct tans_symbol_tbl *symbol_tbl); diff --git a/src/tans_encode_st.c b/src/tans_encode_st.c index d6c7232..6dc3930 100644 --- a/src/tans_encode_st.c +++ b/src/tans_encode_st.c @@ -1,23 +1,31 @@ #include "tans_encode_st.h" +#include + void tans_encode_st_init(struct tans_encode_st *self, const struct tans_symbol_tbl *symbol_tbl) { self->symbol_tbl = *symbol_tbl; tans_encode_tbl_init(&self->encode_tbl, &self->symbol_tbl); - self->x = 0; + self->x = self->encode_tbl.tblsz; } uint16_t tans_encode_st_next(struct tans_encode_st *self, struct tans_bit_writer *bit_writer, uint8_t symbol) { uint8_t nb_bits; uint16_t written; + uint16_t i; + + printf("DEBUG: encoding %02x\n", symbol); - nb_bits = (uint8_t) ((self->x + TANS_L + self->symbol_tbl.entries[symbol].nb) >> (TANS_R + 1)); - written = bit_writer->vtable->write(bit_writer, self->x + TANS_L, nb_bits); + nb_bits = (uint8_t) ((self->x + self->symbol_tbl.entries[symbol].nb) >> (self->symbol_tbl.log2_tblsz + 1)); + written = bit_writer->vtable->write(bit_writer, self->x, nb_bits); if (written != nb_bits) { return (uint16_t) -1; } - self->x = self->encode_tbl.entries[self->symbol_tbl.entries[symbol].start + ((self->x + TANS_L) >> nb_bits)].x; + i = (uint16_t) (self->symbol_tbl.entries[symbol].start + (self->x >> nb_bits)); + self->x = self->encode_tbl.entries[i].x; + + printf("DEBUG: moving to state %d\n", self->x); return written; } diff --git a/src/tans_encode_tbl.c b/src/tans_encode_tbl.c index a60ebdc..6c01b75 100644 --- a/src/tans_encode_tbl.c +++ b/src/tans_encode_tbl.c @@ -3,10 +3,13 @@ void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl) { uint8_t s; - uint16_t x; + uint16_t i, x; - for (x = TANS_L; x < TANS_L << 1; ++x) { - s = symbol_tbl->symbol[x-TANS_L]; - self->entries[symbol_tbl->entries[s].start + symbol_tbl->entries[s].next++].x = x - TANS_L; + self->tblsz = symbol_tbl->tblsz; + + for (x = self->tblsz; x < self->tblsz << 1; ++x) { + s = symbol_tbl->symbol[x-self->tblsz]; + i = (uint16_t) (symbol_tbl->entries[s].start + symbol_tbl->entries[s].next++); + self->entries[i].x = x; } } diff --git a/src/tans_encode_tbl.h b/src/tans_encode_tbl.h index 79ccf30..fbae420 100644 --- a/src/tans_encode_tbl.h +++ b/src/tans_encode_tbl.h @@ -8,8 +8,8 @@ struct tans_encode_tbl_entry { }; struct tans_encode_tbl { - // TODO verify size of entries table - struct tans_encode_tbl_entry entries[TANS_L]; + uint16_t tblsz; + struct tans_encode_tbl_entry entries[TANS_MAX_TBLSZ]; }; void tans_encode_tbl_init(struct tans_encode_tbl *self, struct tans_symbol_tbl *symbol_tbl); diff --git a/src/tans_file_bit_reader.c b/src/tans_file_bit_reader.c index fa79ddd..a84a306 100644 --- a/src/tans_file_bit_reader.c +++ b/src/tans_file_bit_reader.c @@ -12,7 +12,7 @@ static uint16_t tans_file_bit_reader_read(struct tans_bit_reader *reader, uint8_ uint32_t byte = self->bit / 8; if (bits == 0) { - return (uint16_t) -1; + return 0; } while (self->len * 8 - self->bit < bits) { diff --git a/src/tans_freq_tbl.c b/src/tans_freq_tbl.c new file mode 100644 index 0000000..23b88dd --- /dev/null +++ b/src/tans_freq_tbl.c @@ -0,0 +1,49 @@ +#include "tans_freq_tbl.h" + +#include + +int tans_freq_tbl_init(struct tans_freq_tbl *self, uint16_t n_symbols, double *p, uint16_t log2_tblsz) +{ + uint16_t i, tblsz, total; + double total_p; + + if (n_symbols == 0) return -1; + if (n_symbols > TANS_MAX_SYMBOLS) return -1; + if (log2_tblsz > TANS_LOG2_MAX_TBLSZ) return -1; + + self->n_symbols = n_symbols; + self->log2_tblsz = log2_tblsz; + tblsz = 1 << log2_tblsz; + + if (tblsz < n_symbols) return -1; + + total_p = 0.0; + for (i = 0; i < n_symbols; ++i) { + total_p += p[i]; + } + + total = 0; + for (i = 0; i < n_symbols; ++i) { + self->freq[i] = (uint16_t) ((p[i] / total_p + 0.5 / tblsz) * tblsz); + if (self->freq[i] == 0) ++self->freq[i]; + total += self->freq[i]; + } + + while (total < tblsz) { + for (i = 0; i < n_symbols && total < tblsz; ++i) { + ++self->freq[i]; + ++total; + } + } + + while (total > tblsz) { + for (i = 0; i < n_symbols && total > tblsz; ++i) { + if (self->freq[i] > 1) { + --self->freq[i]; + --total; + } + } + } + + return 0; +} diff --git a/src/tans_freq_tbl.h b/src/tans_freq_tbl.h index d2ff754..168067c 100644 --- a/src/tans_freq_tbl.h +++ b/src/tans_freq_tbl.h @@ -1,7 +1,13 @@ #pragma once +#include "tans_constants.h" + #include struct tans_freq_tbl { - uint16_t freq[256]; + uint16_t n_symbols; + uint16_t log2_tblsz; + uint16_t freq[TANS_MAX_SYMBOLS]; }; + +int tans_freq_tbl_init(struct tans_freq_tbl *self, uint16_t n_symbols, double *p, uint16_t log2_tblsz); diff --git a/src/tans_rev_buf_bit_reader.c b/src/tans_rev_buf_bit_reader.c new file mode 100644 index 0000000..a0fe4a9 --- /dev/null +++ b/src/tans_rev_buf_bit_reader.c @@ -0,0 +1,40 @@ +#include "tans_rev_buf_bit_reader.h" + +static uint16_t tans_rev_buf_bit_reader_read(struct tans_bit_reader *reader, uint8_t bits) +{ + struct tans_rev_buf_bit_reader *self = (struct tans_rev_buf_bit_reader *) reader; + uint32_t bit = self->bit % 8 + (uint32_t) 8 * (self->bit % 8 == 0); + uint32_t byte = (self->bit - 1) / 8; + + if (bits == 0) { + return 0; + } + + if (self->bit < bits) { + return (uint16_t) -1; + } + + self->bit -= bits; + + if (8 - bit + bits <= 8) { + return (uint16_t) (((1 << bits) - 1) & (self->buf[byte] >> (bit - bits))); + } else if (8 - bit + bits <= 16) { + return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte-1] | (self->buf[byte] << 8)) >> (bit + 8 - bits))); + } else if (8 - bit + bits <= 24) { + return (uint16_t) (((1 << bits) - 1) & ((self->buf[byte-2] | (self->buf[byte-1] << 8) | (self->buf[byte] << 16)) >> (bit + 16 - bits))); + } else { + return (uint16_t) -1; + } +} + +static const struct tans_bit_reader_ops vtable = { + .read = tans_rev_buf_bit_reader_read, +}; + +void tans_rev_buf_bit_reader_init(struct tans_rev_buf_bit_reader *self, const uint8_t *buf, uint32_t len) +{ + self->vtable = &vtable; + self->bit = len * 8; + self->len = len; + self->buf = buf; +} diff --git a/src/tans_rev_buf_bit_reader.h b/src/tans_rev_buf_bit_reader.h new file mode 100644 index 0000000..93f8b2b --- /dev/null +++ b/src/tans_rev_buf_bit_reader.h @@ -0,0 +1,12 @@ +#pragma once + +#include "tans_bit_reader.h" + +struct tans_rev_buf_bit_reader { + const struct tans_bit_reader_ops *vtable; + uint32_t bit; + uint32_t len; + const uint8_t *buf; +}; + +void tans_rev_buf_bit_reader_init(struct tans_rev_buf_bit_reader *self, const uint8_t *buf, uint32_t len); diff --git a/src/tans_symbol_tbl.c b/src/tans_symbol_tbl.c index a1237b9..fe105fd 100644 --- a/src/tans_symbol_tbl.c +++ b/src/tans_symbol_tbl.c @@ -6,25 +6,29 @@ int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tb { uint16_t x, step, s, i, start, freq, k; + self->n_symbols = freq_tbl->n_symbols; + self->log2_tblsz = freq_tbl->log2_tblsz; + self->tblsz = 1 << self->log2_tblsz; + x = 0; - step = TANS_L*5/8 + 3; + step = (uint16_t) (self->tblsz * 5 / 8 + 3); start = 0; - for (s = 0; s < 256; ++s) { + for (s = 0; s < self->n_symbols; ++s) { freq = freq_tbl->freq[s]; - self->entries[s].start = start; + self->entries[s].start = start - freq; self->entries[s].next = freq; - k = TANS_R - floor_log2(freq); - self->entries[s].nb = (uint16_t) ((k << (TANS_R + 1)) - (freq << k)); + k = self->log2_tblsz - floor_log2(freq); + self->entries[s].nb = (uint32_t) ((k << (self->log2_tblsz + 1)) - (freq << k)); start += freq; for (i = 0; i < freq; ++i) { self->symbol[x] = (uint8_t) s; x += step; - x %= TANS_L; + x &= self->tblsz - 1; } } - if (start != TANS_L) { // freq entries must add up to TANS_L + if (start != self->tblsz) { // freq entries must add up to tblsz return -1; } diff --git a/src/tans_symbol_tbl.h b/src/tans_symbol_tbl.h index 985928c..1392b5a 100644 --- a/src/tans_symbol_tbl.h +++ b/src/tans_symbol_tbl.h @@ -4,14 +4,17 @@ #include "tans_freq_tbl.h" struct tans_symbol_tbl_entry { - uint16_t nb; + uint32_t nb; uint16_t start; uint16_t next; }; struct tans_symbol_tbl { - uint8_t symbol[TANS_L]; - struct tans_symbol_tbl_entry entries[256]; + uint16_t n_symbols; + uint16_t log2_tblsz; + uint16_t tblsz; + uint8_t symbol[TANS_MAX_TBLSZ]; + struct tans_symbol_tbl_entry entries[TANS_MAX_SYMBOLS]; }; int tans_symbol_tbl_init(struct tans_symbol_tbl *self, const struct tans_freq_tbl *freq_tbl); diff --git a/test/test.h b/test/test.h index d9888ea..31290bd 100644 --- a/test/test.h +++ b/test/test.h @@ -11,7 +11,7 @@ enum test_result { #define ASSERT_EQ(lhs, rhs) do { \ long a = (long) (lhs), b = (long) (rhs); \ if ((a) != (b)) { \ - printf("ERROR: " #lhs " (%ld) != " #rhs " (%ld)\n", (a), (b)); \ + printf("ERROR: %s:%d: %s (%ld) != %s (%ld)\n", __FILE__, __LINE__, #lhs, a, #rhs, b); \ return TEST_FAILURE; \ } \ } while(0) @@ -19,7 +19,15 @@ enum test_result { #define ASSERT_NE(lhs, rhs) do { \ long a = (long) (lhs), b = (long) (rhs); \ if ((a) == (b)) { \ - printf("ERROR: " #lhs " (%ld) == " #rhs " (%ld)\n", (a), (b)); \ + printf("ERROR: %s:%d: %s (%ld) == %s (%ld)\n", __FILE__, __LINE__, #lhs, a, #rhs, b); \ + return TEST_FAILURE; \ + } \ + } while(0) + +#define ASSERT_LT(lhs, rhs) do { \ + long a = (long) (lhs), b = (long) (rhs); \ + if ((a) >= (b)) { \ + printf("ERROR: %s:%d: %s (%ld) >= %s (%ld)\n", __FILE__, __LINE__, #lhs, a, #rhs, b); \ return TEST_FAILURE; \ } \ } while(0) diff --git a/test/test_tans_bit_read_write.c b/test/test_tans_bit_read_write.c new file mode 100644 index 0000000..4ce2153 --- /dev/null +++ b/test/test_tans_bit_read_write.c @@ -0,0 +1,48 @@ +#include "test.h" + +#include "tans_buf_bit_writer.h" +#include "tans_rev_buf_bit_reader.h" + +enum test_result test_tans_buf_bit_write_read_rev(void) +{ + struct tans_buf_bit_writer buf_bit_writer; + struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; + struct tans_rev_buf_bit_reader buf_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &buf_bit_reader; + uint8_t buf[8] = {0}; + + tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf); + tans_rev_buf_bit_reader_init(&buf_bit_reader, buf, sizeof buf); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 0), 0); + + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 8), 8); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x2f, 6), 6); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 2), 2); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x3fe0, 16), 16); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xd0, 8), 8); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x0f, 7), 7); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 1, 1), 1); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0, 3), 3); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0x18, 5), 5); + ASSERT_EQ(bit_writer->vtable->write(bit_writer, 0xf, 4), 4); + + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 4), 0xf); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 5), 0x18); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 3), 0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 1), 1); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 7), 0x0f); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 8), 0xd0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 16), 0x3fe0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 2), 0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 6), 0x2f); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 4), 0xf); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 8), 1); + + return TEST_SUCCESS; +} + +int main(void) +{ + RUN_TEST(test_tans_buf_bit_write_read_rev); +} diff --git a/test/test_tans_bit_reader b/test/test_tans_bit_reader deleted file mode 100755 index 1f43ac2..0000000 Binary files a/test/test_tans_bit_reader and /dev/null differ diff --git a/test/test_tans_bit_reader.c b/test/test_tans_bit_reader.c index f94a931..cc10851 100644 --- a/test/test_tans_bit_reader.c +++ b/test/test_tans_bit_reader.c @@ -5,38 +5,39 @@ enum test_result test_tans_buf_bit_reader(void) { - struct tans_buf_bit_reader bit_reader; + struct tans_buf_bit_reader buf_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &buf_bit_reader; uint8_t buf[8] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0xfd, 0x08, 0xfc}; - tans_buf_bit_reader_init(&bit_reader, buf, sizeof buf); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1); - - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 1); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 6), 0x2f); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 2), 0); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 16), 0x3fe0); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 8), 0xd0); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 7), 0x0f); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), 1); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 3), 0); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 5), 0x18); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 4), 0xf); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 1), (uint16_t) -1); + tans_buf_bit_reader_init(&buf_bit_reader, buf, sizeof buf); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 0), 0); + + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 8), 1); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 4), 0xf); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 6), 0x2f); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 2), 0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 16), 0x3fe0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 8), 0xd0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 7), 0x0f); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 1), 1); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 3), 0); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 5), 0x18); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 4), 0xf); + ASSERT_EQ(bit_reader->vtable->read(bit_reader, 1), (uint16_t) -1); return TEST_SUCCESS; } enum test_result test_tans_file_bit_reader(void) { - struct tans_file_bit_reader bit_reader; + struct tans_file_bit_reader file_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &file_bit_reader; uint8_t bits; - ASSERT_EQ(tans_file_bit_reader_init(&bit_reader, "/dev/zero"), 0); - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, 0), (uint16_t) -1); + ASSERT_EQ(tans_file_bit_reader_init(&file_bit_reader, "/dev/zero"), 0); - for (bits = 1; bits <= 16; ++bits) { - ASSERT_EQ(bit_reader.vtable->read((struct tans_bit_reader *) &bit_reader, bits), 0); + for (bits = 0; bits <= 16; ++bits) { + ASSERT_EQ(bit_reader->vtable->read(bit_reader, bits), 0); } return TEST_SUCCESS; diff --git a/test/test_tans_bit_writer b/test/test_tans_bit_writer deleted file mode 100755 index e8fe9ba..0000000 Binary files a/test/test_tans_bit_writer and /dev/null differ diff --git a/test/test_tans_encode_decode.c b/test/test_tans_encode_decode.c new file mode 100644 index 0000000..cdca52e --- /dev/null +++ b/test/test_tans_encode_decode.c @@ -0,0 +1,139 @@ +#include "test.h" + +#include "floor_log2.h" +#include "tans_buf_bit_writer.h" +#include "tans_decode_st.h" +#include "tans_encode_st.h" +#include "tans_rev_buf_bit_reader.h" + +enum test_result test_tans_encode_decode_equal_freq(void) +{ + struct tans_freq_tbl freq_tbl; + struct tans_symbol_tbl symbol_tbl; + struct tans_encode_st encode_st; + struct tans_buf_bit_writer buf_bit_writer; + struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; + struct tans_decode_st decode_st; + struct tans_rev_buf_bit_reader buf_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &buf_bit_reader; + uint8_t data[8] = {0x01, 0xfe, 0x32, 0x12, 0x06, 0x07, 0x88, 0x00}; + double p[256]; + uint8_t buf[8] = {0}; + uint16_t i; + uint16_t n_symbols = 256; + uint16_t log2_tblsz = 10; + + for (i = 0; i < n_symbols; ++i) p[i] = 1.0 / n_symbols; + ASSERT_NE(tans_freq_tbl_init(&freq_tbl, n_symbols, p, log2_tblsz), -1); + ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0); + tans_encode_st_init(&encode_st, &symbol_tbl); + tans_buf_bit_writer_init(&buf_bit_writer, buf, floor_log2(n_symbols)); + tans_decode_st_init(&decode_st, &symbol_tbl); + tans_rev_buf_bit_reader_init(&buf_bit_reader, buf, floor_log2(n_symbols)); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, (uint8_t) (data[i] % n_symbols)), (uint16_t) -1); + } + + ASSERT_EQ(buf_bit_writer.bit, buf_bit_writer.len * 8); + ASSERT_EQ(buf_bit_writer.bit, buf_bit_reader.bit); + + decode_st.x = (uint16_t) (encode_st.x - (1 << log2_tblsz)); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_EQ(tans_decode_st_next(&decode_st, bit_reader), data[sizeof data - 1 - i] % n_symbols); + } + + return TEST_SUCCESS; +} + +enum test_result test_tans_encode_decode_high_zero_probability(void) +{ + struct tans_freq_tbl freq_tbl; + struct tans_symbol_tbl symbol_tbl; + struct tans_encode_st encode_st; + struct tans_buf_bit_writer buf_bit_writer; + struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; + struct tans_decode_st decode_st; + struct tans_rev_buf_bit_reader buf_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &buf_bit_reader; + uint8_t data[8] = {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23}; + double p[256]; + uint8_t buf[8] = {0}; + uint16_t i; + uint16_t n_symbols = 256; + uint16_t log2_tblsz = 12; + + p[0] = 0.75; + for (i = 1; i < n_symbols; ++i) p[i] = 0.25 / n_symbols; + ASSERT_NE(tans_freq_tbl_init(&freq_tbl, n_symbols, p, log2_tblsz), -1); + ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0); + tans_encode_st_init(&encode_st, &symbol_tbl); + tans_buf_bit_writer_init(&buf_bit_writer, buf, floor_log2(n_symbols)); + tans_decode_st_init(&decode_st, &symbol_tbl); + tans_rev_buf_bit_reader_init(&buf_bit_reader, buf, floor_log2(n_symbols)); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, (uint8_t) (data[i] % n_symbols)), (uint16_t) -1); + } + + buf_bit_reader.bit = buf_bit_writer.bit; + decode_st.x = (uint16_t) (encode_st.x - (1 << log2_tblsz)); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_EQ(tans_decode_st_next(&decode_st, bit_reader), data[sizeof data - 1 - i] % n_symbols); + } + + return TEST_SUCCESS; +} + +enum test_result test_tans_encode_decode_long_stream(void) +{ + struct tans_freq_tbl freq_tbl; + struct tans_symbol_tbl symbol_tbl; + struct tans_encode_st encode_st; + struct tans_buf_bit_writer buf_bit_writer; + struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; + struct tans_decode_st decode_st; + struct tans_rev_buf_bit_reader buf_bit_reader; + struct tans_bit_reader *bit_reader = (struct tans_bit_reader *) &buf_bit_reader; + uint8_t data[65536]; + double p[256]; + uint8_t buf[32768] = {0}; + uint16_t n_symbols = 256; + uint16_t log2_tblsz = 10; + uint32_t i; + + p[0] = 0.75; + for (i = 1; i < n_symbols; ++i) p[i] = 0.25 / n_symbols; + ASSERT_NE(tans_freq_tbl_init(&freq_tbl, n_symbols, p, log2_tblsz), -1); + ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0); + tans_encode_st_init(&encode_st, &symbol_tbl); + tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf); + tans_decode_st_init(&decode_st, &symbol_tbl); + tans_rev_buf_bit_reader_init(&buf_bit_reader, buf, sizeof buf); + + for (i = 0; i < 65536; ++i) { + data[i] = (uint8_t) (i % 4 == 3 ? i / 4 : 0); + } + + for (i = 0; i < sizeof data; ++i) { + ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, (uint8_t) (data[i] % n_symbols)), (uint16_t) -1); + } + + buf_bit_reader.bit = buf_bit_writer.bit; + decode_st.x = (uint16_t) (encode_st.x - (1 << log2_tblsz)); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_EQ(tans_decode_st_next(&decode_st, bit_reader), data[sizeof data - 1 - i] % n_symbols); + } + + return TEST_SUCCESS; +} + +int main(void) +{ + RUN_TEST(test_tans_encode_decode_equal_freq); + RUN_TEST(test_tans_encode_decode_high_zero_probability); + RUN_TEST(test_tans_encode_decode_long_stream); +} diff --git a/test/test_tans_encode_st b/test/test_tans_encode_st deleted file mode 100755 index 5721161..0000000 Binary files a/test/test_tans_encode_st and /dev/null differ diff --git a/test/test_tans_encode_st.c b/test/test_tans_encode_st.c index a7bb884..d4665b4 100644 --- a/test/test_tans_encode_st.c +++ b/test/test_tans_encode_st.c @@ -1,5 +1,6 @@ #include "test.h" +#include "floor_log2.h" #include "tans_buf_bit_writer.h" #include "tans_encode_st.h" @@ -10,19 +11,21 @@ enum test_result test_tans_encode_st_equal_freq(void) struct tans_encode_st encode_st; struct tans_buf_bit_writer buf_bit_writer; struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; - uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + uint8_t data[8] = {0x01, 0xfe, 0x32, 0x12, 0x06, 0x07, 0x88, 0x00}; + double p[256]; uint8_t buf[8] = {0}; uint16_t i; + uint16_t n_symbols = 256; + uint16_t log2_tblsz = 10; - for (i = 0; i < 256; ++i) { - freq_tbl.freq[i] = TANS_L / 256; - } + for (i = 0; i < n_symbols; ++i) p[i] = 1.0 / n_symbols; + ASSERT_NE(tans_freq_tbl_init(&freq_tbl, n_symbols, p, log2_tblsz), -1); ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0); tans_encode_st_init(&encode_st, &symbol_tbl); - tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf); + tans_buf_bit_writer_init(&buf_bit_writer, buf, floor_log2(n_symbols)); for (i = 0; i < sizeof data; ++i) { - ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, data[i]), (uint16_t) -1); + ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, (uint8_t) (data[i] % n_symbols)), (uint16_t) -1); } ASSERT_EQ(buf_bit_writer.bit, buf_bit_writer.len * 8); @@ -31,7 +34,38 @@ enum test_result test_tans_encode_st_equal_freq(void) return TEST_SUCCESS; } +enum test_result test_tans_encode_st_high_zero_probability(void) +{ + struct tans_freq_tbl freq_tbl; + struct tans_symbol_tbl symbol_tbl; + struct tans_encode_st encode_st; + struct tans_buf_bit_writer buf_bit_writer; + struct tans_bit_writer *bit_writer = (struct tans_bit_writer *) &buf_bit_writer; + uint8_t data[8] = {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23}; + double p[256]; + uint8_t buf[16] = {0}; + uint16_t i; + uint16_t n_symbols = 256; + uint16_t log2_tblsz = 12; + + p[0] = 0.75; + for (i = 1; i < n_symbols; ++i) p[i] = 0.25 / n_symbols; + ASSERT_NE(tans_freq_tbl_init(&freq_tbl, n_symbols, p, log2_tblsz), -1); + ASSERT_EQ(tans_symbol_tbl_init(&symbol_tbl, &freq_tbl), 0); + tans_encode_st_init(&encode_st, &symbol_tbl); + tans_buf_bit_writer_init(&buf_bit_writer, buf, sizeof buf); + + for (i = 0; i < sizeof data; ++i) { + ASSERT_NE(tans_encode_st_next(&encode_st, bit_writer, (uint8_t) (data[i] % n_symbols)), (uint16_t) -1); + } + + ASSERT_LT(buf_bit_writer.bit, 24); + + return TEST_SUCCESS; +} + int main(void) { RUN_TEST(test_tans_encode_st_equal_freq); + RUN_TEST(test_tans_encode_st_high_zero_probability); }