Add string support to Buffer.fill

This commit is contained in:
Jarred Sumner
2022-08-18 21:09:26 -07:00
parent d150a2f4dd
commit 0e4db0b28f
7 changed files with 119 additions and 77 deletions

View File

@@ -17,78 +17,85 @@ pub const BufferVectorized = struct {
extern fn memset_pattern16(b: *anyopaque, pattern16: *const anyopaque, len: usize) void;
pub fn fill(
globalObject: *JSGlobalObject,
this: *JSC.ArrayBuffer,
str: *JSC.ZigString,
start: u32,
end: u32,
buf_ptr: [*]u8,
fill_length: usize,
encoding: JSC.Node.Encoding,
) callconv(.C) void {
const allocator = JSC.VirtualMachine.vm.allocator;
var stack_fallback = std.heap.stackFallback(512, allocator);
var stack_fallback_allocator = stack_fallback.get();
var input_string = str.toSlice(stack_fallback_allocator);
if (input_string.len == 0) return;
if (str.len == 0) return;
defer input_string.deinit();
var buf = buf_ptr[0..fill_length];
var buf = this.slice()[start..end];
const written = switch (encoding) {
JSC.Node.Encoding.utf8 => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.utf8)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.utf8),
JSC.Node.Encoding.ascii => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.ascii)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.ascii),
JSC.Node.Encoding.latin1 => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.latin1)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.latin1),
JSC.Node.Encoding.buffer => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.buffer)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.buffer),
JSC.Node.Encoding.utf16le,
JSC.Node.Encoding.ucs2,
=> if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.utf16le)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.utf16le),
JSC.Node.Encoding.base64 => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.base64)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.base64),
JSC.Node.Encoding.base64url => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.base64url)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.base64url),
JSC.Node.Encoding.hex => if (str.is16Bit())
JSC.WebCore.Encoder.writeU16(str.utf16SliceAligned().ptr, str.utf16SliceAligned().len, buf.ptr, buf.len, JSC.Node.Encoding.hex)
else
JSC.WebCore.Encoder.writeU8(str.slice().ptr, str.slice().len, buf.ptr, buf.len, JSC.Node.Encoding.hex),
};
var slice = input_string.slice();
switch (encoding) {
JSC.Node.Encoding.utf8,
JSC.Node.Encoding.ascii,
JSC.Node.Encoding.latin1,
JSC.Node.Encoding.buffer,
=> {
switch (slice.len) {
0 => unreachable,
1 => {
@memset(buf.ptr, slice[0], 1);
return;
},
2...16 => {
if (comptime Environment.isMac) {
var pattern: [16]u8 = undefined;
var remain: []u8 = pattern[0..];
if (written <= 0) {
return;
}
while (remain.len > 0) {
for (slice[0..]) |a| {
remain[0] = a;
remain = remain[1..];
}
}
var contents = buf[0..@intCast(usize, written)];
buf = buf[@intCast(usize, written)..];
memset_pattern16(buf.ptr, &pattern, buf.len);
return;
}
},
else => {},
}
if (contents.len == 1) {
@memset(buf.ptr, contents[0], buf.len);
return;
}
var in_there = @minimum(slice.len, buf.len);
@memcpy(buf.ptr, slice.ptr, in_there);
if (in_there < slice.len) {
return;
}
const minimum_contents = contents;
while (buf.len >= contents.len) {
const min_len = @minimum(contents.len, buf.len);
std.mem.copy(u8, buf[0..min_len], contents[0..min_len]);
if (buf.len <= contents.len) {
break;
}
buf = buf[min_len..];
contents.len *= 2;
}
// var ptr = buf.ptr + @as(usize, start) + slice.len;
// const fill_length = @as(usize, end) - @as(usize, start);
// // while (in_there < fill_length - in_there) {
// // std.mem.copy(ptr)
// // ptr += in_there;
// // in_there *= 2;
// // }
},
else => {},
while (buf.len > 0) {
const to_fill = @minimum(minimum_contents.len, buf.len);
std.mem.copy(u8, buf[0..to_fill], minimum_contents[0..to_fill]);
buf = buf[to_fill..];
}
}
};
comptime {
if (!JSC.is_bindgen) {
@export(BufferVectorized, .{ .name = "Bun__Buffer__fill" });
@export(BufferVectorized.fill, .{ .name = "Bun__Buffer_fill" });
}
}