1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
const debug = @import("debug.zig");
const mem = @import("mem.zig");
const Allocator = mem.Allocator;
const assert = debug.assert;
const ArrayList = @import("array_list.zig").ArrayList;
const fmt = @import("fmt/index.zig");
/// A buffer that allocates memory and maintains a null byte at the end.
pub const Buffer = struct {
list: ArrayList(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 = ArrayList(u8).init(allocator),
}
}
/// Must deinitialize with deinit.
pub fn initFromBuffer(buffer: &const Buffer) -> %Buffer {
return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
}
/// Buffer takes ownership of the passed in slice. The slice must have been
/// allocated with `allocator`.
/// Must deinitialize with deinit.
pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) -> Buffer {
var self = Buffer {
.list = ArrayList(u8).fromOwnedSlice(allocator, slice),
};
self.list.append(0);
return self;
}
/// The caller owns the returned memory. The Buffer becomes null and
/// is safe to `deinit`.
pub fn toOwnedSlice(self: &Buffer) -> []u8 {
const allocator = self.list.allocator;
const result = allocator.shrink(u8, self.list.items, self.len());
*self = initNull(allocator);
return result;
}
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 shrink(self: &Buffer, new_len: usize) {
assert(new_len <= self.len());
self.list.shrink(new_len + 1);
self.list.items[self.len()] = 0;
}
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 appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void {
return fmt.format(self, append, format, args);
}
pub fn appendByte(self: &Buffer, byte: u8) -> %void {
return self.appendByteNTimes(byte, 1);
}
pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) -> %void {
var prev_size: usize = self.len();
%return self.resize(prev_size + count);
var i: usize = 0;
while (i < count) : (i += 1) {
self.list.items[prev_size + i] = 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..l], 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"));
assert(buf.endsWith("orld"));
%%buf2.resize(4);
assert(buf.startsWith(buf2.toSliceConst()));
}
|