aboutsummaryrefslogtreecommitdiff
path: root/src/string_joiner.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/string_joiner.zig')
-rw-r--r--src/string_joiner.zig34
1 files changed, 31 insertions, 3 deletions
diff --git a/src/string_joiner.zig b/src/string_joiner.zig
index 490989c9a..373d24633 100644
--- a/src/string_joiner.zig
+++ b/src/string_joiner.zig
@@ -1,7 +1,8 @@
/// Rope-like data structure for joining many small strings into one big string.
const std = @import("std");
-const default_allocator = @import("bun").default_allocator;
-const string = @import("string_types.zig").string;
+const default_allocator = bun.default_allocator;
+const bun = @import("bun");
+const string = bun.string;
const Allocator = std.mem.Allocator;
const ObjectPool = @import("./pool.zig").ObjectPool;
const Joiner = @This();
@@ -15,7 +16,6 @@ const Joinable = struct {
pub const Pool = ObjectPool(Joinable, null, true, 4);
};
-last_byte: u8 = 0,
len: usize = 0,
use_pool: bool = true,
node_allocator: Allocator = undefined,
@@ -23,6 +23,15 @@ node_allocator: Allocator = undefined,
head: ?*Joinable.Pool.Node = null,
tail: ?*Joinable.Pool.Node = null,
+/// Avoid an extra pass over the list when joining
+watcher: Watcher = .{},
+
+pub const Watcher = struct {
+ input: []const u8 = "",
+ estimated_count: u32 = 0,
+ needs_newline: bool = false,
+};
+
pub fn done(this: *Joiner, allocator: Allocator) ![]u8 {
if (this.head == null) {
var out: []u8 = &[_]u8{};
@@ -60,6 +69,17 @@ pub fn lastByte(this: *const Joiner) u8 {
return 0;
}
+pub fn push(this: *Joiner, slice: string) void {
+ this.append(slice, 0, null);
+}
+
+pub fn ensureNewlineAtEnd(this: *Joiner) void {
+ if (this.watcher.needs_newline) {
+ this.watcher.needs_newline = false;
+ this.push("\n");
+ }
+}
+
pub fn append(this: *Joiner, slice: string, offset: u32, allocator: ?Allocator) void {
const data = slice[offset..];
this.len += @truncate(u32, data.len);
@@ -69,6 +89,14 @@ pub fn append(this: *Joiner, slice: string, offset: u32, allocator: ?Allocator)
else
(this.node_allocator.create(Joinable.Pool.Node) catch unreachable);
+ this.watcher.estimated_count += @boolToInt(
+ this.watcher.input.len > 0 and
+ bun.strings.contains(data, this.watcher.input),
+ );
+
+ this.watcher.needs_newline = this.watcher.input.len > 0 and data.len > 0 and
+ data[data.len - 1] != '\n';
+
new_tail.* = .{
.allocator = default_allocator,
.data = Joinable{