builder.odin 4.6 KB

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