Endian-independent binary IO utilities for C

Shift array much less often to reduce CPU load

Changed files
+64 -36
+64 -36
bini.h
··· 1 - #ifndef __bini__ 2 - #define __bini__ 3 4 /* 5 bini.h: endian-independent binary IO. 6 License: BSD 3-Clause. See EOF for license text. 7 8 - Version: 1.0 9 10 Changelog: 11 1.0 (Dec 28, 2025): Initial version. 12 */ 13 14 /* Used to add functions for version-specific types. */ ··· 100 { 101 /* Read mode for the stream. Should be either BINI_STACK or BINI_STREAM. */ 102 int mode; 103 size_t cap; 104 size_t len; 105 uint8_t *buffer; ··· 125 buffer, and frees the provided variable as well. */ 126 void bini_close(struct bini_stream *bs); 127 128 /* Flush a binary stream, clearing its buffer. */ 129 int bini_flush(struct bini_stream *); 130 /* Dump the binary stream's buffer to fp. */ ··· 255 bs->buffer = calloc(BINI_BUFSIZ, 1); 256 if (!bs->buffer) 257 return BINI_ERR; 258 bs->len = 0; 259 bs->cap = BINI_BUFSIZ; 260 bs->mode = BINI_STREAM; ··· 280 free(bs); 281 } 282 283 int bini_flush(struct bini_stream *bs) 284 { 285 size_t i; ··· 307 int _bini_grow(struct bini_stream *bs, size_t n) 308 { 309 uint8_t *newbuf; 310 if (bs->len + n < bs->cap) 311 return BINI_OK; 312 while (bs->len + n >= bs->cap) 313 { 314 newbuf = realloc(bs->buffer, bs->cap * 2); ··· 317 bs->buffer = newbuf; 318 bs->cap *= 2; 319 } 320 return BINI_OK; 321 } 322 ··· 334 return fwrite(bs->buffer, size, n, fp); 335 } 336 337 - static 338 - #if bini_c >= 1999 339 - inline 340 - #endif 341 - void _bini_shiftleft(struct bini_stream *bs, size_t n) 342 - { 343 - size_t i; 344 - _bini_dbg("shift %d: (len=%lu)\n", n, bs->len); 345 - for (i = 0 ; i < bs->len ; i++) 346 - { 347 - if (i+n >= bs->len) 348 - { 349 - _bini_dbg(" %d: [%d] (out of bounds) to [%d]\n", n, i+n, i); 350 - bs->buffer[i] = 0; 351 - continue; 352 - } 353 - _bini_dbg(" %d: [%d] (%02x '%c') to [%d]\n", 354 - n, 355 - i+n, 356 - bs->buffer[i+n], 357 - bs->buffer[i+n], 358 - i); 359 - bs->buffer[i] = bs->buffer[i+n]; 360 - } 361 - } 362 - 363 #define _bini_rwx(_type, _name) \ 364 void bini_w##_name(struct bini_stream *bs, _type v) \ 365 { \ ··· 376 l ? sizeof(v)-i-1 : i, \ 377 bytes[l ? sizeof(v)-i-1 : i], \ 378 bytes[l ? sizeof(v)-i-1 : i], \ 379 - bs->len+i); \ 380 - bs->buffer[bs->len+i] = bytes[l ? sizeof(v)-i-1 : i]; \ 381 } \ 382 bs->len += i; \ 383 _bini_dbg("-> %s: %d (%lu bytes)\n", __FUNCTION__, *(int *)bytes, sizeof(v)); \ ··· 391 int m = bs->mode == BINI_STREAM; \ 392 for (i = 0 ; i < sizeof(v) ; i++) \ 393 { \ 394 _bini_dbg("%s: byte index [%lu] from buffer index %lu (= %02x '%c')\n", \ 395 __FUNCTION__, \ 396 l ? sizeof(v)-i-1 : i, \ 397 - m ? i : (bs->len-sizeof(v)+i), \ 398 - bs->buffer[m ? i : (bs->len-sizeof(v)+i)], \ 399 - bs->buffer[m ? i : (bs->len-sizeof(v)+i)]); \ 400 - bytes[l ? sizeof(v)-i-1 : i] = bs->buffer[m ? i : (bs->len-sizeof(v)+i)]; \ 401 } \ 402 if (m) \ 403 - _bini_shiftleft(bs, i); \ 404 bs->len -= i; \ 405 return v; \ 406 }
··· 1 + #ifndef __kf_bini__ 2 + #define __kf_bini__ 3 4 /* 5 bini.h: endian-independent binary IO. 6 License: BSD 3-Clause. See EOF for license text. 7 8 + Version: 1.1 9 10 Changelog: 11 1.0 (Dec 28, 2025): Initial version. 12 + 1.1 (Dec 30, 2025): Use an offset instead of shifting the 13 + byte buffer so carelessly. _bini_grow will shift the 14 + buffer on-demand instead so as to conserve CPU time. 15 */ 16 17 /* Used to add functions for version-specific types. */ ··· 103 { 104 /* Read mode for the stream. Should be either BINI_STACK or BINI_STREAM. */ 105 int mode; 106 + /* Offset from the start of the buffer in bytes. Only used for BINI_STREAM. */ 107 + size_t off; 108 size_t cap; 109 size_t len; 110 uint8_t *buffer; ··· 130 buffer, and frees the provided variable as well. */ 131 void bini_close(struct bini_stream *bs); 132 133 + /* Shift a binary stream, resetting the offset and shifting the array. */ 134 + void bini_shift(struct bini_stream *); 135 /* Flush a binary stream, clearing its buffer. */ 136 int bini_flush(struct bini_stream *); 137 /* Dump the binary stream's buffer to fp. */ ··· 262 bs->buffer = calloc(BINI_BUFSIZ, 1); 263 if (!bs->buffer) 264 return BINI_ERR; 265 + bs->off = 0; 266 bs->len = 0; 267 bs->cap = BINI_BUFSIZ; 268 bs->mode = BINI_STREAM; ··· 288 free(bs); 289 } 290 291 + static 292 + #if bini_c >= 1999 293 + inline 294 + #endif 295 + void _bini_shiftleft(struct bini_stream *bs, size_t n) 296 + { 297 + size_t i; 298 + _bini_dbg("shift %d: (len=%lu)\n", n, bs->len); 299 + for (i = 0 ; i < bs->len ; i++) 300 + { 301 + if (i+n >= bs->len) 302 + { 303 + _bini_dbg(" %d: [%d] (out of bounds) to [%d]\n", n, i+n, i); 304 + bs->buffer[i] = 0; 305 + continue; 306 + } 307 + _bini_dbg(" %d: [%d] (%02x '%c') to [%d]\n", 308 + n, 309 + i+n, 310 + bs->buffer[i+n], 311 + bs->buffer[i+n], 312 + i); 313 + bs->buffer[i] = bs->buffer[i+n]; 314 + } 315 + } 316 + 317 + void bini_shift(struct bini_stream *bs) 318 + { 319 + _bini_shiftleft(bs, bs->off); 320 + bs->off = 0; 321 + } 322 + 323 int bini_flush(struct bini_stream *bs) 324 { 325 size_t i; ··· 347 int _bini_grow(struct bini_stream *bs, size_t n) 348 { 349 uint8_t *newbuf; 350 + 351 + if (bs->off + bs->len + n < bs->cap) 352 + return BINI_OK; 353 + 354 + /* Shifting the array could give enough space to 355 + fit `n`, avoiding the need to realloc. */ 356 + bini_shift(bs); 357 + 358 if (bs->len + n < bs->cap) 359 return BINI_OK; 360 + 361 while (bs->len + n >= bs->cap) 362 { 363 newbuf = realloc(bs->buffer, bs->cap * 2); ··· 366 bs->buffer = newbuf; 367 bs->cap *= 2; 368 } 369 + 370 return BINI_OK; 371 } 372 ··· 384 return fwrite(bs->buffer, size, n, fp); 385 } 386 387 #define _bini_rwx(_type, _name) \ 388 void bini_w##_name(struct bini_stream *bs, _type v) \ 389 { \ ··· 400 l ? sizeof(v)-i-1 : i, \ 401 bytes[l ? sizeof(v)-i-1 : i], \ 402 bytes[l ? sizeof(v)-i-1 : i], \ 403 + bs->off+bs->len+i); \ 404 + bs->buffer[bs->off+bs->len+i] = bytes[l ? sizeof(v)-i-1 : i]; \ 405 } \ 406 bs->len += i; \ 407 _bini_dbg("-> %s: %d (%lu bytes)\n", __FUNCTION__, *(int *)bytes, sizeof(v)); \ ··· 415 int m = bs->mode == BINI_STREAM; \ 416 for (i = 0 ; i < sizeof(v) ; i++) \ 417 { \ 418 + const size_t p = bs->off + (m ? i : (bs->len-sizeof(v)+i)); \ 419 _bini_dbg("%s: byte index [%lu] from buffer index %lu (= %02x '%c')\n", \ 420 __FUNCTION__, \ 421 l ? sizeof(v)-i-1 : i, \ 422 + p, \ 423 + bs->buffer[p], \ 424 + bs->buffer[p]); \ 425 + bytes[l ? sizeof(v)-i-1 : i] = bs->buffer[p]; \ 426 } \ 427 if (m) \ 428 + { \ 429 + bs->off += i; \ 430 + /* _bini_shiftleft(bs, i); */ \ 431 + } \ 432 bs->len -= i; \ 433 return v; \ 434 }