@shd101wyy/yo 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,173 @@
1
+ //! Mutable UTF-8 string builder for efficient incremental construction.
2
+
3
+ { ArrayList } :: import "../collections/array_list.yo";
4
+ { rune } :: import "./rune.yo";
5
+ { String } :: import "./string.yo";
6
+
7
+ /**
8
+ * Mutable buffer for building a `String` incrementally.
9
+ *
10
+ * Use `StringBuilder` when you need to construct a string from many parts,
11
+ * appending bytes or strings in a loop, before converting to an immutable
12
+ * `String` with `to_string()`.
13
+ *
14
+ * ## Example
15
+ * ```rust
16
+ * sb := StringBuilder.new();
17
+ * sb.write_str("Hello");
18
+ * sb.write_str(", ");
19
+ * sb.write_string(`world`);
20
+ * sb.write_byte(u8(33)); // '!'
21
+ * result := sb.to_string();
22
+ * assert(result == `Hello, world!`, "built string");
23
+ * ```
24
+ */
25
+ StringBuilder :: object(
26
+ _buf : ArrayList(u8)
27
+ );
28
+
29
+ impl(StringBuilder,
30
+ /**
31
+ * Create a new, empty `StringBuilder`.
32
+ */
33
+ new : (fn() -> Self)(
34
+ Self(_buf: ArrayList(u8).new())
35
+ ),
36
+
37
+ /**
38
+ * Create a `StringBuilder` pre-allocated for `capacity` bytes.
39
+ */
40
+ with_capacity : (fn(capacity: usize) -> Self)(
41
+ Self(_buf: ArrayList(u8).with_capacity(capacity))
42
+ ),
43
+
44
+ /**
45
+ * Returns the current number of bytes in the buffer.
46
+ */
47
+ len : (fn(self: *(Self)) -> usize)(
48
+ self._buf.len()
49
+ ),
50
+
51
+ /**
52
+ * Returns true if the buffer is empty.
53
+ */
54
+ is_empty : (fn(self: *(Self)) -> bool)(
55
+ (self._buf.len() == usize(0))
56
+ ),
57
+
58
+ /**
59
+ * Append a `str` (raw byte slice) to the buffer.
60
+ */
61
+ write_str : (fn(self: *(Self), s: str) -> unit)({
62
+ byte_len := s.len();
63
+ if((byte_len > usize(0)), {
64
+ self._buf.extend_from_ptr(s.ptr(), byte_len);
65
+ });
66
+ }),
67
+
68
+ /**
69
+ * Append a `String` to the buffer.
70
+ */
71
+ write_string : (fn(self: *(Self), s: String) -> unit)(
72
+ match(s._bytes,
73
+ .None => (),
74
+ .Some(al) => {
75
+ i := usize(0);
76
+ n := al.len();
77
+ while ((i < n)),
78
+ (i = (i + usize(1))),
79
+ {
80
+ byte_opt := al.get(i);
81
+ match(byte_opt,
82
+ .Some(b) => { self._buf.push(b); },
83
+ .None => ()
84
+ );
85
+ };
86
+ }
87
+ )
88
+ ),
89
+
90
+ /**
91
+ * Append a single byte to the buffer.
92
+ */
93
+ write_byte : (fn(self: *(Self), b: u8) -> unit)({
94
+ self._buf.push(b);
95
+ }),
96
+
97
+ /**
98
+ * Append a single Unicode code point, encoded as UTF-8.
99
+ *
100
+ * ## Example
101
+ * ```rust
102
+ * sb := StringBuilder.new();
103
+ * sb.write_rune(rune(0x1F600)); // 😀
104
+ * sb.write_rune(rune(0x41)); // 'A'
105
+ * ```
106
+ */
107
+ write_rune : (fn(self: *(Self), r: rune) -> unit)({
108
+ cp := r.char;
109
+ cond(
110
+ (cp < u32(0x80)) => {
111
+ self._buf.push(u8(cp));
112
+ },
113
+ (cp < u32(0x800)) => {
114
+ self._buf.push(u8((u32(0xC0) | (cp >> u32(6)))));
115
+ self._buf.push(u8((u32(0x80) | (cp & u32(0x3F)))));
116
+ },
117
+ (cp < u32(0x10000)) => {
118
+ self._buf.push(u8((u32(0xE0) | (cp >> u32(12)))));
119
+ self._buf.push(u8((u32(0x80) | ((cp >> u32(6)) & u32(0x3F)))));
120
+ self._buf.push(u8((u32(0x80) | (cp & u32(0x3F)))));
121
+ },
122
+ true => {
123
+ self._buf.push(u8((u32(0xF0) | (cp >> u32(18)))));
124
+ self._buf.push(u8((u32(0x80) | ((cp >> u32(12)) & u32(0x3F)))));
125
+ self._buf.push(u8((u32(0x80) | ((cp >> u32(6)) & u32(0x3F)))));
126
+ self._buf.push(u8((u32(0x80) | (cp & u32(0x3F)))));
127
+ }
128
+ );
129
+ }),
130
+
131
+ /**
132
+ * Append a `String` followed by a newline byte (`\n`).
133
+ */
134
+ write_line : (fn(self: *(Self), s: String) -> unit)({
135
+ self.write_string(s);
136
+ self._buf.push(u8(10));
137
+ }),
138
+
139
+ /**
140
+ * Consume the builder and return the accumulated `String`.
141
+ * The builder is left empty after this call.
142
+ */
143
+ to_string : (fn(self: *(Self)) -> String)({
144
+ n := self._buf.len();
145
+ cond(
146
+ (n == usize(0)) => String(_bytes: .None),
147
+ true => {
148
+ buf := ArrayList(u8).with_capacity(n);
149
+ i := usize(0);
150
+ while ((i < n)),
151
+ (i = (i + usize(1))),
152
+ {
153
+ byte_opt := self._buf.get(i);
154
+ match(byte_opt,
155
+ .Some(b) => { buf.push(b); },
156
+ .None => ()
157
+ );
158
+ };
159
+ self._buf = ArrayList(u8).new();
160
+ String(_bytes: .Some(buf))
161
+ }
162
+ )
163
+ }),
164
+
165
+ /**
166
+ * Clear the buffer without freeing memory.
167
+ */
168
+ clear : (fn(self: *(Self)) -> unit)({
169
+ self._buf = ArrayList(u8).new();
170
+ })
171
+ );
172
+
173
+ export StringBuilder;