builder.odin 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package strings
  2. import "core:mem"
  3. import "core:unicode/utf8"
  4. import "core:strconv"
  5. Builder :: struct {
  6. buf: [dynamic]byte,
  7. }
  8. make_builder_none :: proc(allocator := context.allocator) -> Builder {
  9. return Builder{make([dynamic]byte, allocator)};
  10. }
  11. make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder {
  12. return Builder{make([dynamic]byte, len, allocator)};
  13. }
  14. make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
  15. return Builder{make([dynamic]byte, len, cap, allocator)};
  16. }
  17. make_builder :: proc{
  18. make_builder_none,
  19. make_builder_len,
  20. make_builder_len_cap,
  21. };
  22. destroy_builder :: proc(b: ^Builder) {
  23. delete(b.buf);
  24. clear(&b.buf);
  25. }
  26. grow_builder :: proc(b: ^Builder, cap: int) {
  27. reserve(&b.buf, cap);
  28. }
  29. reset_builder :: proc(b: ^Builder) {
  30. clear(&b.buf);
  31. }
  32. builder_from_slice :: proc(backing: []byte) -> Builder {
  33. s := transmute(mem.Raw_Slice)backing;
  34. d := mem.Raw_Dynamic_Array{
  35. data = s.data,
  36. len = 0,
  37. cap = s.len,
  38. allocator = mem.nil_allocator(),
  39. };
  40. return transmute(Builder)d;
  41. }
  42. to_string :: proc(b: Builder) -> string {
  43. return string(b.buf[:]);
  44. }
  45. builder_len :: proc(b: Builder) -> int {
  46. return len(b.buf);
  47. }
  48. builder_cap :: proc(b: Builder) -> int {
  49. return cap(b.buf);
  50. }
  51. write_byte :: proc(b: ^Builder, x: byte) {
  52. append(&b.buf, x);
  53. }
  54. write_rune :: proc(b: ^Builder, r: rune) -> int {
  55. if r < utf8.RUNE_SELF {
  56. write_byte(b, byte(r));
  57. return 1;
  58. }
  59. s, n := utf8.encode_rune(r);
  60. write_bytes(b, s[:n]);
  61. return n;
  62. }
  63. write_string :: proc(b: ^Builder, s: string) {
  64. write_bytes(b, transmute([]byte)s);
  65. }
  66. write_bytes :: proc(b: ^Builder, x: []byte) {
  67. append(&b.buf, ..x);
  68. }
  69. pop_byte :: proc(b: ^Builder) -> (r: byte) {
  70. if len(b.buf) == 0 {
  71. return 0;
  72. }
  73. r = b.buf[len(b.buf)-1];
  74. d := cast(^mem.Raw_Dynamic_Array)&b.buf;
  75. d.len = max(d.len-1, 0);
  76. return;
  77. }
  78. pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
  79. r, width = utf8.decode_last_rune(b.buf[:]);
  80. d := cast(^mem.Raw_Dynamic_Array)&b.buf;
  81. d.len = max(d.len-width, 0);
  82. return;
  83. }
  84. @(private, static)
  85. DIGITS_LOWER := "0123456789abcdefx";
  86. write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') {
  87. write_byte(b, quote);
  88. for width, s := 0, str; len(s) > 0; s = s[width:] {
  89. r := rune(s[0]);
  90. width = 1;
  91. if r >= utf8.RUNE_SELF {
  92. r, width = utf8.decode_rune_in_string(s);
  93. }
  94. if width == 1 && r == utf8.RUNE_ERROR {
  95. write_byte(b, '\\');
  96. write_byte(b, 'x');
  97. write_byte(b, DIGITS_LOWER[s[0]>>4]);
  98. write_byte(b, DIGITS_LOWER[s[0]&0xf]);
  99. continue;
  100. }
  101. write_escaped_rune(b, r, quote);
  102. }
  103. write_byte(b, quote);
  104. }
  105. write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) {
  106. if write_quote do write_byte(b, '\'');
  107. switch r {
  108. case '\a': write_string(b, `\a"`);
  109. case '\b': write_string(b, `\b"`);
  110. case '\e': write_string(b, `\e"`);
  111. case '\f': write_string(b, `\f"`);
  112. case '\n': write_string(b, `\n"`);
  113. case '\r': write_string(b, `\r"`);
  114. case '\t': write_string(b, `\t"`);
  115. case '\v': write_string(b, `\v"`);
  116. case:
  117. if r < 32 {
  118. write_string(b, `\x`);
  119. buf: [2]byte;
  120. s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil);
  121. switch len(s) {
  122. case 0: write_string(b, "00");
  123. case 1: write_byte(b, '0');
  124. case 2: write_string(b, s);
  125. }
  126. } else {
  127. write_rune(b, r);
  128. }
  129. }
  130. if write_quote do write_byte(b, '\'');
  131. }
  132. write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) {
  133. is_printable :: proc(r: rune) -> bool {
  134. if r <= 0xff {
  135. switch r {
  136. case 0x20..0x7e:
  137. return true;
  138. case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
  139. return r != 0xad; //
  140. }
  141. }
  142. // TODO(bill): A proper unicode library will be needed!
  143. return false;
  144. }
  145. if html_safe {
  146. switch r {
  147. case '<', '>', '&':
  148. write_byte(b, '\\');
  149. write_byte(b, 'u');
  150. for s := 12; s >= 0; s -= 4 {
  151. write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
  152. }
  153. return;
  154. }
  155. }
  156. if r == rune(quote) || r == '\\' {
  157. write_byte(b, '\\');
  158. write_byte(b, byte(r));
  159. return;
  160. } else if is_printable(r) {
  161. write_encoded_rune(b, r, false);
  162. return;
  163. }
  164. switch r {
  165. case '\a': write_string(b, `\a`);
  166. case '\b': write_string(b, `\b`);
  167. case '\e': write_string(b, `\e`);
  168. case '\f': write_string(b, `\f`);
  169. case '\n': write_string(b, `\n`);
  170. case '\r': write_string(b, `\r`);
  171. case '\t': write_string(b, `\t`);
  172. case '\v': write_string(b, `\v`);
  173. case:
  174. switch c := r; {
  175. case c < ' ':
  176. write_byte(b, '\\');
  177. write_byte(b, 'x');
  178. write_byte(b, DIGITS_LOWER[byte(c)>>4]);
  179. write_byte(b, DIGITS_LOWER[byte(c)&0xf]);
  180. case c > utf8.MAX_RUNE:
  181. c = 0xfffd;
  182. fallthrough;
  183. case c < 0x10000:
  184. write_byte(b, '\\');
  185. write_byte(b, 'u');
  186. for s := 12; s >= 0; s -= 4 {
  187. write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
  188. }
  189. case:
  190. write_byte(b, '\\');
  191. write_byte(b, 'U');
  192. for s := 28; s >= 0; s -= 4 {
  193. write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
  194. }
  195. }
  196. }
  197. }
  198. write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) {
  199. buf: [32]byte;
  200. s := strconv.append_bits(buf[:], u64(i), base, false, 64, strconv.digits, nil);
  201. write_string(b, s);
  202. }
  203. write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) {
  204. buf: [32]byte;
  205. s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil);
  206. write_string(b, s);
  207. }
  208. write_uint :: proc(b: ^Builder, i: uint, base: int = 10) {
  209. write_u64(b, u64(i), base);
  210. }
  211. write_int :: proc(b: ^Builder, i: int, base: int = 10) {
  212. write_i64(b, i64(i), base);
  213. }