diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/array_list.zig | 33 | ||||
| -rw-r--r-- | lib/std/debug/failing_allocator.zig | 16 | ||||
| -rw-r--r-- | lib/std/json.zig | 1 | ||||
| -rw-r--r-- | lib/std/json/write_stream.zig | 86 | ||||
| -rw-r--r-- | lib/std/mem.zig | 10 | ||||
| -rw-r--r-- | lib/std/special/docs/index.html | 1 | ||||
| -rw-r--r-- | lib/std/special/docs/main.js | 2 | ||||
| -rw-r--r-- | lib/std/target.zig | 9 |
8 files changed, 152 insertions, 6 deletions
diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 31ae02b291..a57839ec3b 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -5,6 +5,10 @@ const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; +/// List of items. +/// +/// This is a wrapper around an array of T values. Initialize with +/// `init`. pub fn ArrayList(comptime T: type) type { return AlignedArrayList(T, null); } @@ -37,18 +41,24 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { }; } + /// Release all allocated memory. pub fn deinit(self: Self) void { self.allocator.free(self.items); } + /// Return contents as a slice. Only valid while the list + /// doesn't change size. pub fn toSlice(self: Self) Slice { return self.items[0..self.len]; } + /// Return list as const slice. Only valid while the list + /// doesn't change size. pub fn toSliceConst(self: Self) SliceConst { return self.items[0..self.len]; } + /// Safely access index i of the list. pub fn at(self: Self, i: usize) T { return self.toSliceConst()[i]; } @@ -66,10 +76,13 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { self.items[i] = item; } + /// Return length of the list. pub fn count(self: Self) usize { return self.len; } + /// Return the maximum number of items the list can hold + /// without allocating more memory. pub fn capacity(self: Self) usize { return self.items.len; } @@ -93,6 +106,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { return result; } + /// Insert `item` at index `n`. Moves `list[n .. list.count()]` + /// to make room. pub fn insert(self: *Self, n: usize, item: T) !void { try self.ensureCapacity(self.len + 1); self.len += 1; @@ -101,6 +116,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { self.items[n] = item; } + /// Insert slice `items` at index `n`. Moves + /// `list[n .. list.count()]` to make room. pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void { try self.ensureCapacity(self.len + items.len); self.len += items.len; @@ -109,16 +126,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { mem.copy(T, self.items[n .. n + items.len], items); } + /// Extend the list by 1 element. Allocates more memory as + /// necessary. pub fn append(self: *Self, item: T) !void { const new_item_ptr = try self.addOne(); new_item_ptr.* = item; } + /// Extend the list by 1 element, but asserting `self.capacity` + /// is sufficient to hold an additional item. pub fn appendAssumeCapacity(self: *Self, item: T) void { const new_item_ptr = self.addOneAssumeCapacity(); new_item_ptr.* = item; } + /// Remove the element at index `i` from the list and return + /// its value. Asserts the array has at least one item. pub fn orderedRemove(self: *Self, i: usize) T { const newlen = self.len - 1; if (newlen == i) return self.pop(); @@ -149,17 +172,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { return self.swapRemove(i); } + /// Append the slice of items to the list. Allocates more + /// memory as necessary. pub fn appendSlice(self: *Self, items: SliceConst) !void { try self.ensureCapacity(self.len + items.len); mem.copy(T, self.items[self.len..], items); self.len += items.len; } + /// Adjust the list's length to `new_len`. Doesn't initialize + /// added items if any. pub fn resize(self: *Self, new_len: usize) !void { try self.ensureCapacity(new_len); self.len = new_len; } + /// Reduce allocated capacity to `new_len`. pub fn shrink(self: *Self, new_len: usize) void { assert(new_len <= self.len); self.len = new_len; @@ -178,6 +206,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { self.items = try self.allocator.realloc(self.items, better_capacity); } + /// Increase length by 1, returning pointer to the new item. pub fn addOne(self: *Self) !*T { const new_length = self.len + 1; try self.ensureCapacity(new_length); @@ -191,11 +220,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { return result; } + /// Remove and return the last element from the list. Asserts + /// the list has at least one item. pub fn pop(self: *Self) T { self.len -= 1; return self.items[self.len]; } + /// Like `pop` but returns `null` if empty. pub fn popOrNull(self: *Self) ?T { if (self.len == 0) return null; return self.pop(); @@ -218,6 +250,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { } }; + /// Return an iterator over the list. pub fn iterator(self: *const Self) Iterator { return Iterator{ .list = self, diff --git a/lib/std/debug/failing_allocator.zig b/lib/std/debug/failing_allocator.zig index 5776d23194..6afd7c4880 100644 --- a/lib/std/debug/failing_allocator.zig +++ b/lib/std/debug/failing_allocator.zig @@ -3,6 +3,14 @@ const mem = std.mem; /// Allocator that fails after N allocations, useful for making sure out of /// memory conditions are handled correctly. +/// +/// To use this, first initialize it and get an allocator with +/// +/// `const failing_allocator = &FailingAllocator.init(<allocator>, +/// <fail_index>).allocator;` +/// +/// Then use `failing_allocator` anywhere you would have used a +/// different allocator. pub const FailingAllocator = struct { allocator: mem.Allocator, index: usize, @@ -13,6 +21,14 @@ pub const FailingAllocator = struct { allocations: usize, deallocations: usize, + /// `fail_index` is the number of successful allocations you can + /// expect from this allocator. The next allocation will fail. + /// For example, if this is called with `fail_index` equal to 2, + /// the following test will pass: + /// + /// var a = try failing_alloc.create(i32); + /// var b = try failing_alloc.create(i32); + /// testing.expectError(error.OutOfMemory, failing_alloc.create(i32)); pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator { return FailingAllocator{ .internal_allocator = allocator, diff --git a/lib/std/json.zig b/lib/std/json.zig index 18a9b31f2b..f385205a24 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1404,6 +1404,7 @@ test "json.parser.dynamic" { test "import more json tests" { _ = @import("json/test.zig"); + _ = @import("json/write_stream.zig"); } test "write json then parse it" { diff --git a/lib/std/json/write_stream.zig b/lib/std/json/write_stream.zig index c30f8ba8d8..0702a3e9f5 100644 --- a/lib/std/json/write_stream.zig +++ b/lib/std/json/write_stream.zig @@ -197,6 +197,34 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type { try self.stream.writeByte('"'); } + /// Writes the complete json into the output stream + pub fn emitJson(self: *Self, json: std.json.Value) Stream.Error!void { + switch (json) { + .Null => try self.emitNull(), + .Bool => |inner| try self.emitBool(inner), + .Integer => |inner| try self.emitNumber(inner), + .Float => |inner| try self.emitNumber(inner), + .String => |inner| try self.emitString(inner), + .Array => |inner| { + try self.beginArray(); + for (inner.toSliceConst()) |elem| { + try self.arrayElem(); + try self.emitJson(elem); + } + try self.endArray(); + }, + .Object => |inner| { + try self.beginObject(); + var it = inner.iterator(); + while (it.next()) |entry| { + try self.objectField(entry.key); + try self.emitJson(entry.value); + } + try self.endObject(); + }, + } + } + fn indent(self: *Self) !void { assert(self.state_index >= 1); try self.stream.write(self.newline); @@ -216,3 +244,61 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type { } }; } + +test "json write stream" { + var out_buf: [1024]u8 = undefined; + var slice_stream = std.io.SliceOutStream.init(&out_buf); + const out = &slice_stream.stream; + + var mem_buf: [1024 * 10]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(&mem_buf).allocator; + + var w = std.json.WriteStream(@typeOf(out).Child, 10).init(out); + try w.emitJson(try getJson(allocator)); + + const result = slice_stream.getWritten(); + const expected = + \\{ + \\ "object": { + \\ "one": 1, + \\ "two": 2.0e+00 + \\ }, + \\ "string": "This is a string", + \\ "array": [ + \\ "Another string", + \\ 1, + \\ 3.14e+00 + \\ ], + \\ "int": 10, + \\ "float": 3.14e+00 + \\} + ; + std.testing.expect(std.mem.eql(u8, expected, result)); +} + +fn getJson(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; + _ = try value.Object.put("string", std.json.Value{ .String = "This is a string" }); + _ = try value.Object.put("int", std.json.Value{ .Integer = @intCast(i64, 10) }); + _ = try value.Object.put("float", std.json.Value{ .Float = 3.14 }); + _ = try value.Object.put("array", try getJsonArray(allocator)); + _ = try value.Object.put("object", try getJsonObject(allocator)); + return value; +} + +fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; + _ = try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) }); + _ = try value.Object.put("two", std.json.Value{ .Float = 2.0 }); + return value; +} + +fn getJsonArray(allocator: *std.mem.Allocator) !std.json.Value { + var value = std.json.Value{ .Array = std.json.Array.init(allocator) }; + var array = &value.Array; + _ = try array.append(std.json.Value{ .String = "Another string" }); + _ = try array.append(std.json.Value{ .Integer = @intCast(i64, 1) }); + _ = try array.append(std.json.Value{ .Float = 3.14 }); + + return value; +} diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 601c50242d..6443c64815 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -93,6 +93,14 @@ pub const Allocator = struct { assert(shrink_result.len == 0); } + /// Allocates an array of `n` items of type `T` and sets all the + /// items to `undefined`. Depending on the Allocator + /// implementation, it may be required to call `free` once the + /// memory is no longer needed, to avoid a resource leak. If the + /// `Allocator` implementation is unknown, then correct code will + /// call `free` when done. + /// + /// For allocating a single item, see `create`. pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T { return self.alignedAlloc(T, null, n); } @@ -218,6 +226,8 @@ pub const Allocator = struct { return @bytesToSlice(T, @alignCast(new_alignment, byte_slice)); } + /// Free an array allocated with `alloc`. To free a single item, + /// see `destroy`. pub fn free(self: *Allocator, memory: var) void { const Slice = @typeInfo(@typeOf(memory)).Pointer; const bytes = @sliceToBytes(memory); diff --git a/lib/std/special/docs/index.html b/lib/std/special/docs/index.html index 8ce1033235..f390f7671d 100644 --- a/lib/std/special/docs/index.html +++ b/lib/std/special/docs/index.html @@ -270,7 +270,6 @@ } .docs td { - vertical-align: top; margin: 0; padding: 0.5em; max-width: 27em; diff --git a/lib/std/special/docs/main.js b/lib/std/special/docs/main.js index 74049f8546..e0d6cdaf05 100644 --- a/lib/std/special/docs/main.js +++ b/lib/std/special/docs/main.js @@ -1369,7 +1369,7 @@ line.text = line.text.substr(1); } else if (line.text.match(/\d+\./)) { - const match = line.match(/(\d+)\./); + const match = line.text.match(/(\d+)\./); line.type = "ul"; line.text = line.text.substr(match[0].length); line.ordered_number = Number(match[1].length); diff --git a/lib/std/target.zig b/lib/std/target.zig index b81563d327..095ba3c8e1 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1,4 +1,5 @@ const std = @import("std.zig"); +const mem = std.mem; const builtin = std.builtin; /// TODO Nearly all the functions in this namespace would be @@ -204,7 +205,7 @@ pub const Target = union(enum) { }, }; - pub fn zigTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { return std.fmt.allocPrint( allocator, "{}{}-{}-{}", @@ -215,13 +216,13 @@ pub const Target = union(enum) { ); } - pub fn allocDescription(self: Target, allocator: *std.mem.Allocator) ![]u8 { + pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 { // TODO is there anything else worthy of the description that is not // already captured in the triple? return self.zigTriple(allocator); } - pub fn zigTripleNoSubArch(self: Target, allocator: *std.mem.Allocator) ![]u8 { + pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 { return std.fmt.allocPrint( allocator, "{}-{}-{}", @@ -231,7 +232,7 @@ pub const Target = union(enum) { ); } - pub fn linuxTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 { return std.fmt.allocPrint( allocator, "{}-{}-{}", |
