Skip to content

Commit 6788e7e

Browse files
authored
support writer (#3)
* remove init, use empty * add writer * bump version * use empty * add more tests
1 parent f7d47db commit 6788e7e

File tree

3 files changed

+134
-11
lines changed

3 files changed

+134
-11
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ std.debug.print("len={} capacity={}\n", .{ list.len, list.capacity });
5555
First, add the dependency to your `build.zig.zon`:
5656

5757
```sh
58-
zig fetch --save git+https://github.com/kalamay/small-array-list#v0.1.1
58+
zig fetch --save git+https://github.com/kalamay/small-array-list#v0.2.0
5959
```
6060

6161
Next add the dependecy to your `build.zig`:
@@ -103,7 +103,7 @@ native machine word size. Because a zig slice requires two machine words for
103103
storing it's `ptr` and `len`, this space can be used for direct item storage
104104
instead until the small capacity is exceeded. For any given type `T`, the
105105
small array list can store up to `2*@sizeOf(usize) / @sizeOf(T)` items before
106-
requiring any internal allocation.
106+
requiring any internal allocation.
107107

108108
For example on a 64-bit processor will print out `smallCapacity=4 sizeOf=24`:
109109

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.{
22
.name = .small_array_list,
3-
.version = "0.1.1",
3+
.version = "0.2.0",
44
.fingerprint = 0x378608764b63102b,
55
.minimum_zig_version = "0.14.0",
66
.paths = .{

src/root.zig

Lines changed: 131 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,11 @@ pub fn SmallArrayListAlignedSized(comptime T: type, comptime alignment: ?u29, co
120120
pub const Slice = SliceType;
121121
pub const SliceConst = SliceConstType;
122122

123-
/// Initialized an empty SmallArrayList. Deinitialize with `deinit`.
124-
pub fn init() Self {
125-
return empty;
126-
}
127-
128123
/// Initialize with capacity to hold `num` elements.
129124
/// The resulting capacity will equal `num` exactly.
130125
/// Deinitialize with `deinit`.
131126
pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {
132-
var self = Self{};
127+
var self = Self.empty;
133128
try self.ensureTotalCapacityPrecise(gpa, num);
134129
return self;
135130
}
@@ -649,6 +644,47 @@ pub fn SmallArrayListAlignedSized(comptime T: type, comptime alignment: ?u29, co
649644
self.as.slice = new_mem;
650645
self.capacity = new_capacity;
651646
}
647+
648+
pub const WriterContext = struct {
649+
self: *Self,
650+
allocator: Allocator,
651+
};
652+
653+
pub const Writer = if (T != u8)
654+
@compileError("The Writer interface is only defined for SmallArrayList(u8) " ++
655+
"but the given type is SmallArrayList(" ++ @typeName(T) ++ ")")
656+
else
657+
std.io.Writer(WriterContext, Allocator.Error, appendWrite);
658+
659+
/// Initializes a Writer which will append to the list.
660+
pub fn writer(self: *Self, gpa: Allocator) Writer {
661+
return .{ .context = .{ .self = self, .allocator = gpa } };
662+
}
663+
664+
/// Same as `append` except it returns the number of bytes written,
665+
/// which is always the same as `m.len`. The purpose of this function
666+
/// existing is to match `std.io.Writer` API.
667+
/// Invalidates element pointers if additional memory is needed.
668+
fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
669+
try context.self.appendSlice(context.allocator, m);
670+
return m.len;
671+
}
672+
673+
pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
674+
675+
/// Initializes a Writer which will append to the list but will return
676+
/// `error.OutOfMemory` rather than increasing capacity.
677+
pub fn fixedWriter(self: *Self) FixedWriter {
678+
return .{ .context = self };
679+
}
680+
681+
/// The purpose of this function existing is to match `std.io.Writer` API.
682+
fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
683+
const available_capacity = self.capacity - self.len;
684+
if (m.len > available_capacity) return error.OutOfMemory;
685+
self.appendSliceAssumeCapacity(m);
686+
return m.len;
687+
}
652688
};
653689
}
654690

@@ -689,14 +725,14 @@ test "init" {
689725
test "initCapacity" {
690726
{
691727
const a = testing.allocator;
692-
var list = try SmallArrayList(i8).initCapacity(a, 200);
728+
var list = try SmallArrayList(u8).initCapacity(a, 200);
693729
defer list.deinit(a);
694730
try testing.expect(list.len == 0);
695731
try testing.expect(list.capacity >= 200);
696732
}
697733
{
698734
const a = testing.allocator;
699-
var list = try SmallArrayListSized(i8, 8).initCapacity(a, 6);
735+
var list = try SmallArrayListSized(u8, 8).initCapacity(a, 6);
700736
try testing.expect(list.len == 0);
701737
try testing.expect(list.capacity >= 6);
702738
try testing.expect(!list.hasAllocation());
@@ -805,6 +841,20 @@ test "basic" {
805841
try testing.expect(list.pop() == 33);
806842
}
807843

844+
test "appendSlice" {
845+
const a = testing.allocator;
846+
var list: SmallArrayList(u8) = .empty;
847+
defer list.deinit(a);
848+
849+
try list.appendSlice(a, "abcdefg");
850+
try testing.expect(!list.hasAllocation());
851+
try list.appendSlice(a, "hijklmn");
852+
try testing.expect(!list.hasAllocation());
853+
try list.appendSlice(a, "opqrstu");
854+
try testing.expect(list.hasAllocation());
855+
try testing.expectEqualStrings("abcdefghijklmnopqrstu", list.items());
856+
}
857+
808858
test "appendNTimes" {
809859
const a = testing.allocator;
810860
var list: SmallArrayList(i32) = .empty;
@@ -1185,3 +1235,76 @@ test "sized" {
11851235
try testing.expect(list1.hasAllocation());
11861236
try testing.expect(!list2.hasAllocation());
11871237
}
1238+
1239+
test "expand and shrink" {
1240+
const List = SmallArrayList(u8);
1241+
var list: List = .empty;
1242+
try testing.expectEqual(list.len, 0);
1243+
try testing.expectEqual(list.capacity, List.smallCapacity);
1244+
1245+
list.expandToCapacity();
1246+
try testing.expectEqual(list.len, List.smallCapacity);
1247+
try testing.expectEqual(list.capacity, List.smallCapacity);
1248+
1249+
list.shrinkRetainingCapacity(4);
1250+
try testing.expectEqual(list.len, 4);
1251+
try testing.expectEqual(list.capacity, List.smallCapacity);
1252+
1253+
list.clearRetainingCapacity();
1254+
try testing.expectEqual(list.len, 0);
1255+
try testing.expectEqual(list.capacity, List.smallCapacity);
1256+
}
1257+
1258+
test "ensureTotalCapacity" {
1259+
const List = SmallArrayList(u8);
1260+
const a = testing.allocator;
1261+
var list: List = .empty;
1262+
1263+
try list.ensureTotalCapacity(a, 100);
1264+
1265+
try testing.expectEqual(list.len, 0);
1266+
try testing.expectEqual(list.capacity, 128);
1267+
1268+
list.clearAndFree(a);
1269+
1270+
try testing.expectEqual(list.len, 0);
1271+
try testing.expectEqual(list.capacity, List.smallCapacity);
1272+
}
1273+
1274+
test "SmallArrayList(u8) implements writer" {
1275+
const a = testing.allocator;
1276+
1277+
{
1278+
var buffer: SmallArrayList(u8) = .empty;
1279+
defer buffer.deinit(a);
1280+
1281+
const x: i32 = 42;
1282+
const y: i32 = 1234;
1283+
try buffer.writer(a).print("x: {}\ny: {}\n", .{ x, y });
1284+
1285+
try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items());
1286+
}
1287+
{
1288+
var list: SmallArrayListAligned(u8, 2) = .empty;
1289+
defer list.deinit(a);
1290+
1291+
const writer = list.writer(a);
1292+
try writer.writeAll("a");
1293+
try writer.writeAll("bc");
1294+
try writer.writeAll("d");
1295+
try writer.writeAll("efg");
1296+
1297+
try testing.expectEqualSlices(u8, "abcdefg", list.items());
1298+
}
1299+
}
1300+
1301+
test "SmallArrayList(u8) implements fixedWriter" {
1302+
var buffer: SmallArrayList(u8) = .empty;
1303+
1304+
const x: i32 = 42;
1305+
const y: i32 = 1234;
1306+
try buffer.fixedWriter().print("x: {}\ny: {}\n", .{ x, y });
1307+
1308+
try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items());
1309+
try testing.expectError(error.OutOfMemory, buffer.fixedWriter().print("x: {}\ny: {}\n", .{ x, y }));
1310+
}

0 commit comments

Comments
 (0)