118 lines
3.4 KiB
Zig
118 lines
3.4 KiB
Zig
const debug = @import("debug.zig");
|
|
const mem = @import("mem.zig");
|
|
const Allocator = mem.Allocator;
|
|
const assert = debug.assert;
|
|
const List = @import("list.zig").List;
|
|
|
|
/// A buffer that allocates memory and maintains a null byte at the end.
|
|
pub const Buffer = struct {
|
|
list: List(u8),
|
|
|
|
/// Must deinitialize with deinit.
|
|
pub fn init(allocator: &Allocator, m: []const u8) -> %Buffer {
|
|
var self = %return initSize(allocator, m.len);
|
|
mem.copy(u8, self.list.items, m);
|
|
return self;
|
|
}
|
|
|
|
/// Must deinitialize with deinit.
|
|
pub fn initSize(allocator: &Allocator, size: usize) -> %Buffer {
|
|
var self = initNull(allocator);
|
|
%return self.resize(size);
|
|
return self;
|
|
}
|
|
|
|
/// Must deinitialize with deinit.
|
|
/// None of the other operations are valid until you do one of these:
|
|
/// * ::replaceContents
|
|
/// * ::replaceContentsBuffer
|
|
/// * ::resize
|
|
pub fn initNull(allocator: &Allocator) -> Buffer {
|
|
Buffer {
|
|
.list = List(u8).init(allocator),
|
|
}
|
|
}
|
|
|
|
/// Must deinitialize with deinit.
|
|
pub fn initFromBuffer(buffer: &const Buffer) -> %Buffer {
|
|
return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
|
|
}
|
|
|
|
pub fn deinit(self: &Buffer) {
|
|
self.list.deinit();
|
|
}
|
|
|
|
pub fn toSlice(self: &Buffer) -> []u8 {
|
|
return self.list.toSlice()[0...self.len()];
|
|
}
|
|
|
|
pub fn toSliceConst(self: &const Buffer) -> []const u8 {
|
|
return self.list.toSliceConst()[0...self.len()];
|
|
}
|
|
|
|
pub fn resize(self: &Buffer, new_len: usize) -> %void {
|
|
%return self.list.resize(new_len + 1);
|
|
self.list.items[self.len()] = 0;
|
|
}
|
|
|
|
pub fn isNull(self: &const Buffer) -> bool {
|
|
return self.list.len == 0;
|
|
}
|
|
|
|
pub fn len(self: &const Buffer) -> usize {
|
|
return self.list.len - 1;
|
|
}
|
|
|
|
pub fn append(self: &Buffer, m: []const u8) -> %void {
|
|
const old_len = self.len();
|
|
%return self.resize(old_len + m.len);
|
|
mem.copy(u8, self.list.toSlice()[old_len...], m);
|
|
}
|
|
|
|
pub fn appendByte(self: &Buffer, byte: u8) -> %void {
|
|
%return self.resize(self.len() + 1);
|
|
self.list.items[self.len() - 1] = byte;
|
|
}
|
|
|
|
pub fn eql(self: &const Buffer, m: []const u8) -> bool {
|
|
mem.eql(u8, self.toSliceConst(), m)
|
|
}
|
|
|
|
pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
|
|
if (self.len() < m.len) return false;
|
|
return mem.eql(u8, self.list.items[0...m.len], m);
|
|
}
|
|
|
|
pub fn endsWith(self: &const Buffer, m: []const u8) -> bool {
|
|
const l = self.len();
|
|
if (l < m.len) return false;
|
|
const start = l - m.len;
|
|
return mem.eql(u8, self.list.items[start...], m);
|
|
}
|
|
|
|
pub fn replaceContents(self: &const Buffer, m: []const u8) -> %void {
|
|
%return self.resize(m.len);
|
|
mem.copy(u8, self.list.toSlice(), m);
|
|
}
|
|
};
|
|
|
|
test "simple Buffer" {
|
|
const cstr = @import("cstr.zig");
|
|
|
|
var buf = %%Buffer.init(&debug.global_allocator, "");
|
|
assert(buf.len() == 0);
|
|
%%buf.append("hello");
|
|
%%buf.appendByte(' ');
|
|
%%buf.append("world");
|
|
assert(buf.eql("hello world"));
|
|
assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
|
|
|
|
var buf2 = %%Buffer.initFromBuffer(&buf);
|
|
assert(buf.eql(buf2.toSliceConst()));
|
|
|
|
assert(buf.startsWith("hell"));
|
|
|
|
%%buf2.resize(4);
|
|
assert(buf.startsWith(buf2.toSliceConst()));
|
|
}
|