aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/array_list.zig33
-rw-r--r--lib/std/debug/failing_allocator.zig16
-rw-r--r--lib/std/json.zig1
-rw-r--r--lib/std/json/write_stream.zig86
-rw-r--r--lib/std/mem.zig10
-rw-r--r--lib/std/special/docs/index.html1
-rw-r--r--lib/std/special/docs/main.js2
-rw-r--r--lib/std/target.zig9
-rw-r--r--src/codegen.cpp12
9 files changed, 158 insertions, 12 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,
"{}-{}-{}",
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 6ee36a72ea..d01bcfbd77 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8469,12 +8469,7 @@ static void init(CodeGen *g) {
// uses as base cpu.
// TODO https://github.com/ziglang/zig/issues/2883
target_specific_cpu_args = "pentium4";
- if (g->zig_target->os == OsFreestanding) {
- target_specific_features = "-sse";
- }
- else {
- target_specific_features = "";
- }
+ target_specific_features = (g->zig_target->os == OsFreestanding) ? "-sse": "";
} else {
target_specific_cpu_args = "";
target_specific_features = "";
@@ -8779,6 +8774,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
args.append("-target-feature");
args.append("-Xclang");
args.append(riscv_default_features);
+ } else if (g->zig_target->os == OsFreestanding && g->zig_target->arch == ZigLLVM_x86) {
+ args.append("-Xclang");
+ args.append("-target-feature");
+ args.append("-Xclang");
+ args.append("-sse");
}
}
if (g->zig_target->os == OsFreestanding) {