Compare commits

...

2 Commits

Author SHA1 Message Date
falsycat 34075fe42d add binary format description to README 2024-02-12 13:06:11 +09:00
falsycat 81e46ff140 implement chunk write functions 2024-02-12 13:05:34 +09:00
3 changed files with 188 additions and 15 deletions

View File

@ -13,6 +13,29 @@ ALLCING is a structured logging library featuring on lightweightness.
- compact log data with simple binary format
- completely-free license (WTFPLv2)
# Log Data Format
```
# [TOKEN] means TOKEN is optional
# <TOKEN> means TOKEN is constant and refer allcing.h for actual value
ROOT := CHUNK_BEGIN | CHUNK_END | CHUNK_CHECK
CHUNK_BEGIN := <ACG_CHUNK_BEGIN> [CHUNK_DATA]
CHUNK_END := <ACG_CHUNK_END> [CHUNK_DATA]
CHUNK_CHECK := <ACG_CHUNK_CHECK> [CHUNK_DATA]
CHUNK_DATA := CHUNK_PAD | CHUNK_BLOB | CHUNK_CTX | CHUNK_LOC | CHUNK_DATA
CHUNK_PAD := <ACG_CHUNK_PAD> PAD
CHUNK_BLOB := <ACG_CHUNK_BLOB> BLOB
CHUNK_CTX := <ACG_CHUNK_CTX> UINT(64) UINT(16)
CHUNK_LOC := <ACG_CHUNK_LOC> UINT(8) BLOB
PAD :=
BLOB :=
UINT(x) :=
```
# License
Do What The Fuck You Want to Public License v2

108
allcing.h
View File

@ -7,11 +7,15 @@
#include <string.h>
#define ACG_CHUNK_BLOB 0x00
#define ACG_CHUNK_PAD 0x00U
#define ACG_CHUNK_BLOB 0x01U
#define ACG_CHUNK_CTX 0x02U
#define ACG_CHUNK_LOC 0x03U
#define ACG_CHUNK_BEGIN 0x04U
#define ACG_CHUNK_END 0x05U
#define ACG_CHUNK_CHECK 0x06U
#define ACG_CHUNK_BEGIN 0x01
#define ACG_CHUNK_END 0x02
#define ACG_CHUNK_CHECK 0x03
#define ACG_UNITBITS_CHUNK_ID 4U
static inline uint64_t acg_util_fullbits(uint8_t bits) {
@ -29,7 +33,15 @@ struct acg_stream {
uint64_t cursor_bits;
};
static inline bool acg_stream_write_pad(struct acg_stream* s) {
assert(NULL != s);
s->cursor_bits = (s->cursor_bits+7U)/8U*8U;
return true;
}
static inline bool acg_stream_write_bool(struct acg_stream* s, bool v) {
assert(NULL != s);
if (s->size_bytes <= s->cursor_bits) {
return false;
}
@ -39,14 +51,19 @@ static inline bool acg_stream_write_bool(struct acg_stream* s, bool v) {
return true;
}
static inline bool acg_stream_write_uint(struct acg_stream* s, uint64_t v, uint8_t unit_bits) {
assert(unit_bits >= 2U);
assert(unit_bits <= 65U);
assert(NULL != s);
assert(2U <= unit_bits);
assert(65U >= unit_bits);
uint8_t* const buf = s->buffer;
uint64_t* const c = &s->cursor_bits;
const uint8_t unit_data_bits = unit_bits - 1U;
while (v) {
if (s->size_bytes*8U - *c < unit_bits) {
return false;
}
const uint64_t next_v = v >> unit_data_bits;
acg_stream_write_bool(s, !!next_v);
@ -66,7 +83,80 @@ static inline bool acg_stream_write_uint(struct acg_stream* s, uint64_t v, uint8
return true;
}
static inline bool acg_stream_write_int(struct acg_stream* s, int64_t v, uint8_t unit_bits) {
assert(unit_bits > 0);
const uint64_t uv = v >= 0? ((uint64_t) v): (~((uint64_t) -v) + 1);
return acg_stream_write_uint(s, uv, unit_bits);
assert(NULL != s);
assert(2U <= unit_bits);
assert(65U >= unit_bits);
if (v >= 0U) {
return
acg_stream_write_bool(s, false) &&
acg_stream_write_uint(s, (uint64_t) v, unit_bits);
} else {
return
acg_stream_write_bool(s, true) &&
acg_stream_write_uint(s, (uint64_t) -v, unit_bits);
}
}
static inline bool acg_stream_write_chunk_pad(struct acg_stream* s) {
assert(NULL != s);
if (s->cursor_bits%8U == 0U) {
return true;
}
if (s->size_bytes <= s->cursor_bits/8U) {
return false;
}
return
acg_stream_write_uint(s, ACG_CHUNK_PAD, ACG_UNITBITS_CHUNK_ID) &&
acg_stream_write_pad(s);
}
static inline bool acg_stream_write_chunk_blob(struct acg_stream* s, uint64_t size_bytes, const uint8_t* buf) {
assert(NULL != s);
if (!acg_stream_write_uint(s, ACG_CHUNK_BLOB, ACG_UNITBITS_CHUNK_ID)) {
return false;
}
if (!acg_stream_write_uint(s, size_bytes, 8U)) {
return false;
}
if (!acg_stream_write_pad(s)) {
return false;
}
uint64_t* const c = &s->cursor_bits;
const uint64_t avail_bytes = s->size_bytes - *c/8U;
if (avail_bytes < size_bytes) {
return false;
}
memcpy(&s->buffer[*c/8], buf, size_bytes);
const uint64_t size_bits = size_bytes * 8U;
*c += size_bits;
return true;
}
static inline bool acg_stream_write_chunk_begin(struct acg_stream* s) {
assert(NULL != s);
if (!acg_stream_write_uint(s, ACG_CHUNK_BEGIN, ACG_UNITBITS_CHUNK_ID)) {
return false;
}
return true;
}
static inline bool acg_stream_write_chunk_end(struct acg_stream* s) {
assert(NULL != s);
if (!acg_stream_write_uint(s, ACG_CHUNK_END, ACG_UNITBITS_CHUNK_ID)) {
return false;
}
return true;
}
static inline bool acg_stream_write_chunk_check(struct acg_stream* s) {
assert(NULL != s);
if (!acg_stream_write_uint(s, ACG_CHUNK_CHECK, ACG_UNITBITS_CHUNK_ID)) {
return false;
}
return true;
}

72
test.c
View File

@ -11,12 +11,6 @@
int main(int, char**) {
# define DEFINE_STREAM(name, offset) \
struct acg_stream s = { \
.buffer = (uint8_t[1024U]) {0U}, \
.size_bytes = 1024U, \
.cursor_bits = (offset), \
}
# define STREAM(size, offset) \
(struct acg_stream) { \
.buffer = (uint8_t[size]) {0U}, \
@ -24,6 +18,17 @@ int main(int, char**) {
.cursor_bits = (offset), \
}
/* acg_stream_write_pad / without offset */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_pad(&s));
assert(s.cursor_bits == 0U);
}
/* acg_stream_write_pad / with offset */ {
struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_write_pad(&s));
assert(s.cursor_bits == 8U);
}
/* acg_stream_write_bool / value=true */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_bool(&s, true));
@ -64,5 +69,60 @@ int main(int, char**) {
assert(s.cursor_bits == 11U);
}
/* acg_stream_write_int */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_int(&s, -1, 4U));
assert(s.buffer[0U] == 0x05U);
assert(s.cursor_bits == 5U);
}
/* acg_stream_write_chunk_pad / without offset */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_chunk_pad(&s));
assert(s.cursor_bits == 0U);
}
/* acg_stream_write_chunk_pad / with offset */ {
struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_write_chunk_pad(&s));
assert(s.buffer[0U] == 0U);
assert(s.cursor_bits == 8U);
}
/* acg_stream_write_chunk_pad / without offset */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_chunk_blob(
&s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03}));
assert(s.buffer[0U] == 0x82);
assert(s.buffer[1U] == 0x00);
assert(s.buffer[2U] == 0x00);
assert(s.buffer[3U] == 0x01);
assert(s.buffer[4U] == 0x02);
assert(s.buffer[5U] == 0x03);
assert(s.cursor_bits == 48U);
}
/* acg_stream_write_chunk_pad / with offset=1 */ {
struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_write_chunk_blob(
&s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03}));
assert(s.buffer[0U] == 0x04);
assert(s.buffer[1U] == 0x01);
assert(s.buffer[2U] == 0x00);
assert(s.buffer[3U] == 0x01);
assert(s.buffer[4U] == 0x02);
assert(s.buffer[5U] == 0x03);
assert(s.cursor_bits == 48U);
}
/* acg_stream_write_chunk_pad / with offset=4 */ {
struct acg_stream s = STREAM(1024U, 4U);
assert(acg_stream_write_chunk_blob(
&s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03}));
assert(s.buffer[0U] == 0x20);
assert(s.buffer[1U] == 0x08);
assert(s.buffer[2U] == 0x00);
assert(s.buffer[3U] == 0x01);
assert(s.buffer[4U] == 0x02);
assert(s.buffer[5U] == 0x03);
assert(s.cursor_bits == 48U);
}
return EXIT_SUCCESS;
}