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__ 1 + #ifndef __kf_bini__ 2 + #define __kf_bini__ 3 3 4 4 /* 5 5 bini.h: endian-independent binary IO. 6 6 License: BSD 3-Clause. See EOF for license text. 7 7 8 - Version: 1.0 8 + Version: 1.1 9 9 10 10 Changelog: 11 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. 12 15 */ 13 16 14 17 /* Used to add functions for version-specific types. */ ··· 100 103 { 101 104 /* Read mode for the stream. Should be either BINI_STACK or BINI_STREAM. */ 102 105 int mode; 106 + /* Offset from the start of the buffer in bytes. Only used for BINI_STREAM. */ 107 + size_t off; 103 108 size_t cap; 104 109 size_t len; 105 110 uint8_t *buffer; ··· 125 130 buffer, and frees the provided variable as well. */ 126 131 void bini_close(struct bini_stream *bs); 127 132 133 + /* Shift a binary stream, resetting the offset and shifting the array. */ 134 + void bini_shift(struct bini_stream *); 128 135 /* Flush a binary stream, clearing its buffer. */ 129 136 int bini_flush(struct bini_stream *); 130 137 /* Dump the binary stream's buffer to fp. */ ··· 255 262 bs->buffer = calloc(BINI_BUFSIZ, 1); 256 263 if (!bs->buffer) 257 264 return BINI_ERR; 265 + bs->off = 0; 258 266 bs->len = 0; 259 267 bs->cap = BINI_BUFSIZ; 260 268 bs->mode = BINI_STREAM; ··· 280 288 free(bs); 281 289 } 282 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 + 283 323 int bini_flush(struct bini_stream *bs) 284 324 { 285 325 size_t i; ··· 307 347 int _bini_grow(struct bini_stream *bs, size_t n) 308 348 { 309 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 + 310 358 if (bs->len + n < bs->cap) 311 359 return BINI_OK; 360 + 312 361 while (bs->len + n >= bs->cap) 313 362 { 314 363 newbuf = realloc(bs->buffer, bs->cap * 2); ··· 317 366 bs->buffer = newbuf; 318 367 bs->cap *= 2; 319 368 } 369 + 320 370 return BINI_OK; 321 371 } 322 372 ··· 334 384 return fwrite(bs->buffer, size, n, fp); 335 385 } 336 386 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 387 #define _bini_rwx(_type, _name) \ 364 388 void bini_w##_name(struct bini_stream *bs, _type v) \ 365 389 { \ ··· 376 400 l ? sizeof(v)-i-1 : i, \ 377 401 bytes[l ? sizeof(v)-i-1 : i], \ 378 402 bytes[l ? sizeof(v)-i-1 : i], \ 379 - bs->len+i); \ 380 - bs->buffer[bs->len+i] = 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]; \ 381 405 } \ 382 406 bs->len += i; \ 383 407 _bini_dbg("-> %s: %d (%lu bytes)\n", __FUNCTION__, *(int *)bytes, sizeof(v)); \ ··· 391 415 int m = bs->mode == BINI_STREAM; \ 392 416 for (i = 0 ; i < sizeof(v) ; i++) \ 393 417 { \ 418 + const size_t p = bs->off + (m ? i : (bs->len-sizeof(v)+i)); \ 394 419 _bini_dbg("%s: byte index [%lu] from buffer index %lu (= %02x '%c')\n", \ 395 420 __FUNCTION__, \ 396 421 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)]; \ 422 + p, \ 423 + bs->buffer[p], \ 424 + bs->buffer[p]); \ 425 + bytes[l ? sizeof(v)-i-1 : i] = bs->buffer[p]; \ 401 426 } \ 402 427 if (m) \ 403 - _bini_shiftleft(bs, i); \ 428 + { \ 429 + bs->off += i; \ 430 + /* _bini_shiftleft(bs, i); */ \ 431 + } \ 404 432 bs->len -= i; \ 405 433 return v; \ 406 434 }