add acg_stream_read functions

This commit is contained in:
falsycat 2024-02-15 09:30:05 +09:00
parent a1cefa690d
commit 2d71b4cec2
2 changed files with 185 additions and 61 deletions

143
allcing.h
View File

@ -15,10 +15,10 @@
// ---- variable points // ---- variable points
#if !defined(ACG_NOW) #if !defined(ACG_NOW)
# define ACG_NOW ((uint64_t) (clock()/CLOCKS_PER_SEC*10000000U)) # define ACG_NOW ((uint64_t) ((double) clock()/CLOCKS_PER_SEC*1000000U))
#endif #endif
#if !defined(ACG_TID) #if !defined(ACG_TID)
# define ACG_TID (0U) // you should replace ACG_TID to log an actual TID # define ACG_TID (0x700FU) // you should replace ACG_TID to log an actual TID
#endif #endif
#if !defined(ACG_LOC_FULL) #if !defined(ACG_LOC_FULL)
# define ACG_LOC_FULL (__FILE__ ":" ACG_UTIL_STR2(__func__) ":" ACG_UTIL_STR2(__LINE__)) # define ACG_LOC_FULL (__FILE__ ":" ACG_UTIL_STR2(__func__) ":" ACG_UTIL_STR2(__LINE__))
@ -33,11 +33,11 @@
// ---- sugar syntax for logging // ---- sugar syntax for logging
#define ACG_BLOB_LITERAL(s, data) ( \ #define ACG_BLOB_LITERAL(s, data) ( \
acg_stream_write_blob((s), sizeof((data)), (const uint8_t*) (data)) && \ acg_stream_write_chunk_blob((s), sizeof((data)), (const uint8_t*) (data)) && \
ACG_FLUSH((s)) \ ACG_FLUSH((s)) \
) )
#define ACG_BLOB(s, size, data) ( \ #define ACG_BLOB(s, size, data) ( \
acg_stream_write_blob((s), (size), (const uint8_t*) (data)) && \ acg_stream_write_chunk_blob((s), (size), (const uint8_t*) (data)) && \
ACG_FLUSH((s)) \ ACG_FLUSH((s)) \
) )
#define ACG_BEGIN(s) ( \ #define ACG_BEGIN(s) ( \
@ -89,6 +89,8 @@ struct acg_stream {
void* udata; void* udata;
}; };
#if !defined(ACG_NO_WRITE_FUNCTIONS)
static inline bool acg_stream_write_pad(struct acg_stream* s) { static inline bool acg_stream_write_pad(struct acg_stream* s) {
assert(NULL != s); assert(NULL != s);
@ -115,44 +117,31 @@ static inline bool acg_stream_write_uint(struct acg_stream* s, uint64_t v, uint8
uint64_t* const c = &s->cursor_bits; uint64_t* const c = &s->cursor_bits;
const uint8_t unit_data_bits = unit_bits - 1U; const uint8_t unit_data_bits = unit_bits - 1U;
while (v) { do {
if (s->size_bytes*8U - *c < unit_bits) { if (s->size_bytes*8U - *c < unit_bits) {
return false; return false;
} }
const uint64_t next_v = v >> unit_data_bits;
acg_stream_write_bool(s, !!next_v);
const uint8_t frag_bits = acg_util_umin(unit_data_bits, (8U - *c%8U)%8U); const uint8_t frag_bits = acg_util_umin(unit_data_bits, (8U - *c%8U)%8U);
if (frag_bits > 0U) { if (frag_bits > 0U) {
buf[*c/8U] |= (v & acg_util_fullbits(frag_bits)) << (*c%8U); buf[*c/8U] |= (v & acg_util_fullbits(frag_bits)) << (*c%8U);
*c += frag_bits; *c += frag_bits;
} }
const uint8_t remain_bits = unit_data_bits - frag_bits; const uint8_t remain_bits = unit_data_bits - frag_bits;
const uint64_t v_part = (v >> frag_bits) & acg_util_fullbits(remain_bits); if (remain_bits > 0U) {
memcpy(&buf[*c/8U], &v_part, (remain_bits + 7U) / 8U); assert(*c%8U == 0U);
*c += remain_bits;
v = next_v; const uint64_t v_part = (v >> frag_bits) & acg_util_fullbits(remain_bits);
} memcpy(&buf[*c/8U], &v_part, (remain_bits + 7U) / 8U);
*c += remain_bits;
}
v >>= unit_data_bits;;
acg_stream_write_bool(s, !!v);
} while (v);
return true; return true;
} }
static inline bool acg_stream_write_int(struct acg_stream* s, int64_t v, uint8_t 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_blob(struct acg_stream* s, uint64_t size_bytes, const uint8_t* buf) { static inline bool acg_stream_write_blob(struct acg_stream* s, uint64_t size_bytes, const uint8_t* buf) {
assert(NULL != s); assert(NULL != s);
@ -198,7 +187,7 @@ static inline bool acg_stream_write_chunk_blob(struct acg_stream* s, uint64_t si
static inline bool acg_stream_write_chunk_ctx(struct acg_stream* s, uint64_t time, uint64_t tid) { static inline bool acg_stream_write_chunk_ctx(struct acg_stream* s, uint64_t time, uint64_t tid) {
assert(NULL != s); assert(NULL != s);
return return
acg_stream_write_uint(s, ACG_CHUNK_LOC, ACG_UNITBITS_CHUNK_ID) && acg_stream_write_uint(s, ACG_CHUNK_CTX, ACG_UNITBITS_CHUNK_ID) &&
acg_stream_write_uint(s, time, 64U) && acg_stream_write_uint(s, time, 64U) &&
acg_stream_write_uint(s, tid, 16U); acg_stream_write_uint(s, tid, 16U);
} }
@ -220,3 +209,97 @@ static inline bool acg_stream_write_chunk_check(struct acg_stream* s) {
assert(NULL != s); assert(NULL != s);
return acg_stream_write_uint(s, ACG_CHUNK_CHECK, ACG_UNITBITS_CHUNK_ID); return acg_stream_write_uint(s, ACG_CHUNK_CHECK, ACG_UNITBITS_CHUNK_ID);
} }
#endif // !defined(ACG_NO_WRITE_FUNCTIONS)
#if !defined(ACG_NO_READ_FUNCTIONS)
static inline bool acg_stream_read_pad(struct acg_stream* s) {
assert(NULL != s);
s->cursor_bits = (s->cursor_bits + 7U)/8U*8U;
return true;
}
static inline bool acg_stream_read_bool(struct acg_stream* s, bool* v) {
assert(NULL != s);
assert(NULL != v);
if (s->size_bytes*8U <= s->cursor_bits) {
return false;
}
uint64_t* const c = &s->cursor_bits;
*v = (s->buffer[*c/8U] >> (*c%8U)) & 1U;
++*c;
return true;
}
static inline bool acg_stream_read_uint(struct acg_stream* s, uint64_t* v, uint8_t unit_bits) {
assert(NULL != s);
assert(NULL != v);
assert(2U <= unit_bits);
assert(65U >= unit_bits);
*v = 0U;
const uint8_t unit_data_bits = unit_bits - 1U;
const uint8_t* const buf = s->buffer;
uint64_t* const c = &s->cursor_bits;
uint8_t v_offset_bits = 0U;
bool cont_flag = true;
while (cont_flag) {
if (s->size_bytes*8U < *c+unit_data_bits) {
return false;
}
const uint8_t frag_bits = acg_util_umin((8U - *c%8U)%8U, unit_data_bits);
if (frag_bits > 0U) {
const uint64_t v_part =
(buf[*c/8U] >> (*c%8U)) & acg_util_fullbits(frag_bits);
*v |= v_part << v_offset_bits;
*c += frag_bits;
v_offset_bits += frag_bits;
}
const uint8_t remain_bits = unit_data_bits - frag_bits;
if (remain_bits > 0U) {
assert(*c%8U == 0U);
uint64_t v_part = 0U;
memcpy(&v_part, &buf[*c/8U], (remain_bits+7U)/8U);
v_part &= acg_util_fullbits(remain_bits);
*v |= v_part << v_offset_bits;
*c += remain_bits;
v_offset_bits += remain_bits;
}
if (!acg_stream_read_bool(s, &cont_flag)) {
return false;
}
}
return true;
}
static inline bool acg_stream_read_blob(struct acg_stream* s, uint64_t* size, uint8_t** buf) {
assert(NULL != s);
assert(NULL != size);
assert(NULL != buf);
if (!acg_stream_read_uint(s, size, 8U)) {
return false;
}
if (!acg_stream_read_pad(s)) {
return false;
}
uint64_t* const c = &s->cursor_bits;
const uint64_t offset = *c/8U;
if (s->size_bytes < offset + *size) {
return false;
}
*buf = &s->buffer[offset];
*c += *size *8U;
return true;
}
#endif // !defined(ACG_NO_READ_FUNCTIONS)

103
test.c
View File

@ -11,9 +11,9 @@
int main(int, char**) { int main(int, char**) {
# define STREAM(size, offset) \ # define STREAM(size, offset, ...) \
(struct acg_stream) { \ (struct acg_stream) { \
.buffer = (uint8_t[size]) {0U}, \ .buffer = (uint8_t[size]) {__VA_ARGS__ __VA_OPT__(,) 0U,}, \
.size_bytes = (size), \ .size_bytes = (size), \
.cursor_bits = (offset), \ .cursor_bits = (offset), \
} }
@ -45,37 +45,30 @@ int main(int, char**) {
/* acg_stream_write_uint / ends in a single byte */ { /* acg_stream_write_uint / ends in a single byte */ {
struct acg_stream s = STREAM(1024U, 0U); struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_uint(&s, 7U, 4U)); assert(acg_stream_write_uint(&s, 7U, 4U));
assert(s.buffer[0U] == 0x0EU); assert(s.buffer[0U] == 0x07U);
assert(s.cursor_bits == 4U); assert(s.cursor_bits == 4U);
} }
/* acg_stream_write_uint / ends in a single byte with offset */ { /* acg_stream_write_uint / ends in a single byte with offset */ {
struct acg_stream s = STREAM(1024U, 1U); struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_write_uint(&s, 7U, 4U)); assert(acg_stream_write_uint(&s, 7U, 4U));
assert(s.buffer[0U] == 0x1CU); assert(s.buffer[0U] == 0x0EU);
assert(s.cursor_bits == 5U); assert(s.cursor_bits == 5U);
} }
/* acg_stream_write_uint / separated data bits */ { /* acg_stream_write_uint / separated data bits */ {
struct acg_stream s = STREAM(1024U, 6U); struct acg_stream s = STREAM(1024U, 6U);
assert(acg_stream_write_uint(&s, 7U, 4U)); assert(acg_stream_write_uint(&s, 7U, 4U));
assert(s.buffer[0U] == 0x80U); assert(s.buffer[0U] == 0xC0U);
assert(s.buffer[1U] == 0x03U); assert(s.buffer[1U] == 0x01U);
assert(s.cursor_bits == 10U); assert(s.cursor_bits == 10U);
} }
/* acg_stream_write_uint / separated cont flag */ { /* acg_stream_write_uint / separated cont flag */ {
struct acg_stream s = STREAM(1024U, 7U); struct acg_stream s = STREAM(1024U, 7U);
assert(acg_stream_write_uint(&s, 7U, 4U)); assert(acg_stream_write_uint(&s, 7U, 4U));
assert(s.buffer[0U] == 0x00U); assert(s.buffer[0U] == 0x80U);
assert(s.buffer[1U] == 0x07U); assert(s.buffer[1U] == 0x03U);
assert(s.cursor_bits == 11U); 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 */ { /* acg_stream_write_chunk_pad / without offset */ {
struct acg_stream s = STREAM(1024U, 0U); struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_write_chunk_pad(&s)); assert(acg_stream_write_chunk_pad(&s));
@ -88,8 +81,20 @@ int main(int, char**) {
assert(s.cursor_bits == 8U); assert(s.cursor_bits == 8U);
} }
/* acg_stream_write_chunk_pad / without offset */ { /* acg_stream_write_chunk_blob / without offset */ {
struct acg_stream s = STREAM(1024U, 0U); 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] == 0x41);
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_blob / with offset=1 */ {
struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_write_chunk_blob( assert(acg_stream_write_chunk_blob(
&s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03}));
assert(s.buffer[0U] == 0x82); assert(s.buffer[0U] == 0x82);
@ -100,29 +105,65 @@ int main(int, char**) {
assert(s.buffer[5U] == 0x03); assert(s.buffer[5U] == 0x03);
assert(s.cursor_bits == 48U); assert(s.cursor_bits == 48U);
} }
/* acg_stream_write_chunk_pad / with offset=1 */ { /* acg_stream_write_chunk_blob / with offset=4 */ {
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); struct acg_stream s = STREAM(1024U, 4U);
assert(acg_stream_write_chunk_blob( assert(acg_stream_write_chunk_blob(
&s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03}));
assert(s.buffer[0U] == 0x20); assert(s.buffer[0U] == 0x10);
assert(s.buffer[1U] == 0x08); assert(s.buffer[1U] == 0x04);
assert(s.buffer[2U] == 0x00); assert(s.buffer[2U] == 0x00);
assert(s.buffer[3U] == 0x01); assert(s.buffer[3U] == 0x01);
assert(s.buffer[4U] == 0x02); assert(s.buffer[4U] == 0x02);
assert(s.buffer[5U] == 0x03); assert(s.buffer[5U] == 0x03);
assert(s.cursor_bits == 48U); assert(s.cursor_bits == 48U);
} }
/* acg_stream_read_pad / without offset */ {
struct acg_stream s = STREAM(1024U, 0U);
assert(acg_stream_read_pad(&s));
assert(s.cursor_bits == 0U);
}
/* acg_stream_read_pad / with offset=1 */ {
struct acg_stream s = STREAM(1024U, 1U);
assert(acg_stream_read_pad(&s));
assert(s.cursor_bits == 8U);
}
/* acg_stream_read_bool / with value=false */ {
struct acg_stream s = STREAM(1024U, 0U);
bool v;
assert(acg_stream_read_bool(&s, &v));
assert(v == false);
assert(s.cursor_bits == 1U);
}
/* acg_stream_read_bool / with value=true */ {
struct acg_stream s = STREAM(1024U, 0U, 0x01U);
bool v;
assert(acg_stream_read_bool(&s, &v));
assert(v == true);
assert(s.cursor_bits == 1U);
}
/* acg_stream_read_uint / with a single unit */ {
struct acg_stream s = STREAM(1024U, 0U, 0x04U);
uint64_t v;
assert(acg_stream_read_uint(&s, &v, 4U));
assert(v == 4U);
assert(s.cursor_bits == 4U);
}
/* acg_stream_read_uint / with multi units */ {
struct acg_stream s = STREAM(1024U, 0U, 0x48U);
uint64_t v;
assert(acg_stream_read_uint(&s, &v, 4U));
assert(v == 32U);
assert(s.cursor_bits == 8U);
}
/* acg_stream_read_uint / with multi bytes */ {
struct acg_stream s = STREAM(1024U, 0U, 0x88U, 0x04U);
uint64_t v;
assert(acg_stream_read_uint(&s, &v, 4U));
assert(v == 256U);
assert(s.cursor_bits == 12U);
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }