Compare commits
4 commits
ffc22e74c0
...
1282fa4523
| Author | SHA1 | Date | |
|---|---|---|---|
| 1282fa4523 | |||
| ab46ac051b | |||
| ad12631a1a | |||
| a4f8b9ca30 |
4 changed files with 303 additions and 3 deletions
38
axl_rle.c
38
axl_rle.c
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
u32 axl_rle_encode(const u8* src, u32 src_size, u8* dst, u32 dst_size)
|
||||
{
|
||||
if (src == NULL || dst == NULL || src_size == 0 || dst_size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 vlq_buff[AXL_VLQ_MAX_LEN];
|
||||
const u8* head = src;
|
||||
u32 used_size = 0;
|
||||
|
|
@ -40,5 +45,38 @@ u32 axl_rle_encode(const u8* src, u32 src_size, u8* dst, u32 dst_size)
|
|||
|
||||
u32 axl_rle_decode(const u8* src, u32 src_size, u8* dst, u32 dst_size)
|
||||
{
|
||||
if (src == NULL || dst == NULL || src_size == 0 || dst_size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8* head = src;
|
||||
u32 used_size = 0;
|
||||
|
||||
while(head < src + src_size)
|
||||
{
|
||||
u32 repeat_count;
|
||||
u32 vlq_len = axl_vlq_decode(head, &repeat_count);
|
||||
|
||||
if(vlq_len == 0 || head + vlq_len + 1 > src + src_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
head += vlq_len;
|
||||
const u8 value = *head;
|
||||
head++;
|
||||
|
||||
used_size += repeat_count;
|
||||
|
||||
if(used_size > dst_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
axl_memset(dst, value, repeat_count);
|
||||
dst += repeat_count;
|
||||
}
|
||||
|
||||
return used_size;
|
||||
}
|
||||
|
|
|
|||
233
axl_rle_test.c
Normal file
233
axl_rle_test.c
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
#include "axl_memory.h"
|
||||
#include "axl_rle.h"
|
||||
#include "axl_koan.h"
|
||||
|
||||
#define ASSERT_ARRAY_EQ(expected, actual, size) \
|
||||
do { \
|
||||
const u8* _e = (expected); \
|
||||
const u8* _a = (actual); \
|
||||
u32 _s = (size); \
|
||||
for (u32 _i = 0; _i < _s; _i++) { \
|
||||
if (_e[_i] != _a[_i]) { \
|
||||
char _r[256]; \
|
||||
snprintf(_r, sizeof(_r), "Mismatch at index %u: exp 0x%02X, got 0x%02X", \
|
||||
_i, _e[_i], _a[_i]); \
|
||||
KOAN_FAIL(_r); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
KOAN(encode_empty)
|
||||
{
|
||||
u8 src[] = "";
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(src, 0, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(encode_single)
|
||||
{
|
||||
u8 src[] = {0xAA};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_encode(src, 1, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(2, size);
|
||||
ASSERT_UINT_EQ(0x01, dst[0]);
|
||||
ASSERT_UINT_EQ(0xAA, dst[1]);
|
||||
}
|
||||
|
||||
KOAN(encode_five_repeats)
|
||||
{
|
||||
u8 src[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_encode(src, 5, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(2, size);
|
||||
ASSERT_UINT_EQ(0x05, dst[0]);
|
||||
ASSERT_UINT_EQ(0xAA, dst[1]);
|
||||
}
|
||||
|
||||
KOAN(encode_three_runs)
|
||||
{
|
||||
u8 src[] = {0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xCC};
|
||||
u8 expected[] = {0x03, 0xAA, 0x02, 0xBB, 0x01, 0xCC};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_encode(src, 6, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(6, size);
|
||||
ASSERT_ARRAY_EQ(expected, dst, 6);
|
||||
}
|
||||
|
||||
KOAN(encode_interleaved)
|
||||
{
|
||||
u8 src[] = {0xAA, 0xAA, 0xBB, 0xBB, 0xAA, 0xAA};
|
||||
u8 expected[] = {0x02, 0xAA, 0x02, 0xBB, 0x02, 0xAA};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_encode(src, 6, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(6, size);
|
||||
ASSERT_ARRAY_EQ(expected, dst, 6);
|
||||
}
|
||||
|
||||
KOAN(encode_all_different)
|
||||
{
|
||||
u8 src[10];
|
||||
u8 dst[32];
|
||||
for (u32 i = 0; i < 10; i++) src[i] = (u8)i;
|
||||
u32 size = axl_rle_encode(src, 10, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(20, size);
|
||||
for (u32 i = 0; i < 10; i++) {
|
||||
ASSERT_UINT_EQ(0x01, dst[i*2]);
|
||||
ASSERT_UINT_EQ((u8)i, dst[i*2+1]);
|
||||
}
|
||||
}
|
||||
|
||||
KOAN(encode_null_ptr)
|
||||
{
|
||||
u8 src[] = {0xAA}, dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(NULL, 1, dst, sizeof(dst)));
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(src, 1, NULL, 32));
|
||||
}
|
||||
|
||||
KOAN(encode_zero_size)
|
||||
{
|
||||
u8 src[] = {0xAA};
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(src, 0, dst, sizeof(dst)));
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(src, 1, dst, 0));
|
||||
}
|
||||
|
||||
KOAN(encode_buffer_too_small)
|
||||
{
|
||||
u8 src[] = {0xAA, 0xAA, 0xAA, 0xBB};
|
||||
u8 dst[3];
|
||||
ASSERT_UINT_EQ(0, axl_rle_encode(src, 4, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(encode_max_127)
|
||||
{
|
||||
u8 src[127];
|
||||
u8 dst[32];
|
||||
for (u32 i = 0; i < 127; i++) src[i] = 0x77;
|
||||
u32 size = axl_rle_encode(src, 127, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(2, size);
|
||||
ASSERT_UINT_EQ(0x7F, dst[0]);
|
||||
ASSERT_UINT_EQ(0x77, dst[1]);
|
||||
}
|
||||
|
||||
KOAN(encode_decode_300)
|
||||
{
|
||||
u8 src[300];
|
||||
u8 encoded[32];
|
||||
u8 decoded[400];
|
||||
for (u32 i = 0; i < 300; i++) src[i] = 0x55;
|
||||
u32 encoded_size = axl_rle_encode(src, 300, encoded, sizeof(encoded));
|
||||
ASSERT_TRUE(encoded_size > 0 && encoded_size <= 6);
|
||||
u32 decoded_size = axl_rle_decode(encoded, encoded_size, decoded, sizeof(decoded));
|
||||
ASSERT_UINT_EQ(300, decoded_size);
|
||||
ASSERT_ARRAY_EQ(src, decoded, 300);
|
||||
}
|
||||
|
||||
KOAN(decode_empty)
|
||||
{
|
||||
u8 src[] = "";
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 0, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(decode_single)
|
||||
{
|
||||
u8 src[] = {0x01, 0xAA};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_decode(src, 2, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(1, size);
|
||||
ASSERT_UINT_EQ(0xAA, dst[0]);
|
||||
}
|
||||
|
||||
KOAN(decode_five)
|
||||
{
|
||||
u8 src[] = {0x05, 0xAA};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_decode(src, 2, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(5, size);
|
||||
for (u32 i = 0; i < 5; i++) ASSERT_UINT_EQ(0xAA, dst[i]);
|
||||
}
|
||||
|
||||
KOAN(decode_three_runs)
|
||||
{
|
||||
u8 src[] = {0x03, 0xAA, 0x02, 0xBB, 0x01, 0xCC};
|
||||
u8 expected[] = {0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xCC};
|
||||
u8 dst[32];
|
||||
u32 size = axl_rle_decode(src, 6, dst, sizeof(dst));
|
||||
ASSERT_UINT_EQ(6, size);
|
||||
ASSERT_ARRAY_EQ(expected, dst, 6);
|
||||
}
|
||||
|
||||
KOAN(decode_null_ptr)
|
||||
{
|
||||
u8 src[] = {0x01, 0xAA}, dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(NULL, 2, dst, sizeof(dst)));
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 2, NULL, 32));
|
||||
}
|
||||
|
||||
KOAN(decode_zero_size)
|
||||
{
|
||||
u8 src[] = {0x01, 0xAA};
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 0, dst, sizeof(dst)));
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 2, dst, 0));
|
||||
}
|
||||
|
||||
KOAN(decode_buffer_too_small)
|
||||
{
|
||||
u8 src[] = {0x05, 0xAA};
|
||||
u8 dst[3];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 2, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(decode_incomplete_vlq)
|
||||
{
|
||||
u8 src[] = {0x85};
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 1, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(decode_missing_value)
|
||||
{
|
||||
u8 src[] = {0x05};
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 1, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(decode_zero_count)
|
||||
{
|
||||
u8 src[] = {0x00, 0xAA};
|
||||
u8 dst[32];
|
||||
ASSERT_UINT_EQ(0, axl_rle_decode(src, 2, dst, sizeof(dst)));
|
||||
}
|
||||
|
||||
KOAN(roundtrip_simple)
|
||||
{
|
||||
u8 original[] = {0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xCC, 0xCC, 0xCC, 0xCC};
|
||||
u8 encoded[32];
|
||||
u8 decoded[32];
|
||||
u32 encoded_size = axl_rle_encode(original, 9, encoded, sizeof(encoded));
|
||||
ASSERT_TRUE(encoded_size > 0);
|
||||
u32 decoded_size = axl_rle_decode(encoded, encoded_size, decoded, sizeof(decoded));
|
||||
ASSERT_UINT_EQ(9, decoded_size);
|
||||
ASSERT_ARRAY_EQ(original, decoded, 9);
|
||||
}
|
||||
|
||||
KOAN(roundtrip_all_different)
|
||||
{
|
||||
u8 original[10];
|
||||
u8 encoded[32];
|
||||
u8 decoded[32];
|
||||
for (u32 i = 0; i < 10; i++) original[i] = (u8)i;
|
||||
u32 encoded_size = axl_rle_encode(original, 10, encoded, sizeof(encoded));
|
||||
ASSERT_UINT_EQ(20, encoded_size);
|
||||
u32 decoded_size = axl_rle_decode(encoded, encoded_size, decoded, sizeof(decoded));
|
||||
ASSERT_UINT_EQ(10, decoded_size);
|
||||
ASSERT_ARRAY_EQ(original, decoded, 10);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
axl_init();
|
||||
return koan_run_all();
|
||||
}
|
||||
33
main.c
33
main.c
|
|
@ -2,14 +2,20 @@
|
|||
#include "axl_io.h"
|
||||
#include "axl_memory.h"
|
||||
#include "axl_string.h"
|
||||
#include "axl_vlq.h"
|
||||
#include "axl_rle.h"
|
||||
#include "axl_memory.h"
|
||||
#include <windows.h>
|
||||
|
||||
void *memset(void *s, int c, size_t n)
|
||||
void* memset(void *s, int c, size_t n)
|
||||
{
|
||||
return axl_memset(s, (i8)c, n);
|
||||
}
|
||||
|
||||
void* memcpy(void* dst, const void * src, unsigned long long count)
|
||||
{
|
||||
return axl_memcpy(dst, src, (u32)count);
|
||||
}
|
||||
|
||||
int _start(void)
|
||||
{
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
|
@ -59,6 +65,29 @@ int _start(void)
|
|||
axl_puts("}");
|
||||
}
|
||||
|
||||
i8 original[] = "00000000022222255555554444444443333339999435999923";
|
||||
i8 encoded[2*sizeof(original)] = {'\0'};
|
||||
i8 decoded[sizeof(original)];
|
||||
|
||||
axl_puts(original);
|
||||
u32 encoded_len = axl_rle_encode((u8*)original, sizeof(original),
|
||||
(u8*)encoded, sizeof(encoded));
|
||||
axl_puts(encoded);
|
||||
axl_rle_decode((u8*)encoded, encoded_len, (u8*)decoded, sizeof(original));
|
||||
axl_puts(decoded);
|
||||
|
||||
i8 orig_size_str[10] = {'\0'};
|
||||
i8 enc_size_str[10] = {'\0'};
|
||||
|
||||
axl_utoa(sizeof(original), orig_size_str, 10);
|
||||
axl_utoa(encoded_len, enc_size_str, 10);
|
||||
|
||||
i8 text_buff[255] = {'\0'};
|
||||
axl_strcat(text_buff, "Original length: ");
|
||||
axl_strcat(text_buff, orig_size_str);
|
||||
axl_strcat(text_buff, "\nEncoded length: ");
|
||||
axl_strcat(text_buff, enc_size_str);
|
||||
axl_puts(text_buff);
|
||||
|
||||
/*u32 new_len = 0;*/
|
||||
/*u8 src[] = "Bonjour le monde!";*/
|
||||
|
|
|
|||
2
makefile
2
makefile
|
|
@ -2,7 +2,7 @@ CC = clang
|
|||
AXL_SOURCES = $(filter-out main.c %_test.c, $(wildcard *.c))
|
||||
TEST_EXES = $(patsubst %.c,%.exe,$(wildcard *_test.c))
|
||||
TEST_CFLAGS = -Wall -Wextra -Werror -pedantic -std=c17 -static -Oz -fsigned-char
|
||||
CFLAGS = $(TEST_CFLAGS) -nostdlib -ffreestanding -fno-builtin
|
||||
CFLAGS = $(TEST_CFLAGS) -nostdlib -ffreestanding -fno-builtin -mno-stack-arg-probe
|
||||
LDFLAGS = -Wl,/SUBSYSTEM:CONSOLE,/ENTRY:_start -fuse-ld=lld
|
||||
LIBS = -lkernel32
|
||||
SOURCES = $(AXL_SOURCES) main.c
|
||||
|
|
|
|||
Loading…
Reference in a new issue