initial implementation complete
authorGeoffrey Allott <geoffrey@allott.email>
Sun, 31 Jul 2022 19:27:53 +0000 (20:27 +0100)
committerGeoffrey Allott <geoffrey@allott.email>
Sun, 31 Jul 2022 19:56:16 +0000 (20:56 +0100)
26 files changed:
Makefile
src/floor_log2.h
src/tans_buf_bit_reader.c
src/tans_buf_bit_writer.c
src/tans_constants.h
src/tans_decode_st.c
src/tans_decode_tbl.c
src/tans_decode_tbl.h
src/tans_encode_st.c
src/tans_encode_tbl.c
src/tans_encode_tbl.h
src/tans_file_bit_reader.c
src/tans_freq_tbl.c [new file with mode: 0644]
src/tans_freq_tbl.h
src/tans_rev_buf_bit_reader.c [new file with mode: 0644]
src/tans_rev_buf_bit_reader.h [new file with mode: 0644]
src/tans_symbol_tbl.c
src/tans_symbol_tbl.h
test/test.h
test/test_tans_bit_read_write.c [new file with mode: 0644]
test/test_tans_bit_reader [deleted file]
test/test_tans_bit_reader.c
test/test_tans_bit_writer [deleted file]
test/test_tans_encode_decode.c [new file with mode: 0644]
test/test_tans_encode_st [deleted file]
test/test_tans_encode_st.c

index cedffbd489f74a951cad12db82b419d3055529e0..2a5b509c86d836966b07c40da7ef530d0c41d2b5 100644 (file)
--- 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)
index 24c2e0efeefd7def7c8125a00e16ddeea50a911d..64e1e0bc332054ccebe82676546f578a37a7a93e 100644 (file)
@@ -1,22 +1,23 @@
 #pragma once
 
+#include <stdint.h>
+
 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;
 }
index 564549e4e89883a988afc9cce6984000847a21ca..e120ee001a4126c8498156942a59d96dd7c16557 100644 (file)
@@ -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;
     }
 
index 20186a1bacafb16c5f5d6f6eb32b5237f06db363..0d36ecdc42fd2f61524c7588f2d5e62df8c615a1 100644 (file)
@@ -1,5 +1,7 @@
 #include "tans_buf_bit_writer.h"
 
+#include <stdio.h>
+
 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) {
index ea031f2dd048ea43ee795ad135ac3a90c4869e96..16a816f432f5284499aaaedbac4ac158cd509283 100644 (file)
@@ -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
index c5077fc42a3c82a951c6ee1f5161819a60929211..19e6762d172cd755d82b6e594d76f5bfe3a7c2a2 100644 (file)
@@ -1,5 +1,7 @@
 #include "tans_decode_st.h"
 
+#include <stdio.h>
+
 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;
index e3feb24daaca1ba6a1d36d6eba5255a8d5d5f158..784ddac65bc154ebffb42689819cfb322eacff4b 100644 (file)
@@ -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);
     }
 }
index e1911764f6b019794abc1610c882c1f48b44672d..7c374a30cf675f33b6aa2fcb7671969d96f5249a 100644 (file)
@@ -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);
index d6c7232e5f4a2ddd9d833b59124ef167128ce6b9..6dc39301f7da0c53fe052ea89367091f0f8fc8ad 100644 (file)
@@ -1,23 +1,31 @@
 #include "tans_encode_st.h"
 
+#include <stdio.h>
+
 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;
 }
index a60ebdc1bc54c3325f9269367bb37a37bd39044b..6c01b756f0906df86a3f8467431b7311b1620774 100644 (file)
@@ -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;
     }
 }
index 79ccf30caf7b51b5f2c2ce974ef1be059342c5ae..fbae4205f715e0f4927d083d7eaf7a25f7197e6b 100644 (file)
@@ -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);
index fa79ddd75a612532ea6481b8a855e452e37f359e..a84a306958c8c7d1bb84de47fe3d07abb70da206 100644 (file)
@@ -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 (file)
index 0000000..23b88dd
--- /dev/null
@@ -0,0 +1,49 @@
+#include "tans_freq_tbl.h"
+
+#include <stdio.h>
+
+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;
+}
index d2ff754b7d6e4de7e56acc647a8bc5cc5ad49469..168067c5580d95212427d17459922402e4a626aa 100644 (file)
@@ -1,7 +1,13 @@
 #pragma once
 
+#include "tans_constants.h"
+
 #include <stdint.h>
 
 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 (file)
index 0000000..a0fe4a9
--- /dev/null
@@ -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 (file)
index 0000000..93f8b2b
--- /dev/null
@@ -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);
index a1237b98cc7e33a485540547f978e09aff4b454f..fe105fd8b945dac2aac0544f15190f550a8b3114 100644 (file)
@@ -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;
     }
 
index 985928ce303d2f974cb96b6f3e966ba04653b0d1..1392b5a974e865e21c18114d656ed095a10bbe41 100644 (file)
@@ -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);
index d9888ea3b955a4bf6a8d75a04851a6027b5501b3..31290bd7f22ef4b3177adab8143673e3a2778164 100644 (file)
@@ -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 (file)
index 0000000..4ce2153
--- /dev/null
@@ -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 (executable)
index 1f43ac2..0000000
Binary files a/test/test_tans_bit_reader and /dev/null differ
index f94a93168c252b057443dc24b61ae1e1344307b6..cc10851842274a20ac8870f2dc53e293b4326083 100644 (file)
@@ -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 (executable)
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 (file)
index 0000000..cdca52e
--- /dev/null
@@ -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 (executable)
index 5721161..0000000
Binary files a/test/test_tans_encode_st and /dev/null differ
index a7bb88468d599b60296860f9f7f8d74b90688c22..d4665b4f83bce0c4b72f798a530961f974e3cb50 100644 (file)
@@ -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);
 }