util.h 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #pragma once
  2. #include <assert.h>
  3. #include <stdbool.h>
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include "../const.h"
  7. #include "../log.h"
  8. typedef struct Buffer {
  9. uint8_t* const start;
  10. uint8_t* ptr;
  11. int32_t const len;
  12. } Buffer;
  13. static void inline write_raw_u8(Buffer* buf, uint8_t v)
  14. {
  15. assert(buf->ptr < buf->start + buf->len);
  16. *buf->ptr++ = v;
  17. }
  18. static void write_leb_i32(Buffer* buf, int32_t v)
  19. {
  20. // Super complex stuff. See the following:
  21. // https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
  22. // http://llvm.org/doxygen/LEB128_8h_source.html#l00048
  23. bool more = true;
  24. bool negative = v < 0;
  25. const uint32_t SIZE = 32;
  26. while (more)
  27. {
  28. uint8_t byte = v & 0b1111111; // get last 7 bits
  29. v >>= 7; // shift them away from the value
  30. if (negative)
  31. {
  32. v |= ((uint32_t)~0 << (SIZE - 7)); // extend sign
  33. }
  34. uint8_t sign_bit = byte & (1 << 6);
  35. if ((v == 0 && sign_bit == 0) || (v == -1 && sign_bit != 0))
  36. {
  37. more = false;
  38. }
  39. else
  40. {
  41. byte |= 0b10000000; // turn on MSB
  42. }
  43. write_raw_u8(buf, byte);
  44. }
  45. }
  46. static void write_leb_u32(Buffer* buf, uint32_t v)
  47. {
  48. do {
  49. uint8_t byte = v & 0b1111111; // get last 7 bits
  50. v >>= 7; // shift them away from the value
  51. if (v != 0)
  52. {
  53. byte |= 0b10000000; // turn on MSB
  54. }
  55. write_raw_u8(buf, byte);
  56. } while (v != 0);
  57. }
  58. static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
  59. {
  60. dbg_assert(x < (1 << 14)); // we have 14 bits of available space in 2 bytes for leb
  61. *(ptr ) = (x & 0b1111111) | 0b10000000;
  62. *(ptr + 1) = x >> 7;
  63. }
  64. static void inline write_fixed_leb32_to_ptr(uint8_t* ptr, uint32_t x)
  65. {
  66. dbg_assert(x < (1 << 28)); // we have 28 bits of available space in 4 bytes for leb
  67. *(ptr ) = (x & 0b1111111) | 0b10000000;
  68. *(ptr + 1) = (x >> 7 & 0b1111111) | 0b10000000;
  69. *(ptr + 2) = (x >> 14 & 0b1111111) | 0b10000000;
  70. *(ptr + 3) = (x >> 21 & 0b1111111);
  71. }
  72. static void append_buffer(Buffer *dest, Buffer *src)
  73. {
  74. assert(dest->len - (dest->ptr - dest->start) >= (src->ptr - src->start));
  75. uint8_t* offset = src->start;
  76. while (offset < src->ptr)
  77. {
  78. write_raw_u8(dest, *offset++);
  79. }
  80. }