aboutsummaryrefslogtreecommitdiff
path: root/src/string_joiner.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-03-06 07:35:16 -0800
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-03-06 07:35:16 -0800
commit7c5c6cd5192acde43006070e740bbe51cfd49255 (patch)
tree53f1e3cb999a477791dd76f4f2bedd3c56084756 /src/string_joiner.zig
parent093807391a9563ad36c2b04a286da23d09fad835 (diff)
downloadbun-7c5c6cd5192acde43006070e740bbe51cfd49255.tar.gz
bun-7c5c6cd5192acde43006070e740bbe51cfd49255.tar.zst
bun-7c5c6cd5192acde43006070e740bbe51cfd49255.zip
source maps work for app code in `bun dev`!
Diffstat (limited to 'src/string_joiner.zig')
-rw-r--r--src/string_joiner.zig80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/string_joiner.zig b/src/string_joiner.zig
new file mode 100644
index 000000000..d49c32867
--- /dev/null
+++ b/src/string_joiner.zig
@@ -0,0 +1,80 @@
+/// Rope-like data structure for joining many small strings into one big string.
+const Joiner = @This();
+
+const string = @import("string_types.zig").string;
+const Allocator = @import("std").mem.Allocator;
+const assert = @import("std").debug.assert;
+const copy = @import("std").mem.copy;
+const Env = @import("./env.zig");
+const ObjectPool = @import("./pool.zig").ObjectPool;
+
+const default_allocator = @import("./global.zig").default_allocator;
+
+const Joinable = struct {
+ offset: u31 = 0,
+ needs_deinit: bool = false,
+ allocator: std.mem.Allocator = undefined,
+ slice: []const u8 = "",
+
+ pub const Pool = ObjectPool(Joinable, null, true, 4);
+};
+
+last_byte: u8 = 0,
+len: usize = 0,
+
+head: ?*Joinable.Pool.Node = null,
+tail: ?*Joinable.Pool.Node = null,
+
+pub fn done(this: *Joiner, allocator: std.mem.Allocator) ![]u8 {
+ var slice = try allocator.alloc(u8, this.cap);
+ var remaining = slice;
+ var el_ = this.head;
+ while (el_) |join| {
+ const to_join = join.data.slice[join.offset..];
+ @memcpy(remaining.ptr, to_join.ptr, to_join.len);
+
+ remaining = remaining[to_join.len..];
+
+ var prev = join;
+ el_ = join.next;
+ if (prev.data.needs_deinit) {
+ prev.data.allocator.free(join.data.slice);
+ prev.data = Joinable{};
+ }
+ prev.release();
+ }
+
+ return slice[0 .. slice.len - remaining.len];
+}
+
+pub fn lastByte(this: *const Joiner) u8 {
+ if (this.tail) |tail| {
+ const slice = tail.data.slice[tail.data.offset..];
+ return if (slice.len > 0) slice[slice.len - 1] else 0;
+ }
+
+ return 0;
+}
+
+pub fn append(this: *Joiner, slice: string, offset: u32, allocator: ?std.mem.Allocator) void {
+ const data = slice[offset..];
+ this.len += @truncate(u32, data.len);
+
+ var new_tail = Joinable.Pool.get(default_allocator);
+ new_tail.data = Joinable{
+ .offset = offset,
+ .allocator = allocator orelse undefined,
+ .needs_deinit = allocator != null,
+ .slice = slice,
+ };
+
+ var tail = this.tail orelse {
+ this.tail = new_tail;
+ this.head = new_tail;
+ return;
+ };
+ tail.next = new_tail;
+ this.tail = new_tail;
+}
+
+const std = @import("std");