builder.odin 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. package strings
  2. import "core:mem"
  3. import "core:unicode/utf8"
  4. import "core:strconv"
  5. import "core:io"
  6. Builder_Flush_Proc :: #type proc(b: ^Builder) -> (do_reset: bool);
  7. Builder :: struct {
  8. buf: [dynamic]byte,
  9. }
  10. make_builder_none :: proc(allocator := context.allocator) -> Builder {
  11. return Builder{buf=make([dynamic]byte, allocator)};
  12. }
  13. make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder {
  14. return Builder{buf=make([dynamic]byte, len, allocator)};
  15. }
  16. make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
  17. return Builder{buf=make([dynamic]byte, len, cap, allocator)};
  18. }
  19. make_builder :: proc{
  20. make_builder_none,
  21. make_builder_len,
  22. make_builder_len_cap,
  23. };
  24. init_builder_none :: proc(b: ^Builder, allocator := context.allocator) {
  25. b.buf = make([dynamic]byte, allocator);
  26. }
  27. init_builder_len :: proc(b: ^Builder, len: int, allocator := context.allocator) {
  28. b.buf = make([dynamic]byte, len, allocator);
  29. }
  30. init_builder_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) {
  31. b.buf = make([dynamic]byte, len, cap, allocator);
  32. }
  33. init_builder :: proc{
  34. init_builder_none,
  35. init_builder_len,
  36. init_builder_len_cap,
  37. };
  38. @(private)
  39. _builder_stream_vtable := &io.Stream_VTable{
  40. impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
  41. b := (^Builder)(s.stream_data);
  42. n = write_bytes(b, p);
  43. if len(b.buf) == cap(b.buf) {
  44. err = .EOF;
  45. }
  46. return;
  47. },
  48. impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
  49. b := (^Builder)(s.stream_data);
  50. _ = write_byte(b, c);
  51. if len(b.buf) == cap(b.buf) {
  52. return .EOF;
  53. }
  54. return nil;
  55. },
  56. impl_size = proc(s: io.Stream) -> i64 {
  57. b := (^Builder)(s.stream_data);
  58. return i64(len(b.buf));
  59. },
  60. impl_destroy = proc(s: io.Stream) -> io.Error {
  61. b := (^Builder)(s.stream_data);
  62. delete(b.buf);
  63. return .None;
  64. },
  65. };
  66. to_stream :: proc(b: ^Builder) -> io.Stream {
  67. return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b};
  68. }
  69. to_writer :: proc(b: ^Builder) -> io.Writer {
  70. w, _ := io.to_writer(to_stream(b));
  71. return w;
  72. }
  73. destroy_builder :: proc(b: ^Builder) {
  74. delete(b.buf);
  75. clear(&b.buf);
  76. }
  77. grow_builder :: proc(b: ^Builder, cap: int) {
  78. reserve(&b.buf, cap);
  79. }
  80. reset_builder :: proc(b: ^Builder) {
  81. clear(&b.buf);
  82. }
  83. builder_from_slice :: proc(backing: []byte) -> Builder {
  84. s := transmute(mem.Raw_Slice)backing;
  85. d := mem.Raw_Dynamic_Array{
  86. data = s.data,
  87. len = 0,
  88. cap = s.len,
  89. allocator = mem.nil_allocator(),
  90. };
  91. return Builder{
  92. buf = transmute([dynamic]byte)d,
  93. };
  94. }
  95. to_string :: proc(b: Builder) -> string {
  96. return string(b.buf[:]);
  97. }
  98. builder_len :: proc(b: Builder) -> int {
  99. return len(b.buf);
  100. }
  101. builder_cap :: proc(b: Builder) -> int {
  102. return cap(b.buf);
  103. }
  104. builder_space :: proc(b: Builder) -> int {
  105. return max(cap(b.buf), len(b.buf), 0);
  106. }
  107. write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
  108. if builder_space(b^) > 0 {
  109. append(&b.buf, x);
  110. n += 1;
  111. }
  112. return;
  113. }
  114. write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
  115. x := x;
  116. for len(x) != 0 {
  117. space := builder_space(b^);
  118. if space == 0 {
  119. break; // No need to append
  120. }
  121. i := min(space, len(x));
  122. n += i;
  123. append(&b.buf, ..x[:i]);
  124. if len(x) <= i {
  125. break; // No more data to append
  126. }
  127. x = x[i:];
  128. }
  129. return;
  130. }
  131. write_rune_builder :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
  132. return io.write_rune(to_writer(b), r);
  133. }
  134. write_quoted_rune_builder :: proc(b: ^Builder, r: rune) -> (n: int) {
  135. return write_quoted_rune(to_writer(b), r);
  136. }
  137. @(private)
  138. _write_byte :: proc(w: io.Writer, c: byte) -> int {
  139. err := io.write_byte(w, c);
  140. return 1 if err == nil else 0;
  141. }
  142. write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) {
  143. quote := byte('\'');
  144. n += _write_byte(w, quote);
  145. buf, width := utf8.encode_rune(r);
  146. if width == 1 && r == utf8.RUNE_ERROR {
  147. n += _write_byte(w, '\\');
  148. n += _write_byte(w, 'x');
  149. n += _write_byte(w, DIGITS_LOWER[buf[0]>>4]);
  150. n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf]);
  151. } else {
  152. n += write_escaped_rune(w, r, quote);
  153. }
  154. n += _write_byte(w, quote);
  155. return;
  156. }
  157. write_string :: proc{
  158. write_string_builder,
  159. write_string_writer,
  160. };
  161. write_string_builder :: proc(b: ^Builder, s: string) -> (n: int) {
  162. return write_string_writer(to_writer(b), s);
  163. }
  164. write_string_writer :: proc(w: io.Writer, s: string) -> (n: int) {
  165. n, _ = io.write(w, transmute([]byte)s);
  166. return;
  167. }
  168. pop_byte :: proc(b: ^Builder) -> (r: byte) {
  169. if len(b.buf) == 0 {
  170. return 0;
  171. }
  172. r = b.buf[len(b.buf)-1];
  173. d := cast(^mem.Raw_Dynamic_Array)&b.buf;
  174. d.len = max(d.len-1, 0);
  175. return;
  176. }
  177. pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
  178. r, width = utf8.decode_last_rune(b.buf[:]);
  179. d := cast(^mem.Raw_Dynamic_Array)&b.buf;
  180. d.len = max(d.len-width, 0);
  181. return;
  182. }
  183. @(private, static)
  184. DIGITS_LOWER := "0123456789abcdefx";
  185. write_quoted_string :: proc{
  186. write_quoted_string_builder,
  187. write_quoted_string_writer,
  188. };
  189. write_quoted_string_builder :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
  190. return write_quoted_string_writer(to_writer(b), str, quote);
  191. }
  192. write_quoted_string_writer :: proc(w: io.Writer, str: string, quote: byte = '"') -> (n: int) {
  193. n += _write_byte(w, quote);
  194. for width, s := 0, str; len(s) > 0; s = s[width:] {
  195. r := rune(s[0]);
  196. width = 1;
  197. if r >= utf8.RUNE_SELF {
  198. r, width = utf8.decode_rune_in_string(s);
  199. }
  200. if width == 1 && r == utf8.RUNE_ERROR {
  201. n += _write_byte(w, '\\');
  202. n += _write_byte(w, 'x');
  203. n += _write_byte(w, DIGITS_LOWER[s[0]>>4]);
  204. n += _write_byte(w, DIGITS_LOWER[s[0]&0xf]);
  205. continue;
  206. }
  207. n += write_escaped_rune(w, r, quote);
  208. }
  209. n += _write_byte(w, quote);
  210. return;
  211. }
  212. write_encoded_rune :: proc{
  213. write_encoded_rune_builder,
  214. write_encoded_rune_writer,
  215. };
  216. write_encoded_rune_builder :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
  217. return write_encoded_rune_writer(to_writer(b), r, write_quote);
  218. }
  219. write_encoded_rune_writer :: proc(w: io.Writer, r: rune, write_quote := true) -> (n: int) {
  220. if write_quote {
  221. n += _write_byte(w, '\'');
  222. }
  223. switch r {
  224. case '\a': n += write_string(w, `\a"`);
  225. case '\b': n += write_string(w, `\b"`);
  226. case '\e': n += write_string(w, `\e"`);
  227. case '\f': n += write_string(w, `\f"`);
  228. case '\n': n += write_string(w, `\n"`);
  229. case '\r': n += write_string(w, `\r"`);
  230. case '\t': n += write_string(w, `\t"`);
  231. case '\v': n += write_string(w, `\v"`);
  232. case:
  233. if r < 32 {
  234. n += write_string(w, `\x`);
  235. buf: [2]byte;
  236. s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil);
  237. switch len(s) {
  238. case 0: n += write_string(w, "00");
  239. case 1: n += _write_byte(w, '0');
  240. case 2: n += write_string(w, s);
  241. }
  242. } else {
  243. rn, _ := io.write_rune(w, r);
  244. n += rn;
  245. }
  246. }
  247. if write_quote {
  248. n += _write_byte(w, '\'');
  249. }
  250. return;
  251. }
  252. write_escaped_rune :: proc{
  253. write_escaped_rune_builder,
  254. write_escaped_rune_writer,
  255. };
  256. write_escaped_rune_builder :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
  257. return write_escaped_rune_writer(to_writer(b), r, quote, html_safe);
  258. }
  259. write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe := false) -> (n: int) {
  260. is_printable :: proc(r: rune) -> bool {
  261. if r <= 0xff {
  262. switch r {
  263. case 0x20..0x7e:
  264. return true;
  265. case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
  266. return r != 0xad; //
  267. }
  268. }
  269. // TODO(bill): A proper unicode library will be needed!
  270. return false;
  271. }
  272. if html_safe {
  273. switch r {
  274. case '<', '>', '&':
  275. n += _write_byte(w, '\\');
  276. n += _write_byte(w, 'u');
  277. for s := 12; s >= 0; s -= 4 {
  278. n += _write_byte(w, DIGITS_LOWER[r>>uint(s) & 0xf]);
  279. }
  280. return;
  281. }
  282. }
  283. if r == rune(quote) || r == '\\' {
  284. n += _write_byte(w, '\\');
  285. n += _write_byte(w, byte(r));
  286. return;
  287. } else if is_printable(r) {
  288. n += write_encoded_rune(w, r, false);
  289. return;
  290. }
  291. switch r {
  292. case '\a': n += write_string(w, `\a`);
  293. case '\b': n += write_string(w, `\b`);
  294. case '\e': n += write_string(w, `\e`);
  295. case '\f': n += write_string(w, `\f`);
  296. case '\n': n += write_string(w, `\n`);
  297. case '\r': n += write_string(w, `\r`);
  298. case '\t': n += write_string(w, `\t`);
  299. case '\v': n += write_string(w, `\v`);
  300. case:
  301. switch c := r; {
  302. case c < ' ':
  303. n += _write_byte(w, '\\');
  304. n += _write_byte(w, 'x');
  305. n += _write_byte(w, DIGITS_LOWER[byte(c)>>4]);
  306. n += _write_byte(w, DIGITS_LOWER[byte(c)&0xf]);
  307. case c > utf8.MAX_RUNE:
  308. c = 0xfffd;
  309. fallthrough;
  310. case c < 0x10000:
  311. n += _write_byte(w, '\\');
  312. n += _write_byte(w, 'u');
  313. for s := 12; s >= 0; s -= 4 {
  314. n += _write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf]);
  315. }
  316. case:
  317. n += _write_byte(w, '\\');
  318. n += _write_byte(w, 'U');
  319. for s := 28; s >= 0; s -= 4 {
  320. n += _write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf]);
  321. }
  322. }
  323. }
  324. return;
  325. }
  326. write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
  327. buf: [32]byte;
  328. s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil);
  329. return write_string(b, s);
  330. }
  331. write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
  332. buf: [32]byte;
  333. s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil);
  334. return write_string(b, s);
  335. }
  336. write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
  337. return write_u64(b, u64(i), base);
  338. }
  339. write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) {
  340. return write_i64(b, i64(i), base);
  341. }