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
161
162
163
164
165
166
167
168
169
170
|
const std = @import("index.zig");
const debug = std.debug;
const mem = std.mem;
const Allocator = mem.Allocator;
const assert = debug.assert;
const ArrayList = std.ArrayList;
const fmt = std.fmt;
/// 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 = try 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);
try 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 {
return 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) void {
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) void {
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 {
try 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();
try self.resize(old_len + m.len);
mem.copy(u8, self.list.toSlice()[old_len..], m);
}
// TODO: remove, use OutStream for this
pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void {
return fmt.format(self, append, format, args);
}
// TODO: remove, use OutStream for this
pub fn appendByte(self: &Buffer, byte: u8) !void {
return self.appendByteNTimes(byte, 1);
}
// TODO: remove, use OutStream for this
pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void {
var prev_size: usize = self.len();
const new_size = prev_size + count;
try self.resize(new_size);
var i: usize = prev_size;
while (i < new_size) : (i += 1) {
self.list.items[i] = byte;
}
}
pub fn eql(self: &const Buffer, m: []const u8) bool {
return 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 {
try self.resize(m.len);
mem.copy(u8, self.list.toSlice(), m);
}
/// For passing to C functions.
pub fn ptr(self: &const Buffer) &u8 {
return self.list.items.ptr;
}
};
test "simple Buffer" {
const cstr = @import("cstr.zig");
var buf = try Buffer.init(debug.global_allocator, "");
assert(buf.len() == 0);
try buf.append("hello");
try buf.appendByte(' ');
try buf.append("world");
assert(buf.eql("hello world"));
assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
var buf2 = try Buffer.initFromBuffer(&buf);
assert(buf.eql(buf2.toSliceConst()));
assert(buf.startsWith("hell"));
assert(buf.endsWith("orld"));
try buf2.resize(4);
assert(buf.startsWith(buf2.toSliceConst()));
}
|