diff --git a/allcing.h b/allcing.h index 0ddf284..54e09be 100644 --- a/allcing.h +++ b/allcing.h @@ -15,10 +15,10 @@ // ---- variable points #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 #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 #if !defined(ACG_LOC_FULL) # define ACG_LOC_FULL (__FILE__ ":" ACG_UTIL_STR2(__func__) ":" ACG_UTIL_STR2(__LINE__)) @@ -33,11 +33,11 @@ // ---- sugar syntax for logging #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)) \ ) #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)) \ ) #define ACG_BEGIN(s) ( \ @@ -89,6 +89,8 @@ struct acg_stream { void* udata; }; + +#if !defined(ACG_NO_WRITE_FUNCTIONS) static inline bool acg_stream_write_pad(struct acg_stream* 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; const uint8_t unit_data_bits = unit_bits - 1U; - while (v) { + do { 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); - const uint8_t frag_bits = acg_util_umin(unit_data_bits, (8U - *c%8U)%8U); if (frag_bits > 0U) { buf[*c/8U] |= (v & acg_util_fullbits(frag_bits)) << (*c%8U); *c += 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); - memcpy(&buf[*c/8U], &v_part, (remain_bits + 7U) / 8U); - *c += remain_bits; + const uint8_t remain_bits = unit_data_bits - frag_bits; + if (remain_bits > 0U) { + assert(*c%8U == 0U); - 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; } -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) { 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) { assert(NULL != s); 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, tid, 16U); } @@ -220,3 +209,97 @@ static inline bool acg_stream_write_chunk_check(struct acg_stream* s) { assert(NULL != s); 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) diff --git a/test.c b/test.c index ead04a2..8b27e65 100644 --- a/test.c +++ b/test.c @@ -11,9 +11,9 @@ int main(int, char**) { -# define STREAM(size, offset) \ +# define STREAM(size, offset, ...) \ (struct acg_stream) { \ - .buffer = (uint8_t[size]) {0U}, \ + .buffer = (uint8_t[size]) {__VA_ARGS__ __VA_OPT__(,) 0U,}, \ .size_bytes = (size), \ .cursor_bits = (offset), \ } @@ -45,37 +45,30 @@ int main(int, char**) { /* acg_stream_write_uint / ends in a single byte */ { struct acg_stream s = STREAM(1024U, 0U); assert(acg_stream_write_uint(&s, 7U, 4U)); - assert(s.buffer[0U] == 0x0EU); + assert(s.buffer[0U] == 0x07U); assert(s.cursor_bits == 4U); } /* acg_stream_write_uint / ends in a single byte with offset */ { struct acg_stream s = STREAM(1024U, 1U); assert(acg_stream_write_uint(&s, 7U, 4U)); - assert(s.buffer[0U] == 0x1CU); + assert(s.buffer[0U] == 0x0EU); assert(s.cursor_bits == 5U); } /* acg_stream_write_uint / separated data bits */ { struct acg_stream s = STREAM(1024U, 6U); assert(acg_stream_write_uint(&s, 7U, 4U)); - assert(s.buffer[0U] == 0x80U); - assert(s.buffer[1U] == 0x03U); + assert(s.buffer[0U] == 0xC0U); + assert(s.buffer[1U] == 0x01U); assert(s.cursor_bits == 10U); } /* acg_stream_write_uint / separated cont flag */ { struct acg_stream s = STREAM(1024U, 7U); assert(acg_stream_write_uint(&s, 7U, 4U)); - assert(s.buffer[0U] == 0x00U); - assert(s.buffer[1U] == 0x07U); + assert(s.buffer[0U] == 0x80U); + assert(s.buffer[1U] == 0x03U); 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)); @@ -88,8 +81,20 @@ int main(int, char**) { 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); + 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( &s, 4U, (uint8_t[]) {0x00, 0x01, 0x02, 0x03})); assert(s.buffer[0U] == 0x82); @@ -100,29 +105,65 @@ int main(int, char**) { 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 */ { + /* acg_stream_write_chunk_blob / 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[0U] == 0x10); + assert(s.buffer[1U] == 0x04); 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_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; }