Merge pull request #1019 from zig-lang/pointer-reform

Pointer Reform - change prefix deref syntax to postfix deref syntax
This commit is contained in:
Andrew Kelley 2018-05-18 13:30:25 -04:00 committed by GitHub
commit 83a7809478
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 6022 additions and 4253 deletions

View File

@ -16,7 +16,7 @@ pub fn build(b: &Builder) !void {
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 {
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
docgen_exe.getOutputPath(),
rel_zig_exe,
"doc/langref.html.in",
@ -30,7 +30,10 @@ pub fn build(b: &Builder) !void {
const test_step = b.step("test", "Run all the tests");
// find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
const build_info = try b.exec([][]const u8{
b.zig_exe,
"BUILD_INFO",
});
var index: usize = 0;
const cmake_binary_dir = nextValue(&index, build_info);
const cxx_compiler = nextValue(&index, build_info);
@ -67,7 +70,10 @@ pub fn build(b: &Builder) !void {
dependOnLib(exe, llvm);
if (exe.target.getOs() == builtin.Os.linux) {
const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
const libstdcxx_path_padded = try b.exec([][]const u8{
cxx_compiler,
"-print-file-name=libstdc++.a",
});
const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
warn(
@ -111,17 +117,11 @@ pub fn build(b: &Builder) !void {
test_step.dependOn(docs_step);
test_step.dependOn(tests.addPkgTests(b, test_filter,
"test/behavior.zig", "behavior", "Run the behavior tests",
with_lldb));
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", with_lldb));
test_step.dependOn(tests.addPkgTests(b, test_filter,
"std/index.zig", "std", "Run the standard library tests",
with_lldb));
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", with_lldb));
test_step.dependOn(tests.addPkgTests(b, test_filter,
"std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests",
with_lldb));
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", with_lldb));
test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
@ -149,8 +149,7 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) vo
fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) void {
const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp",
b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
}
const LibraryDep = struct {
@ -161,11 +160,21 @@ const LibraryDep = struct {
};
fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
const libs_output = try b.exec([][]const u8{
llvm_config_exe,
"--libs",
"--system-libs",
});
const includes_output = try b.exec([][]const u8{
llvm_config_exe,
"--includedir",
});
const libdir_output = try b.exec([][]const u8{
llvm_config_exe,
"--libdir",
});
var result = LibraryDep {
var result = LibraryDep{
.libs = ArrayList([]const u8).init(b.allocator),
.system_libs = ArrayList([]const u8).init(b.allocator),
.includes = ArrayList([]const u8).init(b.allocator),
@ -227,17 +236,17 @@ pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {
}
fn nextValue(index: &usize, build_info: []const u8) []const u8 {
const start = *index;
while (true) : (*index += 1) {
switch (build_info[*index]) {
const start = index.*;
while (true) : (index.* += 1) {
switch (build_info[index.*]) {
'\n' => {
const result = build_info[start..*index];
*index += 1;
const result = build_info[start..index.*];
index.* += 1;
return result;
},
'\r' => {
const result = build_info[start..*index];
*index += 2;
const result = build_info[start..index.*];
index.* += 2;
return result;
},
else => continue,

View File

@ -1232,7 +1232,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
</td>
</tr>
<tr>
<td><pre><code class="zig">*a<code></pre></td>
<td><pre><code class="zig">a.*<code></pre></td>
<td>
<ul>
<li>{#link|Pointers#}</li>
@ -1244,7 +1244,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
<td>
<pre><code class="zig">const x: u32 = 1234;
const ptr = &amp;x;
*x == 1234</code></pre>
x.* == 1234</code></pre>
</td>
</tr>
<tr>
@ -1258,7 +1258,7 @@ const ptr = &amp;x;
<td>
<pre><code class="zig">const x: u32 = 1234;
const ptr = &amp;x;
*x == 1234</code></pre>
x.* == 1234</code></pre>
</td>
</tr>
</table>
@ -1267,8 +1267,8 @@ const ptr = &amp;x;
{#header_open|Precedence#}
<pre><code>x() x[] x.y
a!b
!x -x -%x ~x *x &amp;x ?x ??x
x{}
!x -x -%x ~x &amp;x ?x ??x
x{} x.*
! * / % ** *%
+ - ++ +% -%
&lt;&lt; &gt;&gt;
@ -1316,7 +1316,7 @@ var some_integers: [100]i32 = undefined;
test "modify an array" {
for (some_integers) |*item, i| {
*item = i32(i);
item.* = i32(i);
}
assert(some_integers[10] == 10);
assert(some_integers[99] == 99);
@ -1357,7 +1357,7 @@ comptime {
var fancy_array = init: {
var initial_value: [10]Point = undefined;
for (initial_value) |*pt, i| {
*pt = Point {
pt.* = Point {
.x = i32(i),
.y = i32(i) * 2,
};
@ -1400,7 +1400,7 @@ test "address of syntax" {
const x_ptr = &x;
// Deference a pointer:
assert(*x_ptr == 1234);
assert(x_ptr.* == 1234);
// When you get the address of a const variable, you get a const pointer.
assert(@typeOf(x_ptr) == &const i32);
@ -1409,8 +1409,8 @@ test "address of syntax" {
var y: i32 = 5678;
const y_ptr = &y;
assert(@typeOf(y_ptr) == &i32);
*y_ptr += 1;
assert(*y_ptr == 5679);
y_ptr.* += 1;
assert(y_ptr.* == 5679);
}
test "pointer array access" {
@ -1448,9 +1448,9 @@ comptime {
// @ptrCast.
var x: i32 = 1;
const ptr = &x;
*ptr += 1;
ptr.* += 1;
x += 1;
assert(*ptr == 3);
assert(ptr.* == 3);
}
test "@ptrToInt and @intToPtr" {
@ -1492,7 +1492,7 @@ test "nullable pointers" {
var x: i32 = 1;
ptr = &x;
assert(*??ptr == 1);
assert((??ptr).* == 1);
// Nullable pointers are the same size as normal pointers, because pointer
// value 0 is used as the null value.
@ -1505,7 +1505,7 @@ test "pointer casting" {
// conversions are not possible.
const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
const u32_ptr = @ptrCast(&const u32, &bytes[0]);
assert(*u32_ptr == 0x12121212);
assert(u32_ptr.* == 0x12121212);
// Even this example is contrived - there are better ways to do the above than
// pointer casting. For example, using a slice narrowing cast:
@ -1610,7 +1610,7 @@ fn foo(bytes: []u8) u32 {
<code>u8</code> can alias any memory.
</p>
<p>As an example, this code produces undefined behavior:</p>
<pre><code class="zig">*@ptrCast(&amp;u32, f32(12.34))</code></pre>
<pre><code class="zig">@ptrCast(&amp;u32, f32(12.34)).*</code></pre>
<p>Instead, use {#link|@bitCast#}:
<pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
<p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>
@ -2040,7 +2040,7 @@ const Variant = union(enum) {
Bool: bool,
fn truthy(self: &const Variant) bool {
return switch (*self) {
return switch (self.*) {
Variant.Int => |x_int| x_int != 0,
Variant.Bool => |x_bool| x_bool,
};
@ -2151,7 +2151,7 @@ test "switch enum" {
// A reference to the matched value can be obtained using `*` syntax.
Item.C => |*item| blk: {
(*item).x += 1;
item.*.x += 1;
break :blk 6;
},
@ -2374,7 +2374,7 @@ test "for reference" {
// Iterate over the slice by reference by
// specifying that the capture value is a pointer.
for (items) |*value| {
*value += 1;
value.* += 1;
}
assert(items[0] == 4);
@ -2483,7 +2483,7 @@ test "if nullable" {
// Access the value by reference using a pointer capture.
var c: ?u32 = 3;
if (c) |*value| {
*value = 2;
value.* = 2;
}
if (c) |value| {
@ -2524,7 +2524,7 @@ test "if error union" {
// Access the value by reference using a pointer capture.
var c: error!u32 = 3;
if (c) |*value| {
*value = 9;
value.* = 9;
} else |err| {
unreachable;
}
@ -3872,7 +3872,7 @@ pub fn main() void {
{#header_open|@addWithOverflow#}
<pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a + b</code>. If overflow or underflow occurs,
Performs <code>result.* = a + b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -4073,9 +4073,9 @@ comptime {
</p>
{#code_begin|syntax#}
fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
const old_value = *ptr;
const old_value = ptr.*;
if (old_value == expected_value) {
*ptr = new_value;
ptr.* = new_value;
return null;
} else {
return old_value;
@ -4100,9 +4100,9 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_v
</p>
{#code_begin|syntax#}
fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
const old_value = *ptr;
const old_value = ptr.*;
if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
*ptr = new_value;
ptr.* = new_value;
return null;
} else {
return old_value;
@ -4447,7 +4447,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
This function is a low level intrinsic with no safety mechanisms. Most
code should not use this function, instead using something like this:
</p>
<pre><code class="zig">for (dest[0...byte_count]) |*b| *b = c;</code></pre>
<pre><code class="zig">for (dest[0...byte_count]) |*b| b.* = c;</code></pre>
<p>
The optimizer is intelligent enough to turn the above snippet into a memset.
</p>
@ -4480,7 +4480,7 @@ mem.set(u8, dest, c);</code></pre>
{#header_open|@mulWithOverflow#}
<pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a * b</code>. If overflow or underflow occurs,
Performs <code>result.* = a * b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -4514,7 +4514,7 @@ fn targetFunction(x: i32) usize {
var local_variable: i32 = 42;
const ptr = &local_variable;
*ptr += 1;
ptr.* += 1;
assert(local_variable == 43);
return @ptrToInt(ptr);
@ -4746,7 +4746,7 @@ pub const FloatMode = enum {
{#header_open|@shlWithOverflow#}
<pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,
Performs <code>result.* = a &lt;&lt; b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -4790,7 +4790,7 @@ pub const FloatMode = enum {
{#header_open|@subWithOverflow#}
<pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a - b</code>. If overflow or underflow occurs,
Performs <code>result.* = a - b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -6382,10 +6382,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
FieldAccessExpression = "." Symbol
PtrDerefExpression = ".*"
FnCallExpression = "(" list(Expression, ",") ")"
ArrayAccessExpression = "[" Expression "]"
@ -6398,7 +6400,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
StructLiteralField = "." Symbol "=" Expression
PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType

View File

@ -30,24 +30,22 @@ fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
}
// Modifies the current argument index during iteration
fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize, allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
switch (required) {
0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
0 => return FlagArg{ .None = undefined }, // TODO: Required to force non-tag but value?
1 => {
if (*index + 1 >= args.len) {
if (index.* + 1 >= args.len) {
return error.MissingFlagArguments;
}
*index += 1;
const arg = args[*index];
index.* += 1;
const arg = args[index.*];
if (!argInAllowedSet(allowed_set, arg)) {
return error.ArgumentNotInAllowedSet;
}
return FlagArg { .Single = arg };
return FlagArg{ .Single = arg };
},
else => |needed| {
var extra = ArrayList([]const u8).init(allocator);
@ -55,12 +53,12 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
var j: usize = 0;
while (j < needed) : (j += 1) {
if (*index + 1 >= args.len) {
if (index.* + 1 >= args.len) {
return error.MissingFlagArguments;
}
*index += 1;
const arg = args[*index];
index.* += 1;
const arg = args[index.*];
if (!argInAllowedSet(allowed_set, arg)) {
return error.ArgumentNotInAllowedSet;
@ -69,7 +67,7 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
try extra.append(arg);
}
return FlagArg { .Many = extra };
return FlagArg{ .Many = extra };
},
}
}
@ -82,7 +80,7 @@ pub const Args = struct {
positionals: ArrayList([]const u8),
pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
var parsed = Args {
var parsed = Args{
.flags = HashMapFlags.init(allocator),
.positionals = ArrayList([]const u8).init(allocator),
};
@ -116,11 +114,7 @@ pub const Args = struct {
};
if (flag.mergable) {
var prev =
if (parsed.flags.get(flag_name_trimmed)) |entry|
entry.value.Many
else
ArrayList([]const u8).init(allocator);
var prev = if (parsed.flags.get(flag_name_trimmed)) |entry| entry.value.Many else ArrayList([]const u8).init(allocator);
// MergeN creation disallows 0 length flag entry (doesn't make sense)
switch (flag_args) {
@ -129,7 +123,7 @@ pub const Args = struct {
FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
}
_ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
_ = try parsed.flags.put(flag_name_trimmed, FlagArg{ .Many = prev });
} else {
_ = try parsed.flags.put(flag_name_trimmed, flag_args);
}
@ -163,7 +157,9 @@ pub const Args = struct {
pub fn single(self: &Args, name: []const u8) ?[]const u8 {
if (self.flags.get(name)) |entry| {
switch (entry.value) {
FlagArg.Single => |inner| { return inner; },
FlagArg.Single => |inner| {
return inner;
},
else => @panic("attempted to retrieve flag with wrong type"),
}
} else {
@ -175,7 +171,9 @@ pub const Args = struct {
pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
if (self.flags.get(name)) |entry| {
switch (entry.value) {
FlagArg.Many => |inner| { return inner.toSliceConst(); },
FlagArg.Many => |inner| {
return inner.toSliceConst();
},
else => @panic("attempted to retrieve flag with wrong type"),
}
} else {
@ -207,7 +205,7 @@ pub const Flag = struct {
}
pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
return Flag {
return Flag{
.name = name,
.required = n,
.mergable = false,
@ -220,7 +218,7 @@ pub const Flag = struct {
@compileError("n must be greater than 0");
}
return Flag {
return Flag{
.name = name,
.required = n,
.mergable = true,
@ -229,7 +227,7 @@ pub const Flag = struct {
}
pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
return Flag {
return Flag{
.name = name,
.required = 1,
.mergable = false,
@ -239,26 +237,36 @@ pub const Flag = struct {
};
test "parse arguments" {
const spec1 = comptime []const Flag {
const spec1 = comptime []const Flag{
Flag.Bool("--help"),
Flag.Bool("--init"),
Flag.Arg1("--build-file"),
Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
Flag.Option("--color", []const []const u8{
"on",
"off",
"auto",
}),
Flag.ArgN("--pkg-begin", 2),
Flag.ArgMergeN("--object", 1),
Flag.ArgN("--library", 1),
};
const cliargs = []const []const u8 {
const cliargs = []const []const u8{
"build",
"--help",
"pos1",
"--build-file", "build.zig",
"--object", "obj1",
"--object", "obj2",
"--library", "lib1",
"--library", "lib2",
"--color", "on",
"--build-file",
"build.zig",
"--object",
"obj1",
"--object",
"obj2",
"--library",
"lib1",
"--library",
"lib2",
"--color",
"on",
"pos2",
};

View File

@ -96,6 +96,7 @@ pub const Module = struct {
pub const LinkLib = struct {
name: []const u8,
path: ?[]const u8,
/// the list of symbols we depend on from this lib
symbols: ArrayList([]u8),
provided_explicitly: bool,
@ -130,9 +131,7 @@ pub const Module = struct {
}
};
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
{
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module {
var name_buffer = try Buffer.init(allocator, name);
errdefer name_buffer.deinit();
@ -148,14 +147,14 @@ pub const Module = struct {
const module_ptr = try allocator.create(Module);
errdefer allocator.destroy(module_ptr);
*module_ptr = Module {
module_ptr.* = Module{
.allocator = allocator,
.name = name_buffer,
.root_src_path = root_src_path,
.module = module,
.context = context,
.builder = builder,
.target = *target,
.target = target.*,
.kind = kind,
.build_mode = build_mode,
.zig_lib_dir = zig_lib_dir,
@ -221,8 +220,10 @@ pub const Module = struct {
pub fn build(self: &Module) !void {
if (self.llvm_argv.len != 0) {
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
[][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, [][]const []const u8{
[][]const u8{"zig (LLVM option parsing)"},
self.llvm_argv,
});
defer c_compatible_args.deinit();
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
}
@ -261,7 +262,6 @@ pub const Module = struct {
warn("====llvm ir:====\n");
self.dump();
}
pub fn link(self: &Module, out_file: ?[]const u8) !void {
@ -285,7 +285,7 @@ pub const Module = struct {
}
const link_lib = try self.allocator.create(LinkLib);
*link_lib = LinkLib {
link_lib.* = LinkLib{
.name = name,
.path = null,
.provided_explicitly = provided_explicitly,

View File

@ -12,7 +12,7 @@ pub const Target = union(enum) {
Cross: CrossTarget,
pub fn oFileExt(self: &const Target) []const u8 {
const environ = switch (*self) {
const environ = switch (self.*) {
Target.Native => builtin.environ,
Target.Cross => |t| t.environ,
};
@ -30,7 +30,7 @@ pub const Target = union(enum) {
}
pub fn getOs(self: &const Target) builtin.Os {
return switch (*self) {
return switch (self.*) {
Target.Native => builtin.os,
Target.Cross => |t| t.os,
};
@ -38,7 +38,8 @@ pub const Target = union(enum) {
pub fn isDarwin(self: &const Target) bool {
return switch (self.getOs()) {
builtin.Os.ios, builtin.Os.macosx => true,
builtin.Os.ios,
builtin.Os.macosx => true,
else => false,
};
}

View File

@ -379,6 +379,7 @@ enum NodeType {
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypePtrDeref,
NodeTypeUse,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
@ -603,13 +604,16 @@ struct AstNodeFieldAccessExpr {
Buf *field_name;
};
struct AstNodePtrDerefExpr {
AstNode *target;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
PrefixOpBinNot,
PrefixOpNegation,
PrefixOpNegationWrap,
PrefixOpDereference,
PrefixOpMaybe,
PrefixOpUnwrapMaybe,
};
@ -911,6 +915,7 @@ struct AstNode {
AstNodeCompTime comptime_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodePtrDerefExpr ptr_deref_expr;
AstNodeContainerDecl container_decl;
AstNodeStructField struct_field;
AstNodeStringLiteral string_literal;

View File

@ -3281,6 +3281,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeUnreachable:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypePtrDeref:
case NodeTypeStructField:
case NodeTypeContainerInitExpr:
case NodeTypeStructValueField:

View File

@ -66,7 +66,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
case PrefixOpNegationWrap: return "-%";
case PrefixOpBoolNot: return "!";
case PrefixOpBinNot: return "~";
case PrefixOpDereference: return "*";
case PrefixOpMaybe: return "?";
case PrefixOpUnwrapMaybe: return "??";
}
@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
return "AsmExpr";
case NodeTypeFieldAccessExpr:
return "FieldAccessExpr";
case NodeTypePtrDeref:
return "PtrDerefExpr";
case NodeTypeContainerDecl:
return "ContainerDecl";
case NodeTypeStructField:
@ -696,6 +697,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
print_symbol(ar, rhs);
break;
}
case NodeTypePtrDeref:
{
AstNode *lhs = node->data.ptr_deref_expr.target;
render_node_ungrouped(ar, lhs);
fprintf(ar->f, ".*");
break;
}
case NodeTypeUndefinedLiteral:
fprintf(ar->f, "undefined");
break;

View File

@ -4609,8 +4609,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
}
static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
AstNode *expr_node;
if (node->type == NodeTypePrefixOpExpr) {
expr_node = node->data.prefix_op_expr.primary_expr;
} else if (node->type == NodeTypePtrDeref) {
expr_node = node->data.ptr_deref_expr.target;
} else {
zig_unreachable();
}
IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
if (value == irb->codegen->invalid_instruction)
@ -4751,8 +4757,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
case PrefixOpNegationWrap:
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
case PrefixOpDereference:
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
case PrefixOpMaybe:
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
case PrefixOpUnwrapMaybe:
@ -6588,6 +6592,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_build_load_ptr(irb, scope, node, ptr_instruction);
}
case NodeTypePtrDeref:
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
case NodeTypeThisLiteral:
return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
case NodeTypeBoolLiteral:

View File

@ -1046,11 +1046,12 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
}
/*
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
SliceExpression = "[" Expression ".." option(Expression) "]"
FieldAccessExpression : token(Dot) token(Symbol)
PtrDerefExpression = ".*"
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
*/
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
@ -1131,13 +1132,27 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
} else if (first_token->id == TokenIdDot) {
*token_index += 1;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
Token *token = &pc->tokens->at(*token_index);
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
node->data.field_access_expr.struct_expr = primary_expr;
node->data.field_access_expr.field_name = token_buf(name_token);
if (token->id == TokenIdSymbol) {
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
node->data.field_access_expr.struct_expr = primary_expr;
node->data.field_access_expr.field_name = token_buf(token);
primary_expr = node;
} else if (token->id == TokenIdStar) {
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
node->data.ptr_deref_expr.target = primary_expr;
primary_expr = node;
} else {
ast_invalid_token_error(pc, token);
}
primary_expr = node;
} else {
return primary_expr;
}
@ -1150,10 +1165,8 @@ static PrefixOp tok_to_prefix_op(Token *token) {
case TokenIdDash: return PrefixOpNegation;
case TokenIdMinusPercent: return PrefixOpNegationWrap;
case TokenIdTilde: return PrefixOpBinNot;
case TokenIdStar: return PrefixOpDereference;
case TokenIdMaybe: return PrefixOpMaybe;
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
case TokenIdStarStar: return PrefixOpDereference;
default: return PrefixOpInvalid;
}
}
@ -1199,7 +1212,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
/*
PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
*/
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@ -1222,15 +1235,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
AstNode *parent_node = node;
if (token->id == TokenIdStarStar) {
// pretend that we got 2 star tokens
parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
parent_node->data.prefix_op_expr.primary_expr = node;
parent_node->data.prefix_op_expr.prefix_op = PrefixOpDereference;
node->column += 1;
}
AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
@ -3012,6 +3016,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeFieldAccessExpr:
visit_field(&node->data.field_access_expr.struct_expr, visit, context);
break;
case NodeTypePtrDeref:
visit_field(&node->data.ptr_deref_expr.target, visit, context);
break;
case NodeTypeUse:
visit_field(&node->data.use.expr, visit, context);
break;

View File

@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe
return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
}
static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) {
AstNode *node = trans_create_node(c, NodeTypePtrDeref);
node->data.ptr_deref_expr.target = child_node;
return node;
}
static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
node->data.prefix_op_expr.prefix_op = op;
@ -1412,8 +1418,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
stmt->getComputationLHSType(),
stmt->getLHS()->getType(),
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name)));
// result_type(... >> u5(rhs))
AstNode *result_type_cast = trans_c_cast(c, rhs_location,
@ -1426,7 +1431,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
// *_ref = ...
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, tmp_var_name)),
BinOpTypeAssign, result_type_cast);
@ -1436,7 +1441,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
// break :x *_ref
child_scope->node->data.block.statements.append(
trans_create_node_break(c, label_name,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, tmp_var_name))));
}
@ -1483,11 +1488,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
if (rhs == nullptr) return nullptr;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, tmp_var_name)),
BinOpTypeAssign,
trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, tmp_var_name)),
bin_op,
rhs));
@ -1496,7 +1501,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
// break :x *_ref
child_scope->node->data.block.statements.append(
trans_create_node_break(c, label_name,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, tmp_var_name))));
return child_scope->node;
@ -1817,13 +1822,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
// const _tmp = *_ref;
Buf* tmp_var_name = buf_create_from_str("_tmp");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, ref_var_name)));
child_scope->node->data.block.statements.append(tmp_var_decl);
// *_ref += 1;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, ref_var_name)),
assign_op,
trans_create_node_unsigned(c, 1));
@ -1871,14 +1876,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
// *_ref += 1;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, ref_var_name)),
assign_op,
trans_create_node_unsigned(c, 1));
child_scope->node->data.block.statements.append(assign_statement);
// break :x *_ref
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
AstNode *deref_expr = trans_create_node_ptr_deref(c,
trans_create_node_symbol(c, ref_var_name));
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
@ -1923,7 +1928,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
if (is_fn_ptr)
return value_node;
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);
return trans_create_node_ptr_deref(c, unwrapped);
}
case UO_Plus:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
@ -4443,27 +4448,45 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
}
}
static PrefixOp ctok_to_prefix_op(CTok *token) {
switch (token->id) {
case CTokIdBang: return PrefixOpBoolNot;
case CTokIdMinus: return PrefixOpNegation;
case CTokIdTilde: return PrefixOpBinNot;
case CTokIdAsterisk: return PrefixOpDereference;
default: return PrefixOpInvalid;
}
}
static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
CTok *op_tok = &ctok->tokens.at(*tok_i);
PrefixOp prefix_op = ctok_to_prefix_op(op_tok);
if (prefix_op == PrefixOpInvalid) {
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
}
*tok_i += 1;
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
if (prefix_op_expr == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr);
switch (op_tok->id) {
case CTokIdBang:
{
*tok_i += 1;
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
if (prefix_op_expr == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr);
}
case CTokIdMinus:
{
*tok_i += 1;
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
if (prefix_op_expr == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr);
}
case CTokIdTilde:
{
*tok_i += 1;
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
if (prefix_op_expr == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr);
}
case CTokIdAsterisk:
{
*tok_i += 1;
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
if (prefix_op_expr == nullptr)
return nullptr;
return trans_create_node_ptr_deref(c, prefix_op_expr);
}
default:
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
}
}
static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {

View File

@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) type {
return AlignedArrayList(T, @alignOf(T));
}
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
return struct {
const Self = this;
@ -21,7 +21,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
/// Deinitialize with `deinit` or use `toOwnedSlice`.
pub fn init(allocator: &Allocator) Self {
return Self {
return Self{
.items = []align(A) T{},
.len = 0,
.allocator = allocator,
@ -52,7 +52,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
/// allocated with `allocator`.
/// Deinitialize with `deinit` or use `toOwnedSlice`.
pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {
return Self {
return Self{
.items = slice,
.len = slice.len,
.allocator = allocator,
@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
pub fn toOwnedSlice(self: &Self) []align(A) T {
const allocator = self.allocator;
const result = allocator.alignedShrink(T, A, self.items, self.len);
*self = init(allocator);
self.* = init(allocator);
return result;
}
@ -71,21 +71,21 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
try l.ensureCapacity(l.len + 1);
l.len += 1;
mem.copy(T, l.items[n+1..l.len], l.items[n..l.len-1]);
l.items[n] = *item;
mem.copy(T, l.items[n + 1..l.len], l.items[n..l.len - 1]);
l.items[n] = item.*;
}
pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
try l.ensureCapacity(l.len + items.len);
l.len += items.len;
mem.copy(T, l.items[n+items.len..l.len], l.items[n..l.len-items.len]);
mem.copy(T, l.items[n..n+items.len], items);
mem.copy(T, l.items[n + items.len..l.len], l.items[n..l.len - items.len]);
mem.copy(T, l.items[n..n + items.len], items);
}
pub fn append(l: &Self, item: &const T) !void {
const new_item_ptr = try l.addOne();
*new_item_ptr = *item;
new_item_ptr.* = item.*;
}
pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
@ -128,8 +128,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
}
pub fn popOrNull(self: &Self) ?T {
if (self.len == 0)
return null;
if (self.len == 0) return null;
return self.pop();
}
@ -160,13 +159,19 @@ test "basic ArrayList test" {
var list = ArrayList(i32).init(debug.global_allocator);
defer list.deinit();
{var i: usize = 0; while (i < 10) : (i += 1) {
list.append(i32(i + 1)) catch unreachable;
}}
{
var i: usize = 0;
while (i < 10) : (i += 1) {
list.append(i32(i + 1)) catch unreachable;
}
}
{var i: usize = 0; while (i < 10) : (i += 1) {
assert(list.items[i] == i32(i + 1));
}}
{
var i: usize = 0;
while (i < 10) : (i += 1) {
assert(list.items[i] == i32(i + 1));
}
}
for (list.toSlice()) |v, i| {
assert(v == i32(i + 1));
@ -179,14 +184,18 @@ test "basic ArrayList test" {
assert(list.pop() == 10);
assert(list.len == 9);
list.appendSlice([]const i32 { 1, 2, 3 }) catch unreachable;
list.appendSlice([]const i32{
1,
2,
3,
}) catch unreachable;
assert(list.len == 12);
assert(list.pop() == 3);
assert(list.pop() == 2);
assert(list.pop() == 1);
assert(list.len == 9);
list.appendSlice([]const i32 {}) catch unreachable;
list.appendSlice([]const i32{}) catch unreachable;
assert(list.len == 9);
}
@ -228,12 +237,15 @@ test "insert ArrayList test" {
assert(list.items[0] == 5);
assert(list.items[1] == 1);
try list.insertSlice(1, []const i32 { 9, 8 });
try list.insertSlice(1, []const i32{
9,
8,
});
assert(list.items[0] == 5);
assert(list.items[1] == 9);
assert(list.items[2] == 8);
const items = []const i32 { 1 };
const items = []const i32{1};
try list.insertSlice(0, items[0..0]);
assert(list.items[0] == 5);
}

View File

@ -70,7 +70,7 @@ test "std.atomic.queue" {
var queue: Queue(i32) = undefined;
queue.init();
var context = Context {
var context = Context{
.allocator = a,
.queue = &queue,
.put_sum = 0,
@ -81,16 +81,18 @@ test "std.atomic.queue" {
var putters: [put_thread_count]&std.os.Thread = undefined;
for (putters) |*t| {
*t = try std.os.spawnThread(&context, startPuts);
t.* = try std.os.spawnThread(&context, startPuts);
}
var getters: [put_thread_count]&std.os.Thread = undefined;
for (getters) |*t| {
*t = try std.os.spawnThread(&context, startGets);
t.* = try std.os.spawnThread(&context, startGets);
}
for (putters) |t| t.wait();
for (putters) |t|
t.wait();
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
for (getters) |t| t.wait();
for (getters) |t|
t.wait();
std.debug.assert(context.put_sum == context.get_sum);
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);

View File

@ -14,9 +14,7 @@ pub fn Stack(comptime T: type) type {
};
pub fn init() Self {
return Self {
.root = null,
};
return Self{ .root = null };
}
/// push operation, but only if you are the first item in the stack. if you did not succeed in
@ -75,7 +73,7 @@ test "std.atomic.stack" {
var a = &fixed_buffer_allocator.allocator;
var stack = Stack(i32).init();
var context = Context {
var context = Context{
.allocator = a,
.stack = &stack,
.put_sum = 0,
@ -86,16 +84,18 @@ test "std.atomic.stack" {
var putters: [put_thread_count]&std.os.Thread = undefined;
for (putters) |*t| {
*t = try std.os.spawnThread(&context, startPuts);
t.* = try std.os.spawnThread(&context, startPuts);
}
var getters: [put_thread_count]&std.os.Thread = undefined;
for (getters) |*t| {
*t = try std.os.spawnThread(&context, startGets);
t.* = try std.os.spawnThread(&context, startGets);
}
for (putters) |t| t.wait();
for (putters) |t|
t.wait();
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
for (getters) |t| t.wait();
for (getters) |t|
t.wait();
std.debug.assert(context.put_sum == context.get_sum);
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);

View File

@ -31,9 +31,7 @@ pub const Buffer = struct {
/// * ::replaceContentsBuffer
/// * ::resize
pub fn initNull(allocator: &Allocator) Buffer {
return Buffer {
.list = ArrayList(u8).init(allocator),
};
return Buffer{ .list = ArrayList(u8).init(allocator) };
}
/// Must deinitialize with deinit.
@ -45,9 +43,7 @@ pub const Buffer = struct {
/// allocated with `allocator`.
/// Must deinitialize with deinit.
pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) Buffer {
var self = Buffer {
.list = ArrayList(u8).fromOwnedSlice(allocator, slice),
};
var self = Buffer{ .list = ArrayList(u8).fromOwnedSlice(allocator, slice) };
self.list.append(0);
return self;
}
@ -57,11 +53,10 @@ pub const Buffer = struct {
pub fn toOwnedSlice(self: &Buffer) []u8 {
const allocator = self.list.allocator;
const result = allocator.shrink(u8, self.list.items, self.len());
*self = initNull(allocator);
self.* = initNull(allocator);
return result;
}
pub fn deinit(self: &Buffer) void {
self.list.deinit();
}

View File

@ -82,10 +82,8 @@ pub const Builder = struct {
description: []const u8,
};
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8,
cache_root: []const u8) Builder
{
var self = Builder {
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
var self = Builder{
.zig_exe = zig_exe,
.build_root = build_root,
.cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
@ -112,12 +110,12 @@ pub const Builder = struct {
.lib_dir = undefined,
.exe_dir = undefined,
.installed_files = ArrayList([]const u8).init(allocator),
.uninstall_tls = TopLevelStep {
.uninstall_tls = TopLevelStep{
.step = Step.init("uninstall", allocator, makeUninstall),
.description = "Remove build artifacts from prefix path",
},
.have_uninstall_step = false,
.install_tls = TopLevelStep {
.install_tls = TopLevelStep{
.step = Step.initNoOp("install", allocator),
.description = "Copy build artifacts to prefix path",
},
@ -151,9 +149,7 @@ pub const Builder = struct {
return LibExeObjStep.createObject(self, name, root_src);
}
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8,
ver: &const Version) &LibExeObjStep
{
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);
}
@ -163,7 +159,7 @@ pub const Builder = struct {
pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {
const test_step = self.allocator.create(TestStep) catch unreachable;
*test_step = TestStep.init(self, root_src);
test_step.* = TestStep.init(self, root_src);
return test_step;
}
@ -190,33 +186,31 @@ pub const Builder = struct {
}
/// ::argv is copied.
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
argv: []const []const u8) &CommandStep
{
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
return CommandStep.create(self, cwd, env_map, argv);
}
pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {
const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
*write_file_step = WriteFileStep.init(self, file_path, data);
write_file_step.* = WriteFileStep.init(self, file_path, data);
return write_file_step;
}
pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) &LogStep {
const data = self.fmt(format, args);
const log_step = self.allocator.create(LogStep) catch unreachable;
*log_step = LogStep.init(self, data);
log_step.* = LogStep.init(self, data);
return log_step;
}
pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) &RemoveDirStep {
const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
*remove_dir_step = RemoveDirStep.init(self, dir_path);
remove_dir_step.* = RemoveDirStep.init(self, dir_path);
return remove_dir_step;
}
pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {
return Version {
return Version{
.major = major,
.minor = minor,
.patch = patch,
@ -254,8 +248,7 @@ pub const Builder = struct {
}
pub fn getInstallStep(self: &Builder) &Step {
if (self.have_install_step)
return &self.install_tls.step;
if (self.have_install_step) return &self.install_tls.step;
self.top_level_steps.append(&self.install_tls) catch unreachable;
self.have_install_step = true;
@ -263,8 +256,7 @@ pub const Builder = struct {
}
pub fn getUninstallStep(self: &Builder) &Step {
if (self.have_uninstall_step)
return &self.uninstall_tls.step;
if (self.have_uninstall_step) return &self.uninstall_tls.step;
self.top_level_steps.append(&self.uninstall_tls) catch unreachable;
self.have_uninstall_step = true;
@ -360,7 +352,7 @@ pub const Builder = struct {
pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
const type_id = comptime typeToEnum(T);
const available_option = AvailableOption {
const available_option = AvailableOption{
.name = name,
.type_id = type_id,
.description = description,
@ -413,7 +405,7 @@ pub const Builder = struct {
pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {
const step_info = self.allocator.create(TopLevelStep) catch unreachable;
*step_info = TopLevelStep {
step_info.* = TopLevelStep{
.step = Step.initNoOp(name, self.allocator),
.description = description,
};
@ -446,9 +438,9 @@ pub const Builder = struct {
}
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) bool {
if (self.user_input_options.put(name, UserInputOption {
if (self.user_input_options.put(name, UserInputOption{
.name = name,
.value = UserValue { .Scalar = value },
.value = UserValue{ .Scalar = value },
.used = false,
}) catch unreachable) |*prev_value| {
// option already exists
@ -458,18 +450,18 @@ pub const Builder = struct {
var list = ArrayList([]const u8).init(self.allocator);
list.append(s) catch unreachable;
list.append(value) catch unreachable;
_ = self.user_input_options.put(name, UserInputOption {
_ = self.user_input_options.put(name, UserInputOption{
.name = name,
.value = UserValue { .List = list },
.value = UserValue{ .List = list },
.used = false,
}) catch unreachable;
},
UserValue.List => |*list| {
// append to the list
list.append(value) catch unreachable;
_ = self.user_input_options.put(name, UserInputOption {
_ = self.user_input_options.put(name, UserInputOption{
.name = name,
.value = UserValue { .List = *list },
.value = UserValue{ .List = list.* },
.used = false,
}) catch unreachable;
},
@ -483,9 +475,9 @@ pub const Builder = struct {
}
pub fn addUserInputFlag(self: &Builder, name: []const u8) bool {
if (self.user_input_options.put(name, UserInputOption {
if (self.user_input_options.put(name, UserInputOption{
.name = name,
.value = UserValue {.Flag = {} },
.value = UserValue{ .Flag = {} },
.used = false,
}) catch unreachable) |*prev_value| {
switch (prev_value.value) {
@ -556,9 +548,7 @@ pub const Builder = struct {
warn("\n");
}
fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
argv: []const []const u8) !void
{
fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) !void {
if (self.verbose) {
printCmd(cwd, argv);
}
@ -617,7 +607,7 @@ pub const Builder = struct {
self.pushInstalledFile(full_dest_path);
const install_step = self.allocator.create(InstallFileStep) catch unreachable;
*install_step = InstallFileStep.init(self, src_path, full_dest_path);
install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
return install_step;
}
@ -659,25 +649,23 @@ pub const Builder = struct {
if (builtin.environ == builtin.Environ.msvc) {
return "cl.exe";
} else {
return os.getEnvVarOwned(self.allocator, "CC") catch |err|
return os.getEnvVarOwned(self.allocator, "CC") catch |err|
if (err == error.EnvironmentVariableNotFound)
([]const u8)("cc")
else
debug.panic("Unable to get environment variable: {}", err)
;
debug.panic("Unable to get environment variable: {}", err);
}
}
pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
// TODO report error for ambiguous situations
const exe_extension = (Target { .Native = {}}).exeFileExt();
const exe_extension = (Target{ .Native = {} }).exeFileExt();
for (self.search_prefixes.toSliceConst()) |search_prefix| {
for (names) |name| {
if (os.path.isAbsolute(name)) {
return name;
}
const full_path = try os.path.join(self.allocator, search_prefix, "bin",
self.fmt("{}{}", name, exe_extension));
const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
if (os.path.real(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
@ -761,7 +749,7 @@ pub const Target = union(enum) {
Cross: CrossTarget,
pub fn oFileExt(self: &const Target) []const u8 {
const environ = switch (*self) {
const environ = switch (self.*) {
Target.Native => builtin.environ,
Target.Cross => |t| t.environ,
};
@ -786,7 +774,7 @@ pub const Target = union(enum) {
}
pub fn getOs(self: &const Target) builtin.Os {
return switch (*self) {
return switch (self.*) {
Target.Native => builtin.os,
Target.Cross => |t| t.os,
};
@ -794,7 +782,8 @@ pub const Target = union(enum) {
pub fn isDarwin(self: &const Target) bool {
return switch (self.getOs()) {
builtin.Os.ios, builtin.Os.macosx => true,
builtin.Os.ios,
builtin.Os.macosx => true,
else => false,
};
}
@ -860,61 +849,57 @@ pub const LibExeObjStep = struct {
Obj,
};
pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8,
ver: &const Version) &LibExeObjStep
{
pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
return self;
}
pub fn createCSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initC(builder, name, Kind.Lib, version, false);
self.* = initC(builder, name, Kind.Lib, version, false);
return self;
}
pub fn createStaticLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
return self;
}
pub fn createCStaticLibrary(builder: &Builder, name: []const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
return self;
}
pub fn createObject(builder: &Builder, name: []const u8, root_src: []const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
return self;
}
pub fn createCObject(builder: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
self.object_src = src;
return self;
}
pub fn createExecutable(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
self.* = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
return self;
}
pub fn createCExecutable(builder: &Builder, name: []const u8) &LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
*self = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
return self;
}
fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind,
static: bool, ver: &const Version) LibExeObjStep
{
var self = LibExeObjStep {
fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: &const Version) LibExeObjStep {
var self = LibExeObjStep{
.strip = false,
.builder = builder,
.verbose_link = false,
@ -930,7 +915,7 @@ pub const LibExeObjStep = struct {
.step = Step.init(name, builder.allocator, make),
.output_path = null,
.output_h_path = null,
.version = *ver,
.version = ver.*,
.out_filename = undefined,
.out_h_filename = builder.fmt("{}.h", name),
.major_only_filename = undefined,
@ -953,11 +938,11 @@ pub const LibExeObjStep = struct {
}
fn initC(builder: &Builder, name: []const u8, kind: Kind, version: &const Version, static: bool) LibExeObjStep {
var self = LibExeObjStep {
var self = LibExeObjStep{
.builder = builder,
.name = name,
.kind = kind,
.version = *version,
.version = version.*,
.static = static,
.target = Target.Native,
.cflags = ArrayList([]const u8).init(builder.allocator),
@ -1005,9 +990,9 @@ pub const LibExeObjStep = struct {
self.out_filename = self.builder.fmt("lib{}.a", self.name);
} else {
switch (self.target.getOs()) {
builtin.Os.ios, builtin.Os.macosx => {
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib",
self.name, self.version.major, self.version.minor, self.version.patch);
builtin.Os.ios,
builtin.Os.macosx => {
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
},
@ -1015,8 +1000,7 @@ pub const LibExeObjStep = struct {
self.out_filename = self.builder.fmt("{}.dll", self.name);
},
else => {
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
self.name, self.version.major, self.version.minor, self.version.patch);
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
},
@ -1026,16 +1010,12 @@ pub const LibExeObjStep = struct {
}
}
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ) void
{
self.target = Target {
.Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
}
};
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
self.target = Target{ .Cross = CrossTarget{
.arch = target_arch,
.os = target_os,
.environ = target_environ,
} };
self.computeOutFileNames();
}
@ -1159,7 +1139,7 @@ pub const LibExeObjStep = struct {
pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
assert(self.is_zig);
self.packages.append(Pkg {
self.packages.append(Pkg{
.name = name,
.path = pkg_index_path,
}) catch unreachable;
@ -1343,8 +1323,7 @@ pub const LibExeObjStep = struct {
try builder.spawnChild(zig_args.toSliceConst());
if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
self.name_only_filename);
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
}
}
@ -1373,7 +1352,8 @@ pub const LibExeObjStep = struct {
args.append("ssp-buffer-size=4") catch unreachable;
}
},
builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {
builtin.Mode.ReleaseFast,
builtin.Mode.ReleaseSmall => {
args.append("-O2") catch unreachable;
args.append("-fno-stack-protector") catch unreachable;
},
@ -1505,8 +1485,7 @@ pub const LibExeObjStep = struct {
}
if (!is_darwin) {
const rpath_arg = builder.fmt("-Wl,-rpath,{}",
os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
defer builder.allocator.free(rpath_arg);
cc_args.append(rpath_arg) catch unreachable;
@ -1535,8 +1514,7 @@ pub const LibExeObjStep = struct {
try builder.spawnChild(cc_args.toSliceConst());
if (self.target.wantSharedLibSymLinks()) {
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
self.name_only_filename);
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
}
}
},
@ -1581,8 +1559,7 @@ pub const LibExeObjStep = struct {
cc_args.append("-o") catch unreachable;
cc_args.append(output_path) catch unreachable;
const rpath_arg = builder.fmt("-Wl,-rpath,{}",
os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
defer builder.allocator.free(rpath_arg);
cc_args.append(rpath_arg) catch unreachable;
@ -1635,7 +1612,7 @@ pub const TestStep = struct {
pub fn init(builder: &Builder, root_src: []const u8) TestStep {
const step_name = builder.fmt("test {}", root_src);
return TestStep {
return TestStep{
.step = Step.init(step_name, builder.allocator, make),
.builder = builder,
.root_src = root_src,
@ -1644,7 +1621,7 @@ pub const TestStep = struct {
.name_prefix = "",
.filter = null,
.link_libs = BufSet.init(builder.allocator),
.target = Target { .Native = {} },
.target = Target{ .Native = {} },
.exec_cmd_args = null,
.include_dirs = ArrayList([]const u8).init(builder.allocator),
};
@ -1674,16 +1651,12 @@ pub const TestStep = struct {
self.filter = text;
}
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ) void
{
self.target = Target {
.Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
}
};
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
self.target = Target{ .Cross = CrossTarget{
.arch = target_arch,
.os = target_os,
.environ = target_environ,
} };
}
pub fn setExecCmd(self: &TestStep, args: []const ?[]const u8) void {
@ -1789,11 +1762,9 @@ pub const CommandStep = struct {
env_map: &const BufMap,
/// ::argv is copied.
pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
argv: []const []const u8) &CommandStep
{
pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
const self = builder.allocator.create(CommandStep) catch unreachable;
*self = CommandStep {
self.* = CommandStep{
.builder = builder,
.step = Step.init(argv[0], builder.allocator, make),
.argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
@ -1828,7 +1799,7 @@ const InstallArtifactStep = struct {
LibExeObjStep.Kind.Exe => builder.exe_dir,
LibExeObjStep.Kind.Lib => builder.lib_dir,
};
*self = Self {
self.* = Self{
.builder = builder,
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
.artifact = artifact,
@ -1837,10 +1808,8 @@ const InstallArtifactStep = struct {
self.step.dependOn(&artifact.step);
builder.pushInstalledFile(self.dest_file);
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,
artifact.major_only_filename) catch unreachable);
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,
artifact.name_only_filename) catch unreachable);
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
}
return self;
}
@ -1859,8 +1828,7 @@ const InstallArtifactStep = struct {
};
try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
try doAtomicSymLinks(builder.allocator, self.dest_file,
self.artifact.major_only_filename, self.artifact.name_only_filename);
try doAtomicSymLinks(builder.allocator, self.dest_file, self.artifact.major_only_filename, self.artifact.name_only_filename);
}
}
};
@ -1872,7 +1840,7 @@ pub const InstallFileStep = struct {
dest_path: []const u8,
pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {
return InstallFileStep {
return InstallFileStep{
.builder = builder,
.step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
.src_path = src_path,
@ -1893,7 +1861,7 @@ pub const WriteFileStep = struct {
data: []const u8,
pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) WriteFileStep {
return WriteFileStep {
return WriteFileStep{
.builder = builder,
.step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),
.file_path = file_path,
@ -1922,7 +1890,7 @@ pub const LogStep = struct {
data: []const u8,
pub fn init(builder: &Builder, data: []const u8) LogStep {
return LogStep {
return LogStep{
.builder = builder,
.step = Step.init(builder.fmt("log {}", data), builder.allocator, make),
.data = data,
@ -1941,7 +1909,7 @@ pub const RemoveDirStep = struct {
dir_path: []const u8,
pub fn init(builder: &Builder, dir_path: []const u8) RemoveDirStep {
return RemoveDirStep {
return RemoveDirStep{
.builder = builder,
.step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),
.dir_path = dir_path,
@ -1966,8 +1934,8 @@ pub const Step = struct {
loop_flag: bool,
done_flag: bool,
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {
return Step {
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn(&Step) error!void) Step {
return Step{
.name = name,
.makeFn = makeFn,
.dependencies = ArrayList(&Step).init(allocator),
@ -1980,8 +1948,7 @@ pub const Step = struct {
}
pub fn make(self: &Step) !void {
if (self.done_flag)
return;
if (self.done_flag) return;
try self.makeFn(self);
self.done_flag = true;
@ -1994,9 +1961,7 @@ pub const Step = struct {
fn makeNoOp(self: &Step) error!void {}
};
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
filename_name_only: []const u8) !void
{
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
const out_dir = os.path.dirname(output_path);
const out_basename = os.path.basename(output_path);
// sym link for libfoo.so.1 to libfoo.so.1.2.3

View File

@ -6,11 +6,23 @@ const builtin = @import("builtin");
const htest = @import("test.zig");
const RoundParam = struct {
a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
a: usize,
b: usize,
c: usize,
d: usize,
x: usize,
y: usize,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
return RoundParam{
.a = a,
.b = b,
.c = c,
.d = d,
.x = x,
.y = y,
};
}
/////////////////////
@ -19,145 +31,153 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
pub const Blake2s224 = Blake2s(224);
pub const Blake2s256 = Blake2s(256);
fn Blake2s(comptime out_len: usize) type { return struct {
const Self = this;
const block_size = 64;
const digest_size = out_len / 8;
fn Blake2s(comptime out_len: usize) type {
return struct {
const Self = this;
const block_size = 64;
const digest_size = out_len / 8;
const iv = [8]u32 {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
};
const iv = [8]u32{
0x6A09E667,
0xBB67AE85,
0x3C6EF372,
0xA54FF53A,
0x510E527F,
0x9B05688C,
0x1F83D9AB,
0x5BE0CD19,
};
const sigma = [10][16]u8 {
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
[]const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
[]const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
[]const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
[]const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
[]const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
[]const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
[]const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
[]const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
};
const sigma = [10][16]u8{
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
[]const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
[]const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
[]const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
[]const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
[]const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
[]const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
[]const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
[]const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
};
h: [8]u32,
t: u64,
// Streaming cache
buf: [64]u8,
buf_len: u8,
h: [8]u32,
t: u64,
// Streaming cache
buf: [64]u8,
buf_len: u8,
pub fn init() Self {
debug.assert(8 <= out_len and out_len <= 512);
pub fn init() Self {
debug.assert(8 <= out_len and out_len <= 512);
var s: Self = undefined;
s.reset();
return s;
}
var s: Self = undefined;
s.reset();
return s;
}
pub fn reset(d: &Self) void {
mem.copy(u32, d.h[0..], iv[0..]);
pub fn reset(d: &Self) void {
mem.copy(u32, d.h[0..], iv[0..]);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
d.t = 0;
d.buf_len = 0;
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
pub fn update(d: &Self, b: []const u8) void {
var off: usize = 0;
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
off += 64 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 64;
d.round(d.buf[0..], false);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
d.t = 0;
d.buf_len = 0;
}
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.t += 64;
d.round(b[off..off + 64], false);
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
}
pub fn update(d: &Self, b: []const u8) void {
var off: usize = 0;
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= out_len / 8);
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
off += 64 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 64;
d.round(d.buf[0..], false);
d.buf_len = 0;
}
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.t += 64;
d.round(b[off..off + 64], false);
}
const rr = d.h[0 .. out_len / 32];
for (rr) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
}
}
fn round(d: &Self, b: []const u8, last: bool) void {
debug.assert(b.len == 64);
var m: [16]u32 = undefined;
var v: [16]u32 = undefined;
for (m) |*r, i| {
*r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
}
var k: usize = 0;
while (k < 8) : (k += 1) {
v[k] = d.h[k];
v[k+8] = iv[k];
}
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= out_len / 8);
v[12] ^= @truncate(u32, d.t);
v[13] ^= u32(d.t >> 32);
if (last) v[14] = ~v[14];
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
const rounds = comptime []RoundParam {
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
};
const rr = d.h[0..out_len / 32];
comptime var j: usize = 0;
inline while (j < 10) : (j += 1) {
inline for (rounds) |r| {
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
for (rr) |s, j| {
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Little);
}
}
for (d.h) |*r, i| {
*r ^= v[i] ^ v[i + 8];
fn round(d: &Self, b: []const u8, last: bool) void {
debug.assert(b.len == 64);
var m: [16]u32 = undefined;
var v: [16]u32 = undefined;
for (m) |*r, i| {
r.* = mem.readIntLE(u32, b[4 * i..4 * i + 4]);
}
var k: usize = 0;
while (k < 8) : (k += 1) {
v[k] = d.h[k];
v[k + 8] = iv[k];
}
v[12] ^= @truncate(u32, d.t);
v[13] ^= u32(d.t >> 32);
if (last) v[14] = ~v[14];
const rounds = comptime []RoundParam{
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
};
comptime var j: usize = 0;
inline while (j < 10) : (j += 1) {
inline for (rounds) |r| {
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
}
}
for (d.h) |*r, i| {
r.* ^= v[i] ^ v[i + 8];
}
}
}
};}
};
}
test "blake2s224 single" {
const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
@ -230,7 +250,7 @@ test "blake2s256 streaming" {
}
test "blake2s256 aligned final" {
var block = []u8 {0} ** Blake2s256.block_size;
var block = []u8{0} ** Blake2s256.block_size;
var out: [Blake2s256.digest_size]u8 = undefined;
var h = Blake2s256.init();
@ -238,154 +258,363 @@ test "blake2s256 aligned final" {
h.final(out[0..]);
}
/////////////////////
// Blake2b
pub const Blake2b384 = Blake2b(384);
pub const Blake2b512 = Blake2b(512);
fn Blake2b(comptime out_len: usize) type { return struct {
const Self = this;
const block_size = 128;
const digest_size = out_len / 8;
fn Blake2b(comptime out_len: usize) type {
return struct {
const Self = this;
const block_size = 128;
const digest_size = out_len / 8;
const iv = [8]u64 {
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
};
const iv = [8]u64{
0x6a09e667f3bcc908,
0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1,
0x510e527fade682d1,
0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,
0x5be0cd19137e2179,
};
const sigma = [12][16]u8 {
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
[]const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
[]const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
[]const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
[]const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
[]const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
[]const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
[]const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
[]const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
};
const sigma = [12][16]u8{
[]const u8{
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
},
[]const u8{
14,
10,
4,
8,
9,
15,
13,
6,
1,
12,
0,
2,
11,
7,
5,
3,
},
[]const u8{
11,
8,
12,
0,
5,
2,
15,
13,
10,
14,
3,
6,
7,
1,
9,
4,
},
[]const u8{
7,
9,
3,
1,
13,
12,
11,
14,
2,
6,
5,
10,
4,
0,
15,
8,
},
[]const u8{
9,
0,
5,
7,
2,
4,
10,
15,
14,
1,
11,
12,
6,
8,
3,
13,
},
[]const u8{
2,
12,
6,
10,
0,
11,
8,
3,
4,
13,
7,
5,
15,
14,
1,
9,
},
[]const u8{
12,
5,
1,
15,
14,
13,
4,
10,
0,
7,
6,
3,
9,
2,
8,
11,
},
[]const u8{
13,
11,
7,
14,
12,
1,
3,
9,
5,
0,
15,
4,
8,
6,
2,
10,
},
[]const u8{
6,
15,
14,
9,
11,
3,
0,
8,
12,
2,
13,
7,
1,
4,
10,
5,
},
[]const u8{
10,
2,
8,
4,
7,
6,
1,
5,
15,
11,
9,
14,
3,
12,
13,
0,
},
[]const u8{
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
},
[]const u8{
14,
10,
4,
8,
9,
15,
13,
6,
1,
12,
0,
2,
11,
7,
5,
3,
},
};
h: [8]u64,
t: u128,
// Streaming cache
buf: [128]u8,
buf_len: u8,
h: [8]u64,
t: u128,
// Streaming cache
buf: [128]u8,
buf_len: u8,
pub fn init() Self {
debug.assert(8 <= out_len and out_len <= 512);
pub fn init() Self {
debug.assert(8 <= out_len and out_len <= 512);
var s: Self = undefined;
s.reset();
return s;
}
var s: Self = undefined;
s.reset();
return s;
}
pub fn reset(d: &Self) void {
mem.copy(u64, d.h[0..], iv[0..]);
pub fn reset(d: &Self) void {
mem.copy(u64, d.h[0..], iv[0..]);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ (out_len >> 3);
d.t = 0;
d.buf_len = 0;
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
pub fn update(d: &Self, b: []const u8) void {
var off: usize = 0;
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
off += 128 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 128;
d.round(d.buf[0..], false);
// No key plus default parameters
d.h[0] ^= 0x01010000 ^ (out_len >> 3);
d.t = 0;
d.buf_len = 0;
}
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
d.t += 128;
d.round(b[off..off + 128], false);
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
}
pub fn update(d: &Self, b: []const u8) void {
var off: usize = 0;
pub fn final(d: &Self, out: []u8) void {
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
// Partial buffer exists from previous update. Copy into buffer then hash.
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
off += 128 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.t += 128;
d.round(d.buf[0..], false);
d.buf_len = 0;
}
const rr = d.h[0 .. out_len / 64];
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
d.t += 128;
d.round(b[off..off + 128], false);
}
for (rr) |s, j| {
mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
}
}
fn round(d: &Self, b: []const u8, last: bool) void {
debug.assert(b.len == 128);
var m: [16]u64 = undefined;
var v: [16]u64 = undefined;
for (m) |*r, i| {
*r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
}
var k: usize = 0;
while (k < 8) : (k += 1) {
v[k] = d.h[k];
v[k+8] = iv[k];
}
pub fn final(d: &Self, out: []u8) void {
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
v[12] ^= @truncate(u64, d.t);
v[13] ^= u64(d.t >> 64);
if (last) v[14] = ~v[14];
const rr = d.h[0..out_len / 64];
const rounds = comptime []RoundParam {
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
};
comptime var j: usize = 0;
inline while (j < 12) : (j += 1) {
inline for (rounds) |r| {
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
for (rr) |s, j| {
mem.writeInt(out[8 * j..8 * j + 8], s, builtin.Endian.Little);
}
}
for (d.h) |*r, i| {
*r ^= v[i] ^ v[i + 8];
fn round(d: &Self, b: []const u8, last: bool) void {
debug.assert(b.len == 128);
var m: [16]u64 = undefined;
var v: [16]u64 = undefined;
for (m) |*r, i| {
r.* = mem.readIntLE(u64, b[8 * i..8 * i + 8]);
}
var k: usize = 0;
while (k < 8) : (k += 1) {
v[k] = d.h[k];
v[k + 8] = iv[k];
}
v[12] ^= @truncate(u64, d.t);
v[13] ^= u64(d.t >> 64);
if (last) v[14] = ~v[14];
const rounds = comptime []RoundParam{
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
};
comptime var j: usize = 0;
inline while (j < 12) : (j += 1) {
inline for (rounds) |r| {
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
v[r.c] = v[r.c] +% v[r.d];
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
}
}
for (d.h) |*r, i| {
r.* ^= v[i] ^ v[i + 8];
}
}
}
};}
};
}
test "blake2b384 single" {
const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
@ -458,7 +687,7 @@ test "blake2b512 streaming" {
}
test "blake2b512 aligned final" {
var block = []u8 {0} ** Blake2b512.block_size;
var block = []u8{0} ** Blake2b512.block_size;
var out: [Blake2b512.digest_size]u8 = undefined;
var h = Blake2b512.init();

View File

@ -29,12 +29,12 @@ pub fn Hmac(comptime H: type) type {
var o_key_pad: [H.block_size]u8 = undefined;
for (o_key_pad) |*b, i| {
*b = scratch[i] ^ 0x5c;
b.* = scratch[i] ^ 0x5c;
}
var i_key_pad: [H.block_size]u8 = undefined;
for (i_key_pad) |*b, i| {
*b = scratch[i] ^ 0x36;
b.* = scratch[i] ^ 0x36;
}
// HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation

View File

@ -10,148 +10,228 @@ pub const Sha3_256 = Keccak(256, 0x06);
pub const Sha3_384 = Keccak(384, 0x06);
pub const Sha3_512 = Keccak(512, 0x06);
fn Keccak(comptime bits: usize, comptime delim: u8) type { return struct {
const Self = this;
const block_size = 200;
const digest_size = bits / 8;
fn Keccak(comptime bits: usize, comptime delim: u8) type {
return struct {
const Self = this;
const block_size = 200;
const digest_size = bits / 8;
s: [200]u8,
offset: usize,
rate: usize,
s: [200]u8,
offset: usize,
rate: usize,
pub fn init() Self {
var d: Self = undefined;
d.reset();
return d;
}
pub fn init() Self {
var d: Self = undefined;
d.reset();
return d;
}
pub fn reset(d: &Self) void {
mem.set(u8, d.s[0..], 0);
d.offset = 0;
d.rate = 200 - (bits / 4);
}
pub fn reset(d: &Self) void {
mem.set(u8, d.s[0..], 0);
d.offset = 0;
d.rate = 200 - (bits / 4);
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
pub fn hash(b: []const u8, out: []u8) void {
var d = Self.init();
d.update(b);
d.final(out);
}
pub fn update(d: &Self, b: []const u8) void {
var ip: usize = 0;
var len = b.len;
var rate = d.rate - d.offset;
var offset = d.offset;
pub fn update(d: &Self, b: []const u8) void {
var ip: usize = 0;
var len = b.len;
var rate = d.rate - d.offset;
var offset = d.offset;
// absorb
while (len >= rate) {
for (d.s[offset .. offset + rate]) |*r, i|
*r ^= b[ip..][i];
// absorb
while (len >= rate) {
for (d.s[offset..offset + rate]) |*r, i|
r.* ^= b[ip..][i];
keccak_f(1600, d.s[0..]);
ip += rate;
len -= rate;
rate = d.rate;
offset = 0;
}
for (d.s[offset..offset + len]) |*r, i|
r.* ^= b[ip..][i];
d.offset = offset + len;
}
pub fn final(d: &Self, out: []u8) void {
// padding
d.s[d.offset] ^= delim;
d.s[d.rate - 1] ^= 0x80;
keccak_f(1600, d.s[0..]);
ip += rate;
len -= rate;
rate = d.rate;
offset = 0;
// squeeze
var op: usize = 0;
var len: usize = bits / 8;
while (len >= d.rate) {
mem.copy(u8, out[op..], d.s[0..d.rate]);
keccak_f(1600, d.s[0..]);
op += d.rate;
len -= d.rate;
}
mem.copy(u8, out[op..], d.s[0..len]);
}
};
}
for (d.s[offset .. offset + len]) |*r, i|
*r ^= b[ip..][i];
d.offset = offset + len;
}
pub fn final(d: &Self, out: []u8) void {
// padding
d.s[d.offset] ^= delim;
d.s[d.rate - 1] ^= 0x80;
keccak_f(1600, d.s[0..]);
// squeeze
var op: usize = 0;
var len: usize = bits / 8;
while (len >= d.rate) {
mem.copy(u8, out[op..], d.s[0..d.rate]);
keccak_f(1600, d.s[0..]);
op += d.rate;
len -= d.rate;
}
mem.copy(u8, out[op..], d.s[0..len]);
}
};}
const RC = []const u64 {
0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
const RC = []const u64{
0x0000000000000001,
0x0000000000008082,
0x800000000000808a,
0x8000000080008000,
0x000000000000808b,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008a,
0x0000000000000088,
0x0000000080008009,
0x000000008000000a,
0x000000008000808b,
0x800000000000008b,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800a,
0x800000008000000a,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008,
};
const ROTC = []const usize {
1, 3, 6, 10, 15, 21, 28, 36,
45, 55, 2, 14, 27, 41, 56, 8,
25, 43, 62, 18, 39, 61, 20, 44
const ROTC = []const usize{
1,
3,
6,
10,
15,
21,
28,
36,
45,
55,
2,
14,
27,
41,
56,
8,
25,
43,
62,
18,
39,
61,
20,
44,
};
const PIL = []const usize {
10, 7, 11, 17, 18, 3, 5, 16,
8, 21, 24, 4, 15, 23, 19, 13,
12, 2, 20, 14, 22, 9, 6, 1
const PIL = []const usize{
10,
7,
11,
17,
18,
3,
5,
16,
8,
21,
24,
4,
15,
23,
19,
13,
12,
2,
20,
14,
22,
9,
6,
1,
};
const M5 = []const usize {
0, 1, 2, 3, 4, 0, 1, 2, 3, 4
const M5 = []const usize{
0,
1,
2,
3,
4,
0,
1,
2,
3,
4,
};
fn keccak_f(comptime F: usize, d: []u8) void {
debug.assert(d.len == F / 8);
const B = F / 25;
const no_rounds = comptime x: { break :x 12 + 2 * math.log2(B); };
const no_rounds = comptime x: {
break :x 12 + 2 * math.log2(B);
};
var s = []const u64 {0} ** 25;
var t = []const u64 {0} ** 1;
var c = []const u64 {0} ** 5;
var s = []const u64{0} ** 25;
var t = []const u64{0} ** 1;
var c = []const u64{0} ** 5;
for (s) |*r, i| {
*r = mem.readIntLE(u64, d[8*i .. 8*i + 8]);
r.* = mem.readIntLE(u64, d[8 * i..8 * i + 8]);
}
comptime var x: usize = 0;
comptime var y: usize = 0;
for (RC[0..no_rounds]) |round| {
// theta
x = 0; inline while (x < 5) : (x += 1) {
c[x] = s[x] ^ s[x+5] ^ s[x+10] ^ s[x+15] ^ s[x+20];
x = 0;
inline while (x < 5) : (x += 1) {
c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
}
x = 0; inline while (x < 5) : (x += 1) {
t[0] = c[M5[x+4]] ^ math.rotl(u64, c[M5[x+1]], usize(1));
y = 0; inline while (y < 5) : (y += 1) {
s[x + y*5] ^= t[0];
x = 0;
inline while (x < 5) : (x += 1) {
t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], usize(1));
y = 0;
inline while (y < 5) : (y += 1) {
s[x + y * 5] ^= t[0];
}
}
// rho+pi
t[0] = s[1];
x = 0; inline while (x < 24) : (x += 1) {
x = 0;
inline while (x < 24) : (x += 1) {
c[0] = s[PIL[x]];
s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
t[0] = c[0];
}
// chi
y = 0; inline while (y < 5) : (y += 1) {
x = 0; inline while (x < 5) : (x += 1) {
c[x] = s[x + y*5];
y = 0;
inline while (y < 5) : (y += 1) {
x = 0;
inline while (x < 5) : (x += 1) {
c[x] = s[x + y * 5];
}
x = 0; inline while (x < 5) : (x += 1) {
s[x + y*5] = c[x] ^ (~c[M5[x+1]] & c[M5[x+2]]);
x = 0;
inline while (x < 5) : (x += 1) {
s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
}
}
@ -160,11 +240,10 @@ fn keccak_f(comptime F: usize, d: []u8) void {
}
for (s) |r, i| {
mem.writeInt(d[8*i .. 8*i + 8], r, builtin.Endian.Little);
mem.writeInt(d[8 * i..8 * i + 8], r, builtin.Endian.Little);
}
}
test "sha3-224 single" {
htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
@ -192,7 +271,7 @@ test "sha3-224 streaming" {
}
test "sha3-256 single" {
htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" , "");
htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "");
htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc");
htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
@ -218,7 +297,7 @@ test "sha3-256 streaming" {
}
test "sha3-256 aligned final" {
var block = []u8 {0} ** Sha3_256.block_size;
var block = []u8{0} ** Sha3_256.block_size;
var out: [Sha3_256.digest_size]u8 = undefined;
var h = Sha3_256.init();
@ -228,7 +307,7 @@ test "sha3-256 aligned final" {
test "sha3-384 single" {
const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
htest.assertEqualHash(Sha3_384, h1 , "");
htest.assertEqualHash(Sha3_384, h1, "");
const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
htest.assertEqualHash(Sha3_384, h2, "abc");
const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7";
@ -259,7 +338,7 @@ test "sha3-384 streaming" {
test "sha3-512 single" {
const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
htest.assertEqualHash(Sha3_512, h1 , "");
htest.assertEqualHash(Sha3_512, h1, "");
const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
htest.assertEqualHash(Sha3_512, h2, "abc");
const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185";
@ -289,7 +368,7 @@ test "sha3-512 streaming" {
}
test "sha3-512 aligned final" {
var block = []u8 {0} ** Sha3_512.block_size;
var block = []u8{0} ** Sha3_512.block_size;
var out: [Sha3_512.digest_size]u8 = undefined;
var h = Sha3_512.init();

View File

@ -14,9 +14,8 @@ pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, inpu
pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
var expected_bytes: [expected.len / 2]u8 = undefined;
for (expected_bytes) |*r, i| {
*r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
}
debug.assert(mem.eql(u8, expected_bytes, input));
}

View File

@ -104,9 +104,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
var panicking: u8 = 0; // TODO make this a bool
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,
comptime format: []const u8, args: ...) noreturn
{
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
@setCold(true);
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
@ -132,9 +130,7 @@ const WHITE = "\x1b[37;1m";
const DIM = "\x1b[2m";
const RESET = "\x1b[0m";
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
debug_info: &ElfStackTrace, tty_color: bool) !void
{
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool) !void {
var frame_index: usize = undefined;
var frames_left: usize = undefined;
if (stack_trace.index < stack_trace.instruction_addresses.len) {
@ -154,9 +150,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
}
}
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
{
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void {
const AddressState = union(enum) {
NotLookingForStartAddress,
LookingForStartAddress: usize,
@ -166,14 +160,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
// else AddressState.NotLookingForStartAddress;
var addr_state: AddressState = undefined;
if (start_addr) |addr| {
addr_state = AddressState { .LookingForStartAddress = addr };
addr_state = AddressState{ .LookingForStartAddress = addr };
} else {
addr_state = AddressState.NotLookingForStartAddress;
}
var fp = @ptrToInt(@frameAddress());
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
while (fp != 0) : (fp = @intToPtr(&const usize, fp).*) {
const return_address = @intToPtr(&const usize, fp + @sizeOf(usize)).*;
switch (addr_state) {
AddressState.NotLookingForStartAddress => {},
@ -200,32 +194,32 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
// in practice because the compiler dumps everything in a single
// object file. Future improvement: use external dSYM data when
// available.
const unknown = macho.Symbol { .name = "???", .address = address };
const unknown = macho.Symbol{
.name = "???",
.address = address,
};
const symbol = debug_info.symbol_table.search(address) ?? &unknown;
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++
DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n",
symbol.name, address);
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
},
else => {
const compile_unit = findCompileUnit(debug_info, address) catch {
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
address);
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", address);
return;
};
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
defer line_info.deinit();
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
line_info.file_name, line_info.line, line_info.column,
address, compile_unit_name);
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", line_info.file_name, line_info.line, line_info.column, address, compile_unit_name);
if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
if (line_info.column == 0) {
try out_stream.write("\n");
} else {
{var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
try out_stream.writeByte(' ');
}}
{
var col_i: usize = 1;
while (col_i < line_info.column) : (col_i += 1) {
try out_stream.writeByte(' ');
}
}
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
}
} else |err| switch (err) {
@ -233,7 +227,8 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
else => return err,
}
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
error.MissingDebugInfo,
error.InvalidDebugInfo => {
try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
},
else => return err,
@ -247,7 +242,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
builtin.ObjectFormat.elf => {
const st = try allocator.create(ElfStackTrace);
errdefer allocator.destroy(st);
*st = ElfStackTrace {
st.* = ElfStackTrace{
.self_exe_file = undefined,
.elf = undefined,
.debug_info = undefined,
@ -279,9 +274,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
const st = try allocator.create(ElfStackTrace);
errdefer allocator.destroy(st);
*st = ElfStackTrace {
.symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)),
};
st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
return st;
},
@ -325,8 +318,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con
}
}
if (amt_read < buf.len)
return error.EndOfFile;
if (amt_read < buf.len) return error.EndOfFile;
}
}
@ -418,10 +410,8 @@ const Constant = struct {
signed: bool,
fn asUnsignedLe(self: &const Constant) !u64 {
if (self.payload.len > @sizeOf(u64))
return error.InvalidDebugInfo;
if (self.signed)
return error.InvalidDebugInfo;
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
if (self.signed) return error.InvalidDebugInfo;
return mem.readInt(self.payload, u64, builtin.Endian.Little);
}
};
@ -438,15 +428,14 @@ const Die = struct {
fn getAttr(self: &const Die, id: u64) ?&const FormValue {
for (self.attrs.toSliceConst()) |*attr| {
if (attr.id == id)
return &attr.value;
if (attr.id == id) return &attr.value;
}
return null;
}
fn getAttrAddr(self: &const Die, id: u64) !u64 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
return switch (form_value.*) {
FormValue.Address => |value| value,
else => error.InvalidDebugInfo,
};
@ -454,7 +443,7 @@ const Die = struct {
fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
return switch (form_value.*) {
FormValue.Const => |value| value.asUnsignedLe(),
FormValue.SecOffset => |value| value,
else => error.InvalidDebugInfo,
@ -463,7 +452,7 @@ const Die = struct {
fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
return switch (form_value.*) {
FormValue.Const => |value| value.asUnsignedLe(),
else => error.InvalidDebugInfo,
};
@ -471,7 +460,7 @@ const Die = struct {
fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
return switch (form_value.*) {
FormValue.String => |value| value,
FormValue.StrPtr => |offset| getString(st, offset),
else => error.InvalidDebugInfo,
@ -518,10 +507,8 @@ const LineNumberProgram = struct {
prev_basic_block: bool,
prev_end_sequence: bool,
pub fn init(is_stmt: bool, include_dirs: []const []const u8,
file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram
{
return LineNumberProgram {
pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram {
return LineNumberProgram{
.address = 0,
.file = 1,
.line = 1,
@ -548,14 +535,16 @@ const LineNumberProgram = struct {
return error.MissingDebugInfo;
} else if (self.prev_file - 1 >= self.file_entries.len) {
return error.InvalidDebugInfo;
} else &self.file_entries.items[self.prev_file - 1];
} else
&self.file_entries.items[self.prev_file - 1];
const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
return error.InvalidDebugInfo;
} else self.include_dirs[file_entry.dir_index];
} else
self.include_dirs[file_entry.dir_index];
const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
errdefer self.file_entries.allocator.free(file_name);
return LineInfo {
return LineInfo{
.line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
.column = self.prev_column,
.file_name = file_name,
@ -578,8 +567,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
var buf = ArrayList(u8).init(allocator);
while (true) {
const byte = try in_stream.readByte();
if (byte == 0)
break;
if (byte == 0) break;
try buf.append(byte);
}
return buf.toSlice();
@ -600,7 +588,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
const buf = try readAllocBytes(allocator, in_stream, size);
return FormValue { .Block = buf };
return FormValue{ .Block = buf };
}
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
@ -609,26 +597,23 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !
}
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
return FormValue { .Const = Constant {
return FormValue{ .Const = Constant{
.signed = signed,
.payload = try readAllocBytes(allocator, in_stream, size),
}};
} };
}
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
return if (is_64) try in_stream.readIntLe(u64)
else u64(try in_stream.readIntLe(u32)) ;
return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
}
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))
else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
else unreachable;
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
}
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
const buf = try readAllocBytes(allocator, in_stream, size);
return FormValue { .Ref = buf };
return FormValue{ .Ref = buf };
}
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
@ -646,11 +631,9 @@ const ParseFormValueError = error {
OutOfMemory,
};
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
ParseFormValueError!FormValue
{
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
return switch (form_id) {
DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
@ -662,7 +645,8 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
DW.FORM_udata, DW.FORM_sdata => {
DW.FORM_udata,
DW.FORM_sdata => {
const block_len = try readULeb128(in_stream);
const signed = form_id == DW.FORM_sdata;
return parseFormValueConstant(allocator, in_stream, signed, block_len);
@ -670,11 +654,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_exprloc => {
const size = try readULeb128(in_stream);
const buf = try readAllocBytes(allocator, in_stream, size);
return FormValue { .ExprLoc = buf };
return FormValue{ .ExprLoc = buf };
},
DW.FORM_flag => FormValue { .Flag = (try in_stream.readByte()) != 0 },
DW.FORM_flag_present => FormValue { .Flag = true },
DW.FORM_sec_offset => FormValue { .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
DW.FORM_flag_present => FormValue{ .Flag = true },
DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
@ -685,11 +669,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
return parseFormValueRefLen(allocator, in_stream, ref_len);
},
DW.FORM_ref_addr => FormValue { .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref_sig8 => FormValue { .RefSig8 = try in_stream.readIntLe(u64) },
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
DW.FORM_string => FormValue { .String = try readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue { .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_indirect => {
const child_form_id = try readULeb128(in_stream);
return parseFormValue(allocator, in_stream, child_form_id, is_64);
@ -705,9 +689,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
var result = AbbrevTable.init(st.allocator());
while (true) {
const abbrev_code = try readULeb128(in_stream);
if (abbrev_code == 0)
return result;
try result.append(AbbrevTableEntry {
if (abbrev_code == 0) return result;
try result.append(AbbrevTableEntry{
.abbrev_code = abbrev_code,
.tag_id = try readULeb128(in_stream),
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
@ -718,9 +701,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
while (true) {
const attr_id = try readULeb128(in_stream);
const form_id = try readULeb128(in_stream);
if (attr_id == 0 and form_id == 0)
break;
try attrs.append(AbbrevAttr {
if (attr_id == 0 and form_id == 0) break;
try attrs.append(AbbrevAttr{
.attr_id = attr_id,
.form_id = form_id,
});
@ -737,7 +719,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
}
}
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
try st.abbrev_table_list.append(AbbrevTableHeader {
try st.abbrev_table_list.append(AbbrevTableHeader{
.offset = abbrev_offset,
.table = try parseAbbrevTable(st),
});
@ -746,8 +728,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
for (abbrev_table.toSliceConst()) |*table_entry| {
if (table_entry.abbrev_code == abbrev_code)
return table_entry;
if (table_entry.abbrev_code == abbrev_code) return table_entry;
}
return null;
}
@ -759,14 +740,14 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !
const abbrev_code = try readULeb128(in_stream);
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
var result = Die {
var result = Die{
.tag_id = table_entry.tag_id,
.has_children = table_entry.has_children,
.attrs = ArrayList(Die.Attr).init(st.allocator()),
};
try result.attrs.resize(table_entry.attrs.len);
for (table_entry.attrs.toSliceConst()) |attr, i| {
result.attrs.items[i] = Die.Attr {
result.attrs.items[i] = Die.Attr{
.id = attr.attr_id,
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
};
@ -790,8 +771,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
var is_64: bool = undefined;
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
if (unit_length == 0)
return error.MissingDebugInfo;
if (unit_length == 0) return error.MissingDebugInfo;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
if (compile_unit.index != this_index) {
@ -803,8 +783,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64)
else try in_stream.readInt(st.elf.endian, u32);
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
const prog_start_offset = (try in_file.getPos()) + prologue_length;
const minimum_instruction_length = try in_stream.readByte();
@ -819,38 +798,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
const line_base = try in_stream.readByteSigned();
const line_range = try in_stream.readByte();
if (line_range == 0)
return error.InvalidDebugInfo;
if (line_range == 0) return error.InvalidDebugInfo;
const opcode_base = try in_stream.readByte();
const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
{var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
standard_opcode_lengths[i] = try in_stream.readByte();
}}
{
var i: usize = 0;
while (i < opcode_base - 1) : (i += 1) {
standard_opcode_lengths[i] = try in_stream.readByte();
}
}
var include_directories = ArrayList([]u8).init(st.allocator());
try include_directories.append(compile_unit_cwd);
while (true) {
const dir = try st.readString();
if (dir.len == 0)
break;
if (dir.len == 0) break;
try include_directories.append(dir);
}
var file_entries = ArrayList(FileEntry).init(st.allocator());
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
&file_entries, target_address);
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
while (true) {
const file_name = try st.readString();
if (file_name.len == 0)
break;
if (file_name.len == 0) break;
const dir_index = try readULeb128(in_stream);
const mtime = try readULeb128(in_stream);
const len_bytes = try readULeb128(in_stream);
try file_entries.append(FileEntry {
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
.mtime = mtime,
@ -866,8 +844,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
if (opcode == DW.LNS_extended_op) {
const op_size = try readULeb128(in_stream);
if (op_size < 1)
return error.InvalidDebugInfo;
if (op_size < 1) return error.InvalidDebugInfo;
sub_op = try in_stream.readByte();
switch (sub_op) {
DW.LNE_end_sequence => {
@ -884,7 +861,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
const dir_index = try readULeb128(in_stream);
const mtime = try readULeb128(in_stream);
const len_bytes = try readULeb128(in_stream);
try file_entries.append(FileEntry {
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
.mtime = mtime,
@ -941,11 +918,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
const arg = try in_stream.readInt(st.elf.endian, u16);
prog.address += arg;
},
DW.LNS_set_prologue_end => {
},
DW.LNS_set_prologue_end => {},
else => {
if (opcode - 1 >= standard_opcode_lengths.len)
return error.InvalidDebugInfo;
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
const len_bytes = standard_opcode_lengths[opcode - 1];
try in_file.seekForward(len_bytes);
},
@ -972,16 +947,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
var is_64: bool = undefined;
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
if (unit_length == 0)
return;
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
const version = try in_stream.readInt(st.elf.endian, u16);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
const debug_abbrev_offset =
if (is_64) try in_stream.readInt(st.elf.endian, u64)
else try in_stream.readInt(st.elf.endian, u32);
const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
const address_size = try in_stream.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
@ -992,15 +964,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
try st.self_exe_file.seekTo(compile_unit_pos);
const compile_unit_die = try st.allocator().create(Die);
*compile_unit_die = try parseDie(st, abbrev_table, is_64);
compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
if (compile_unit_die.tag_id != DW.TAG_compile_unit)
return error.InvalidDebugInfo;
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
const pc_range = x: {
if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
const pc_end = switch (*high_pc_value) {
const pc_end = switch (high_pc_value.*) {
FormValue.Address => |value| value,
FormValue.Const => |value| b: {
const offset = try value.asUnsignedLe();
@ -1008,7 +979,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
},
else => return error.InvalidDebugInfo,
};
break :x PcRange {
break :x PcRange{
.start = low_pc,
.end = pc_end,
};
@ -1016,13 +987,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
break :x null;
}
} else |err| {
if (err != error.MissingDebugInfo)
return err;
if (err != error.MissingDebugInfo) return err;
break :x null;
}
};
try st.compile_unit_list.append(CompileUnit {
try st.compile_unit_list.append(CompileUnit{
.version = version,
.is_64 = is_64,
.pc_range = pc_range,
@ -1040,8 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
const in_stream = &in_file_stream.stream;
for (st.compile_unit_list.toSlice()) |*compile_unit| {
if (compile_unit.pc_range) |range| {
if (target_address >= range.start and target_address < range.end)
return compile_unit;
if (target_address >= range.start and target_address < range.end) return compile_unit;
}
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
var base_address: usize = 0;
@ -1063,8 +1032,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
}
}
} else |err| {
if (err != error.MissingDebugInfo)
return err;
if (err != error.MissingDebugInfo) return err;
continue;
}
}
@ -1073,8 +1041,8 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
const first_32_bits = try in_stream.readIntLe(u32);
*is_64 = (first_32_bits == 0xffffffff);
if (*is_64) {
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
return in_stream.readIntLe(u64);
} else {
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
@ -1091,13 +1059,11 @@ fn readULeb128(in_stream: var) !u64 {
var operand: u64 = undefined;
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
return error.InvalidDebugInfo;
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
result |= operand;
if ((byte & 0b10000000) == 0)
return result;
if ((byte & 0b10000000) == 0) return result;
shift += 7;
}
@ -1112,15 +1078,13 @@ fn readILeb128(in_stream: var) !i64 {
var operand: i64 = undefined;
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
return error.InvalidDebugInfo;
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
result |= operand;
shift += 7;
if ((byte & 0b10000000) == 0) {
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
result |= -(i64(1) << u6(shift));
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << u6(shift));
return result;
}
}
@ -1131,7 +1095,6 @@ pub const global_allocator = &global_fixed_allocator.allocator;
var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
var global_allocator_mem: [100 * 1024]u8 = undefined;
// TODO make thread safe
var debug_info_allocator: ?&mem.Allocator = null;
var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;

View File

@ -6,7 +6,7 @@ const mem = std.mem;
const posix = std.os.posix;
pub const TcpServer = struct {
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void,
loop: &Loop,
sockfd: i32,
@ -18,13 +18,11 @@ pub const TcpServer = struct {
const PromiseNode = std.LinkedList(promise).Node;
pub fn init(loop: &Loop) !TcpServer {
const sockfd = try std.os.posixSocket(posix.AF_INET,
posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
posix.PROTO_tcp);
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
errdefer std.os.close(sockfd);
// TODO can't initialize handler coroutine here because we need well defined copy elision
return TcpServer {
return TcpServer{
.loop = loop,
.sockfd = sockfd,
.accept_coro = null,
@ -34,9 +32,7 @@ pub const TcpServer = struct {
};
}
pub fn listen(self: &TcpServer, address: &const std.net.Address,
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
{
pub fn listen(self: &TcpServer, address: &const std.net.Address, handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void) !void {
self.handleRequestFn = handleRequestFn;
try std.os.posixBind(self.sockfd, &address.os_addr);
@ -48,7 +44,6 @@ pub const TcpServer = struct {
try self.loop.addFd(self.sockfd, ??self.accept_coro);
errdefer self.loop.removeFd(self.sockfd);
}
pub fn deinit(self: &TcpServer) void {
@ -60,9 +55,7 @@ pub const TcpServer = struct {
pub async fn handler(self: &TcpServer) void {
while (true) {
var accepted_addr: std.net.Address = undefined;
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
{
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
var socket = std.os.File.openHandle(accepted_fd);
_ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
error.OutOfMemory => {
@ -110,7 +103,7 @@ pub const Loop = struct {
fn init(allocator: &mem.Allocator) !Loop {
const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
return Loop {
return Loop{
.keep_running = true,
.allocator = allocator,
.epollfd = epollfd,
@ -118,11 +111,9 @@ pub const Loop = struct {
}
pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
var ev = std.os.linux.epoll_event {
.events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
.data = std.os.linux.epoll_data {
.ptr = @ptrToInt(prom),
},
var ev = std.os.linux.epoll_event{
.events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
.data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },
};
try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
}
@ -157,9 +148,9 @@ pub const Loop = struct {
};
pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
var address = _address.*; // TODO https://github.com/zig-lang/zig/issues/733
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
errdefer std.os.close(sockfd);
try std.os.posixConnectAsync(sockfd, &address.os_addr);
@ -179,11 +170,9 @@ test "listen on a port, send bytes, receive bytes" {
const Self = this;
async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
_socket: &const std.os.File) void
{
async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address, _socket: &const std.os.File) void {
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
var socket = _socket.*; // TODO https://github.com/zig-lang/zig/issues/733
defer socket.close();
const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
error.OutOfMemory => @panic("unable to handle connection: out of memory"),
@ -191,14 +180,14 @@ test "listen on a port, send bytes, receive bytes" {
(await next_handler) catch |err| {
std.debug.panic("unable to handle connection: {}\n", err);
};
suspend |p| { cancel p; }
suspend |p| {
cancel p;
}
}
async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
_socket: &const std.os.File) !void
{
const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
async fn errorableHandler(self: &Self, _addr: &const std.net.Address, _socket: &const std.os.File) !void {
const addr = _addr.*; // TODO https://github.com/zig-lang/zig/issues/733
var socket = _socket.*; // TODO https://github.com/zig-lang/zig/issues/733
var adapter = std.io.FileOutStream.init(&socket);
var stream = &adapter.stream;
@ -210,9 +199,7 @@ test "listen on a port, send bytes, receive bytes" {
const addr = std.net.Address.initIp4(ip4addr, 0);
var loop = try Loop.init(std.debug.global_allocator);
var server = MyServer {
.tcp_server = try TcpServer.init(&loop),
};
var server = MyServer{ .tcp_server = try TcpServer.init(&loop) };
defer server.tcp_server.deinit();
try server.tcp_server.listen(addr, MyServer.handler);

View File

@ -86,7 +86,7 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
const data = enum3_data[i];
const digits = buffer[1..data.str.len + 1];
mem.copy(u8, digits, data.str);
return FloatDecimal {
return FloatDecimal{
.digits = digits,
.exp = data.exp,
};
@ -105,7 +105,6 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
return errolFixed(val, buffer);
}
// normalize the midpoint
const e = math.frexp(val).exponent;
@ -137,11 +136,11 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
}
// compute boundaries
var high = HP {
var high = HP{
.val = mid.val,
.off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
};
var low = HP {
var low = HP{
.val = mid.val,
.off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
};
@ -171,15 +170,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
var buf_index: usize = 1;
while (true) {
var hdig = u8(math.floor(high.val));
if ((high.val == f64(hdig)) and (high.off < 0))
hdig -= 1;
if ((high.val == f64(hdig)) and (high.off < 0)) hdig -= 1;
var ldig = u8(math.floor(low.val));
if ((low.val == f64(ldig)) and (low.off < 0))
ldig -= 1;
if ((low.val == f64(ldig)) and (low.off < 0)) ldig -= 1;
if (ldig != hdig)
break;
if (ldig != hdig) break;
buffer[buf_index] = hdig + '0';
buf_index += 1;
@ -191,13 +187,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
const tmp = (high.val + low.val) / 2.0;
var mdig = u8(math.floor(tmp + 0.5));
if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0)
mdig -= 1;
if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
buffer[buf_index] = mdig + '0';
buf_index += 1;
return FloatDecimal {
return FloatDecimal{
.digits = buffer[1..buf_index],
.exp = exp,
};
@ -235,7 +230,7 @@ fn hpProd(in: &const HP, val: f64) HP {
const p = in.val * val;
const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
return HP {
return HP{
.val = p,
.off = in.off * val + e,
};
@ -246,8 +241,8 @@ fn hpProd(in: &const HP, val: f64) HP {
/// @hi: The high bits.
/// @lo: The low bits.
fn split(val: f64, hi: &f64, lo: &f64) void {
*hi = gethi(val);
*lo = val - *hi;
hi.* = gethi(val);
lo.* = val - hi.*;
}
fn gethi(in: f64) f64 {
@ -301,7 +296,6 @@ fn hpMul10(hp: &HP) void {
hpNormalize(hp);
}
/// Integer conversion algorithm, guaranteed correct, optimal, and best.
/// @val: The val.
/// @buf: The output buffer.
@ -343,8 +337,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
}
const m64 = @truncate(u64, @divTrunc(mid, x));
if (lf != hf)
mi += 19;
if (lf != hf) mi += 19;
var buf_index = u64toa(m64, buffer) - 1;
@ -354,7 +347,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
buf_index += 1;
}
return FloatDecimal {
return FloatDecimal{
.digits = buffer[0..buf_index],
.exp = i32(buf_index) + mi,
};
@ -396,25 +389,24 @@ fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
buffer[j] = u8(mdig + '0');
j += 1;
if(hdig != ldig or j > 50)
break;
if (hdig != ldig or j > 50) break;
}
if (mid > 0.5) {
buffer[j-1] += 1;
} else if ((mid == 0.5) and (buffer[j-1] & 0x1) != 0) {
buffer[j-1] += 1;
buffer[j - 1] += 1;
} else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
buffer[j - 1] += 1;
}
} else {
while (buffer[j-1] == '0') {
buffer[j-1] = 0;
while (buffer[j - 1] == '0') {
buffer[j - 1] = 0;
j -= 1;
}
}
buffer[j] = 0;
return FloatDecimal {
return FloatDecimal{
.digits = buffer[0..j],
.exp = exp,
};
@ -587,7 +579,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
buffer[buf_index] = c_digits_lut[d8 + 1];
buf_index += 1;
} else {
const a = u32(value / kTen16); // 1 to 1844
const a = u32(value / kTen16); // 1 to 1844
value %= kTen16;
if (a < 10) {
@ -686,7 +678,6 @@ fn fpeint(from: f64) u128 {
return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
}
/// Given two different integers with the same length in terms of the number
/// of decimal digits, index the digits from the right-most position starting
/// from zero, find the first index where the digits in the two integers
@ -713,7 +704,6 @@ fn mismatch10(a: u64, b: u64) i32 {
a_copy /= 10;
b_copy /= 10;
if (a_copy == b_copy)
return i;
if (a_copy == b_copy) return i;
}
}

View File

@ -11,9 +11,7 @@ const max_int_digits = 65;
/// Renders fmt string with args, calling output with slices of bytes.
/// If `output` returns an error, the error is returned from `format` and
/// `output` is not called again.
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
comptime fmt: []const u8, args: ...) Errors!void
{
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
const State = enum {
Start,
OpenBrace,
@ -270,7 +268,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
}
}
pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
const T = @typeOf(value);
switch (@typeId(T)) {
builtin.TypeId.Int => {
@ -305,7 +303,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
},
builtin.TypeId.Pointer => {
if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
return output(context, (*value)[0..]);
return output(context, (value.*)[0..]);
} else {
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
}
@ -319,13 +317,11 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
}
}
pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
return output(context, (&c)[0..1]);
}
pub fn formatBuf(buf: []const u8, width: usize,
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
{
pub fn formatBuf(buf: []const u8, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
try output(context, buf);
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
@ -338,7 +334,7 @@ pub fn formatBuf(buf: []const u8, width: usize,
// Print a float in scientific notation to the specified precision. Null uses full precision.
// It should be the case that every full precision, printed value can be re-parsed back to the
// same type unambiguously.
pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
var x = f64(value);
// Errol doesn't handle these special cases.
@ -387,7 +383,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
var printed: usize = 0;
if (float_decimal.digits.len > 1) {
const num_digits = math.min(float_decimal.digits.len, precision + 1);
try output(context, float_decimal.digits[1 .. num_digits]);
try output(context, float_decimal.digits[1..num_digits]);
printed += num_digits - 1;
}
@ -399,12 +395,9 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
try output(context, float_decimal.digits[0..1]);
try output(context, ".");
if (float_decimal.digits.len > 1) {
const num_digits = if (@typeOf(value) == f32)
math.min(usize(9), float_decimal.digits.len)
else
float_decimal.digits.len;
const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
try output(context, float_decimal.digits[1 .. num_digits]);
try output(context, float_decimal.digits[1..num_digits]);
} else {
try output(context, "0");
}
@ -430,7 +423,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
// By default floats are printed at full precision (no rounding).
pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
var x = f64(value);
// Errol doesn't handle these special cases.
@ -480,14 +473,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
try output(context, "0");
}
} else {
try output(context , "0");
try output(context, "0");
}
// {.0} special case doesn't want a trailing '.'
@ -519,10 +512,10 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
// Remaining fractional portion, zero-padding if insufficient.
debug.assert(precision >= printed);
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
try output(context, float_decimal.digits[num_digits_whole_no_pad..num_digits_whole_no_pad + precision - printed]);
return;
} else {
try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
printed += float_decimal.digits.len - num_digits_whole_no_pad;
while (printed < precision) : (printed += 1) {
@ -538,14 +531,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
try output(context, "0");
}
} else {
try output(context , "0");
try output(context, "0");
}
// Omit `.` if no fractional portion
@ -565,7 +558,7 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
}
}
try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
}
}
@ -609,9 +602,7 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
}
}
fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
{
fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
const uint = @IntType(false, @typeOf(value).bit_count);
if (value < 0) {
const minus_sign: u8 = '-';
@ -630,9 +621,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
}
}
fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
{
fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
// max_int_digits accounts for the minus sign. when printing an unsigned
// number we don't need to do that.
var buf: [max_int_digits - 1]u8 = undefined;
@ -644,8 +633,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
index -= 1;
buf[index] = digitToChar(u8(digit), uppercase);
a /= base;
if (a == 0)
break;
if (a == 0) break;
}
const digits_buf = buf[index..];
@ -657,8 +645,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
while (true) {
try output(context, (&zero_byte)[0..1]);
leftover_padding -= 1;
if (leftover_padding == 0)
break;
if (leftover_padding == 0) break;
}
mem.set(u8, buf[0..index], '0');
return output(context, buf);
@ -670,7 +657,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
}
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
var context = FormatIntBuf {
var context = FormatIntBuf{
.out_buf = out_buf,
.index = 0,
};
@ -687,10 +674,8 @@ fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
}
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
if (!T.is_signed)
return parseUnsigned(T, buf, radix);
if (buf.len == 0)
return T(0);
if (!T.is_signed) return parseUnsigned(T, buf, radix);
if (buf.len == 0) return T(0);
if (buf[0] == '-') {
return math.negate(try parseUnsigned(T, buf[1..], radix));
} else if (buf[0] == '+') {
@ -710,9 +695,10 @@ test "fmt.parseInt" {
assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
}
const ParseUnsignedError = error {
const ParseUnsignedError = error{
/// The result cannot fit in the type specified
Overflow,
/// The input had a byte that was not a digit
InvalidCharacter,
};
@ -737,8 +723,7 @@ pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
else => return error.InvalidCharacter,
};
if (value >= radix)
return error.InvalidCharacter;
if (value >= radix) return error.InvalidCharacter;
return value;
}
@ -762,20 +747,21 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
}
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
var context = BufPrintContext { .remaining = buf, };
var context = BufPrintContext{ .remaining = buf };
try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
return buf[0..buf.len - context.remaining.len];
}
pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
var size: usize = 0;
format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {
};
const buf = try allocator.alloc(u8, size);
return bufPrint(buf, fmt, args);
}
fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
*size += bytes.len;
size.* += bytes.len;
}
test "buf print int" {
@ -843,9 +829,7 @@ test "fmt.format" {
unused: u8,
};
var buf1: [32]u8 = undefined;
const value = Struct {
.unused = 42,
};
const value = Struct{ .unused = 42 };
const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
assert(mem.startsWith(u8, result, "pointer: Struct@"));
}
@ -1072,7 +1056,7 @@ fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void
pub fn trim(buf: []const u8) []const u8 {
var start: usize = 0;
while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }
while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
var end: usize = buf.len;
while (true) {
@ -1084,7 +1068,6 @@ pub fn trim(buf: []const u8) []const u8 {
}
}
break;
}
return buf[start..end];
}
@ -1099,7 +1082,10 @@ test "fmt.trim" {
pub fn isWhiteSpace(byte: u8) bool {
return switch (byte) {
' ', '\t', '\n', '\r' => true,
' ',
'\t',
'\n',
'\r' => true,
else => false,
};
}

View File

@ -9,9 +9,9 @@ const std = @import("../index.zig");
const debug = std.debug;
pub const Polynomial = struct {
const IEEE = 0xedb88320;
const IEEE = 0xedb88320;
const Castagnoli = 0x82f63b78;
const Koopman = 0xeb31d82e;
const Koopman = 0xeb31d82e;
};
// IEEE is by far the most common CRC and so is aliased by default.
@ -27,20 +27,22 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
for (tables[0]) |*e, i| {
var crc = u32(i);
var j: usize = 0; while (j < 8) : (j += 1) {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
crc = (crc >> 1) ^ poly;
} else {
crc = (crc >> 1);
}
}
*e = crc;
e.* = crc;
}
var i: usize = 0;
while (i < 256) : (i += 1) {
var crc = tables[0][i];
var j: usize = 1; while (j < 8) : (j += 1) {
var j: usize = 1;
while (j < 8) : (j += 1) {
const index = @truncate(u8, crc);
crc = tables[0][index] ^ (crc >> 8);
tables[j][i] = crc;
@ -53,22 +55,21 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
crc: u32,
pub fn init() Self {
return Self {
.crc = 0xffffffff,
};
return Self{ .crc = 0xffffffff };
}
pub fn update(self: &Self, input: []const u8) void {
var i: usize = 0;
while (i + 8 <= input.len) : (i += 8) {
const p = input[i..i+8];
const p = input[i..i + 8];
// Unrolling this way gives ~50Mb/s increase
self.crc ^= (u32(p[0]) << 0);
self.crc ^= (u32(p[1]) << 8);
self.crc ^= (u32(p[0]) << 0);
self.crc ^= (u32(p[1]) << 8);
self.crc ^= (u32(p[2]) << 16);
self.crc ^= (u32(p[3]) << 24);
self.crc =
lookup_tables[0][p[7]] ^
lookup_tables[1][p[6]] ^
@ -123,14 +124,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
for (table) |*e, i| {
var crc = u32(i * 16);
var j: usize = 0; while (j < 8) : (j += 1) {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
crc = (crc >> 1) ^ poly;
} else {
crc = (crc >> 1);
}
}
*e = crc;
e.* = crc;
}
break :block table;
@ -139,9 +141,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
crc: u32,
pub fn init() Self {
return Self {
.crc = 0xffffffff,
};
return Self{ .crc = 0xffffffff };
}
pub fn update(self: &Self, input: []const u8) void {

View File

@ -9,10 +9,7 @@ const builtin = @import("builtin");
const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;
const debug_u32 = if (want_modification_safety) u32 else void;
pub fn HashMap(comptime K: type, comptime V: type,
comptime hash: fn(key: K)u32,
comptime eql: fn(a: K, b: K)bool) type
{
pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn(key: K) u32, comptime eql: fn(a: K, b: K) bool) type {
return struct {
entries: []Entry,
size: usize,
@ -65,7 +62,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
};
pub fn init(allocator: &Allocator) Self {
return Self {
return Self{
.entries = []Entry{},
.allocator = allocator,
.size = 0,
@ -129,34 +126,36 @@ pub fn HashMap(comptime K: type, comptime V: type,
if (hm.entries.len == 0) return null;
hm.incrementModificationCount();
const start_index = hm.keyToIndex(key);
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
const index = (start_index + roll_over) % hm.entries.len;
var entry = &hm.entries[index];
{
var roll_over: usize = 0;
while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
const index = (start_index + roll_over) % hm.entries.len;
var entry = &hm.entries[index];
if (!entry.used)
return null;
if (!entry.used) return null;
if (!eql(entry.key, key)) continue;
if (!eql(entry.key, key)) continue;
while (roll_over < hm.entries.len) : (roll_over += 1) {
const next_index = (start_index + roll_over + 1) % hm.entries.len;
const next_entry = &hm.entries[next_index];
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
entry.used = false;
hm.size -= 1;
return entry;
while (roll_over < hm.entries.len) : (roll_over += 1) {
const next_index = (start_index + roll_over + 1) % hm.entries.len;
const next_entry = &hm.entries[next_index];
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
entry.used = false;
hm.size -= 1;
return entry;
}
entry.* = next_entry.*;
entry.distance_from_start_index -= 1;
entry = next_entry;
}
*entry = *next_entry;
entry.distance_from_start_index -= 1;
entry = next_entry;
unreachable; // shifting everything in the table
}
unreachable; // shifting everything in the table
}}
}
return null;
}
pub fn iterator(hm: &const Self) Iterator {
return Iterator {
return Iterator{
.hm = hm,
.count = 0,
.index = 0,
@ -182,21 +181,23 @@ pub fn HashMap(comptime K: type, comptime V: type,
/// Returns the value that was already there.
fn internalPut(hm: &Self, orig_key: K, orig_value: &const V) ?V {
var key = orig_key;
var value = *orig_value;
var value = orig_value.*;
const start_index = hm.keyToIndex(key);
var roll_over: usize = 0;
var distance_from_start_index: usize = 0;
while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {
while (roll_over < hm.entries.len) : ({
roll_over += 1;
distance_from_start_index += 1;
}) {
const index = (start_index + roll_over) % hm.entries.len;
const entry = &hm.entries[index];
if (entry.used and !eql(entry.key, key)) {
if (entry.distance_from_start_index < distance_from_start_index) {
// robin hood to the rescue
const tmp = *entry;
hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,
distance_from_start_index);
*entry = Entry {
const tmp = entry.*;
hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index, distance_from_start_index);
entry.* = Entry{
.used = true,
.distance_from_start_index = distance_from_start_index,
.key = key,
@ -219,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
}
hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
*entry = Entry {
entry.* = Entry{
.used = true,
.distance_from_start_index = distance_from_start_index,
.key = key,
@ -232,13 +233,16 @@ pub fn HashMap(comptime K: type, comptime V: type,
fn internalGet(hm: &const Self, key: K) ?&Entry {
const start_index = hm.keyToIndex(key);
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
const index = (start_index + roll_over) % hm.entries.len;
const entry = &hm.entries[index];
{
var roll_over: usize = 0;
while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
const index = (start_index + roll_over) % hm.entries.len;
const entry = &hm.entries[index];
if (!entry.used) return null;
if (eql(entry.key, key)) return entry;
}}
if (!entry.used) return null;
if (eql(entry.key, key)) return entry;
}
}
return null;
}
@ -282,11 +286,19 @@ test "iterator hash map" {
assert((reset_map.put(2, 22) catch unreachable) == null);
assert((reset_map.put(3, 33) catch unreachable) == null);
var keys = []i32 { 1, 2, 3 };
var values = []i32 { 11, 22, 33 };
var keys = []i32{
1,
2,
3,
};
var values = []i32{
11,
22,
33,
};
var it = reset_map.iterator();
var count : usize = 0;
var count: usize = 0;
while (it.next()) |next| {
assert(next.key == keys[count]);
assert(next.value == values[count]);
@ -305,7 +317,7 @@ test "iterator hash map" {
}
it.reset();
var entry = ?? it.next();
var entry = ??it.next();
assert(entry.key == keys[0]);
assert(entry.value == values[0]);
}

View File

@ -10,7 +10,7 @@ const c = std.c;
const Allocator = mem.Allocator;
pub const c_allocator = &c_allocator_state;
var c_allocator_state = Allocator {
var c_allocator_state = Allocator{
.allocFn = cAlloc,
.reallocFn = cRealloc,
.freeFn = cFree,
@ -18,10 +18,7 @@ var c_allocator_state = Allocator {
fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
assert(alignment <= @alignOf(c_longdouble));
return if (c.malloc(n)) |buf|
@ptrCast(&u8, buf)[0..n]
else
error.OutOfMemory;
return if (c.malloc(n)) |buf| @ptrCast(&u8, buf)[0..n] else error.OutOfMemory;
}
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
@ -48,8 +45,8 @@ pub const DirectAllocator = struct {
const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
pub fn init() DirectAllocator {
return DirectAllocator {
.allocator = Allocator {
return DirectAllocator{
.allocator = Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,
@ -71,39 +68,39 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux,
Os.macosx,
Os.ios => {
const p = os.posix;
const alloc_size = if(alignment <= os.page_size) n else n + alignment;
const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE,
p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
if(addr == p.MAP_FAILED) return error.OutOfMemory;
if(alloc_size == n) return @intToPtr(&u8, addr)[0..n];
const alloc_size = if (alignment <= os.page_size) n else n + alignment;
const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
if (addr == p.MAP_FAILED) return error.OutOfMemory;
if (alloc_size == n) return @intToPtr(&u8, addr)[0..n];
var aligned_addr = addr & ~usize(alignment - 1);
aligned_addr += alignment;
//We can unmap the unused portions of our mmap, but we must only
// pass munmap bytes that exist outside our allocated pages or it
// will happily eat us too
//Since alignment > page_size, we are by definition on a page boundry
const unused_start = addr;
const unused_len = aligned_addr - 1 - unused_start;
var err = p.munmap(unused_start, unused_len);
debug.assert(p.getErrno(err) == 0);
//It is impossible that there is an unoccupied page at the top of our
// mmap.
return @intToPtr(&u8, aligned_addr)[0..n];
},
Os.windows => {
const amt = n + alignment + @sizeOf(usize);
const heap_handle = self.heap_handle ?? blk: {
const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0)
?? return error.OutOfMemory;
const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
self.heap_handle = hh;
break :blk hh;
};
@ -113,7 +110,7 @@ pub const DirectAllocator = struct {
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
const adjusted_addr = root_addr + march_forward_bytes;
const record_addr = adjusted_addr + n;
*@intToPtr(&align(1) usize, record_addr) = root_addr;
@intToPtr(&align(1) usize, record_addr).* = root_addr;
return @intToPtr(&u8, adjusted_addr)[0..n];
},
else => @compileError("Unsupported OS"),
@ -124,7 +121,9 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux,
Os.macosx,
Os.ios => {
if (new_size <= old_mem.len) {
const base_addr = @ptrToInt(old_mem.ptr);
const old_addr_end = base_addr + old_mem.len;
@ -144,13 +143,13 @@ pub const DirectAllocator = struct {
Os.windows => {
const old_adjusted_addr = @ptrToInt(old_mem.ptr);
const old_record_addr = old_adjusted_addr + old_mem.len;
const root_addr = *@intToPtr(&align(1) usize, old_record_addr);
const root_addr = @intToPtr(&align(1) usize, old_record_addr).*;
const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
const amt = new_size + alignment + @sizeOf(usize);
const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
if (new_size > old_mem.len) return error.OutOfMemory;
const new_record_addr = old_record_addr - new_size + old_mem.len;
*@intToPtr(&align(1) usize, new_record_addr) = root_addr;
@intToPtr(&align(1) usize, new_record_addr).* = root_addr;
return old_mem[0..new_size];
};
const offset = old_adjusted_addr - root_addr;
@ -158,7 +157,7 @@ pub const DirectAllocator = struct {
const new_adjusted_addr = new_root_addr + offset;
assert(new_adjusted_addr % alignment == 0);
const new_record_addr = new_adjusted_addr + new_size;
*@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;
@intToPtr(&align(1) usize, new_record_addr).* = new_root_addr;
return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
},
else => @compileError("Unsupported OS"),
@ -169,12 +168,14 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux,
Os.macosx,
Os.ios => {
_ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
},
Os.windows => {
const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
const root_addr = *@intToPtr(&align(1) usize, record_addr);
const root_addr = @intToPtr(&align(1) usize, record_addr).*;
const ptr = @intToPtr(os.windows.LPVOID, root_addr);
_ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
},
@ -195,8 +196,8 @@ pub const ArenaAllocator = struct {
const BufNode = std.LinkedList([]u8).Node;
pub fn init(child_allocator: &Allocator) ArenaAllocator {
return ArenaAllocator {
.allocator = Allocator {
return ArenaAllocator{
.allocator = Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,
@ -228,7 +229,7 @@ pub const ArenaAllocator = struct {
const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
const buf_node = &buf_node_slice[0];
*buf_node = BufNode {
buf_node.* = BufNode{
.data = buf,
.prev = null,
.next = null,
@ -253,7 +254,7 @@ pub const ArenaAllocator = struct {
cur_node = try self.createNode(cur_buf.len, n + alignment);
continue;
}
const result = cur_buf[adjusted_index .. new_end_index];
const result = cur_buf[adjusted_index..new_end_index];
self.end_index = new_end_index;
return result;
}
@ -269,7 +270,7 @@ pub const ArenaAllocator = struct {
}
}
fn free(allocator: &Allocator, bytes: []u8) void { }
fn free(allocator: &Allocator, bytes: []u8) void {}
};
pub const FixedBufferAllocator = struct {
@ -278,8 +279,8 @@ pub const FixedBufferAllocator = struct {
buffer: []u8,
pub fn init(buffer: []u8) FixedBufferAllocator {
return FixedBufferAllocator {
.allocator = Allocator {
return FixedBufferAllocator{
.allocator = Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,
@ -299,7 +300,7 @@ pub const FixedBufferAllocator = struct {
if (new_end_index > self.buffer.len) {
return error.OutOfMemory;
}
const result = self.buffer[adjusted_index .. new_end_index];
const result = self.buffer[adjusted_index..new_end_index];
self.end_index = new_end_index;
return result;
@ -315,7 +316,7 @@ pub const FixedBufferAllocator = struct {
}
}
fn free(allocator: &Allocator, bytes: []u8) void { }
fn free(allocator: &Allocator, bytes: []u8) void {}
};
/// lock free
@ -325,8 +326,8 @@ pub const ThreadSafeFixedBufferAllocator = struct {
buffer: []u8,
pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
return ThreadSafeFixedBufferAllocator {
.allocator = Allocator {
return ThreadSafeFixedBufferAllocator{
.allocator = Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,
@ -348,8 +349,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {
if (new_end_index > self.buffer.len) {
return error.OutOfMemory;
}
end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index,
builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index .. new_end_index];
end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index..new_end_index];
}
}
@ -363,11 +363,9 @@ pub const ThreadSafeFixedBufferAllocator = struct {
}
}
fn free(allocator: &Allocator, bytes: []u8) void { }
fn free(allocator: &Allocator, bytes: []u8) void {}
};
test "c_allocator" {
if (builtin.link_libc) {
var slice = c_allocator.alloc(u8, 50) catch return;
@ -415,8 +413,8 @@ fn testAllocator(allocator: &mem.Allocator) !void {
var slice = try allocator.alloc(&i32, 100);
for (slice) |*item, i| {
*item = try allocator.create(i32);
**item = i32(i);
item.* = try allocator.create(i32);
item.*.* = i32(i);
}
for (slice) |item, i| {
@ -434,26 +432,26 @@ fn testAllocator(allocator: &mem.Allocator) !void {
fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {
//Maybe a platform's page_size is actually the same as or
// very near usize?
if(os.page_size << 2 > @maxValue(usize)) return;
if (os.page_size << 2 > @maxValue(usize)) return;
const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
const large_align = u29(os.page_size << 2);
var align_mask: usize = undefined;
_ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
var slice = try allocator.allocFn(allocator, 500, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 100, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 10, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));

View File

@ -18,32 +18,17 @@ const is_windows = builtin.os == builtin.Os.windows;
const GetStdIoErrs = os.WindowsGetStdHandleErrs;
pub fn getStdErr() GetStdIoErrs!File {
const handle = if (is_windows)
try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE)
else if (is_posix)
os.posix.STDERR_FILENO
else
unreachable;
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
return File.openHandle(handle);
}
pub fn getStdOut() GetStdIoErrs!File {
const handle = if (is_windows)
try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE)
else if (is_posix)
os.posix.STDOUT_FILENO
else
unreachable;
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
return File.openHandle(handle);
}
pub fn getStdIn() GetStdIoErrs!File {
const handle = if (is_windows)
try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE)
else if (is_posix)
os.posix.STDIN_FILENO
else
unreachable;
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
return File.openHandle(handle);
}
@ -56,11 +41,9 @@ pub const FileInStream = struct {
pub const Stream = InStream(Error);
pub fn init(file: &File) FileInStream {
return FileInStream {
return FileInStream{
.file = file,
.stream = Stream {
.readFn = readFn,
},
.stream = Stream{ .readFn = readFn },
};
}
@ -79,11 +62,9 @@ pub const FileOutStream = struct {
pub const Stream = OutStream(Error);
pub fn init(file: &File) FileOutStream {
return FileOutStream {
return FileOutStream{
.file = file,
.stream = Stream {
.writeFn = writeFn,
},
.stream = Stream{ .writeFn = writeFn },
};
}
@ -121,8 +102,7 @@ pub fn InStream(comptime ReadError: type) type {
}
const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
if (new_buf_size == actual_buf_len)
return error.StreamTooLong;
if (new_buf_size == actual_buf_len) return error.StreamTooLong;
try buffer.resize(new_buf_size);
}
}
@ -165,9 +145,7 @@ pub fn InStream(comptime ReadError: type) type {
/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
/// Caller owns returned memory.
/// If this function returns an error, the contents from the stream read so far are lost.
pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator,
delimiter: u8, max_size: usize) ![]u8
{
pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, delimiter: u8, max_size: usize) ![]u8 {
var buf = Buffer.initNull(allocator);
defer buf.deinit();
@ -283,7 +261,7 @@ pub fn BufferedInStream(comptime Error: type) type {
pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
return struct {
const Self = this;
const Stream = InStream(Error);
const Stream = InStream(Error);
pub stream: Stream,
@ -294,7 +272,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
end_index: usize,
pub fn init(unbuffered_in_stream: &Stream) Self {
return Self {
return Self{
.unbuffered_in_stream = unbuffered_in_stream,
.buffer = undefined,
@ -305,9 +283,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
.start_index = buffer_size,
.end_index = buffer_size,
.stream = Stream {
.readFn = readFn,
},
.stream = Stream{ .readFn = readFn },
};
}
@ -368,13 +344,11 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
index: usize,
pub fn init(unbuffered_out_stream: &Stream) Self {
return Self {
return Self{
.unbuffered_out_stream = unbuffered_out_stream,
.buffer = undefined,
.index = 0,
.stream = Stream {
.writeFn = writeFn,
},
.stream = Stream{ .writeFn = writeFn },
};
}
@ -416,11 +390,9 @@ pub const BufferOutStream = struct {
pub const Stream = OutStream(Error);
pub fn init(buffer: &Buffer) BufferOutStream {
return BufferOutStream {
return BufferOutStream{
.buffer = buffer,
.stream = Stream {
.writeFn = writeFn,
},
.stream = Stream{ .writeFn = writeFn },
};
}
@ -430,7 +402,6 @@ pub const BufferOutStream = struct {
}
};
pub const BufferedAtomicFile = struct {
atomic_file: os.AtomicFile,
file_stream: FileOutStream,
@ -441,7 +412,7 @@ pub const BufferedAtomicFile = struct {
var self = try allocator.create(BufferedAtomicFile);
errdefer allocator.destroy(self);
*self = BufferedAtomicFile {
self.* = BufferedAtomicFile{
.atomic_file = undefined,
.file_stream = undefined,
.buffered_stream = undefined,
@ -489,7 +460,7 @@ pub fn readLine(buf: []u8) !usize {
'\r' => {
// trash the following \n
_ = stream.readByte() catch return error.EndOfFile;
return index;
return index;
},
'\n' => return index,
else => {

View File

@ -35,7 +35,7 @@ pub const Token = struct {
};
pub fn init(id: Id, count: usize, offset: u1) Token {
return Token {
return Token{
.id = id,
.offset = offset,
.string_has_escape = false,
@ -45,7 +45,7 @@ pub const Token = struct {
}
pub fn initString(count: usize, has_unicode_escape: bool) Token {
return Token {
return Token{
.id = Id.String,
.offset = 0,
.string_has_escape = has_unicode_escape,
@ -55,7 +55,7 @@ pub const Token = struct {
}
pub fn initNumber(count: usize, number_is_integer: bool) Token {
return Token {
return Token{
.id = Id.Number,
.offset = 0,
.string_has_escape = false,
@ -66,7 +66,7 @@ pub const Token = struct {
// A marker token is a zero-length
pub fn initMarker(id: Id) Token {
return Token {
return Token{
.id = id,
.offset = 0,
.string_has_escape = false,
@ -77,7 +77,7 @@ pub const Token = struct {
// Slice into the underlying input string.
pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
return input[i + self.offset - self.count .. i + self.offset];
return input[i + self.offset - self.count..i + self.offset];
}
};
@ -105,8 +105,8 @@ const StreamingJsonParser = struct {
stack: u256,
stack_used: u8,
const object_bit = 0;
const array_bit = 1;
const object_bit = 0;
const array_bit = 1;
const max_stack_size = @maxValue(u8);
pub fn init() StreamingJsonParser {
@ -120,7 +120,7 @@ const StreamingJsonParser = struct {
p.count = 0;
// Set before ever read in main transition function
p.after_string_state = undefined;
p.after_value_state = State.ValueEnd; // handle end of values normally
p.after_value_state = State.ValueEnd; // handle end of values normally
p.stack = 0;
p.stack_used = 0;
p.complete = false;
@ -181,7 +181,7 @@ const StreamingJsonParser = struct {
}
};
pub const Error = error {
pub const Error = error{
InvalidTopLevel,
TooManyNestedItems,
TooManyClosingItems,
@ -206,8 +206,8 @@ const StreamingJsonParser = struct {
//
// There is currently no error recovery on a bad stream.
pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {
*token1 = null;
*token2 = null;
token1.* = null;
token2.* = null;
p.count += 1;
// unlikely
@ -228,7 +228,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ObjectSeparator;
*token = Token.initMarker(Token.Id.ObjectBegin);
token.* = Token.initMarker(Token.Id.ObjectBegin);
},
'[' => {
p.stack <<= 1;
@ -238,7 +238,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ValueEnd;
*token = Token.initMarker(Token.Id.ArrayBegin);
token.* = Token.initMarker(Token.Id.ArrayBegin);
},
'-' => {
p.number_is_integer = true;
@ -281,7 +281,10 @@ const StreamingJsonParser = struct {
p.after_value_state = State.TopLevelEnd;
p.count = 0;
},
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -290,7 +293,10 @@ const StreamingJsonParser = struct {
},
State.TopLevelEnd => switch (c) {
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -324,7 +330,7 @@ const StreamingJsonParser = struct {
else => {},
}
*token = Token.initMarker(Token.Id.ObjectEnd);
token.* = Token.initMarker(Token.Id.ObjectEnd);
},
']' => {
if (p.stack & 1 != array_bit) {
@ -348,7 +354,7 @@ const StreamingJsonParser = struct {
else => {},
}
*token = Token.initMarker(Token.Id.ArrayEnd);
token.* = Token.initMarker(Token.Id.ArrayEnd);
},
'{' => {
if (p.stack_used == max_stack_size) {
@ -362,7 +368,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ObjectSeparator;
*token = Token.initMarker(Token.Id.ObjectBegin);
token.* = Token.initMarker(Token.Id.ObjectBegin);
},
'[' => {
if (p.stack_used == max_stack_size) {
@ -376,7 +382,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ValueEnd;
*token = Token.initMarker(Token.Id.ArrayBegin);
token.* = Token.initMarker(Token.Id.ArrayBegin);
},
'-' => {
p.state = State.Number;
@ -406,7 +412,10 @@ const StreamingJsonParser = struct {
p.state = State.NullLiteral1;
p.count = 0;
},
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -428,7 +437,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ObjectSeparator;
*token = Token.initMarker(Token.Id.ObjectBegin);
token.* = Token.initMarker(Token.Id.ObjectBegin);
},
'[' => {
if (p.stack_used == max_stack_size) {
@ -442,7 +451,7 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ValueEnd;
*token = Token.initMarker(Token.Id.ArrayBegin);
token.* = Token.initMarker(Token.Id.ArrayBegin);
},
'-' => {
p.state = State.Number;
@ -472,7 +481,10 @@ const StreamingJsonParser = struct {
p.state = State.NullLiteral1;
p.count = 0;
},
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -501,7 +513,7 @@ const StreamingJsonParser = struct {
p.state = State.TopLevelEnd;
}
*token = Token.initMarker(Token.Id.ArrayEnd);
token.* = Token.initMarker(Token.Id.ArrayEnd);
},
'}' => {
if (p.stack_used == 0) {
@ -519,9 +531,12 @@ const StreamingJsonParser = struct {
p.state = State.TopLevelEnd;
}
*token = Token.initMarker(Token.Id.ObjectEnd);
token.* = Token.initMarker(Token.Id.ObjectEnd);
},
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -534,7 +549,10 @@ const StreamingJsonParser = struct {
p.state = State.ValueBegin;
p.after_string_state = State.ValueEnd;
},
0x09, 0x0A, 0x0D, 0x20 => {
0x09,
0x0A,
0x0D,
0x20 => {
// whitespace
},
else => {
@ -553,12 +571,15 @@ const StreamingJsonParser = struct {
p.complete = true;
}
*token = Token.initString(p.count - 1, p.string_has_escape);
token.* = Token.initString(p.count - 1, p.string_has_escape);
},
'\\' => {
p.state = State.StringEscapeCharacter;
},
0x20, 0x21, 0x23 ... 0x5B, 0x5D ... 0x7F => {
0x20,
0x21,
0x23 ... 0x5B,
0x5D ... 0x7F => {
// non-control ascii
},
0xC0 ... 0xDF => {
@ -599,7 +620,14 @@ const StreamingJsonParser = struct {
// The current JSONTestSuite tests rely on both of this behaviour being present
// however, so we default to the status quo where both are accepted until this
// is further clarified.
'"', '\\', '/', 'b', 'f', 'n', 'r', 't' => {
'"',
'\\',
'/',
'b',
'f',
'n',
'r',
't' => {
p.string_has_escape = true;
p.state = State.String;
},
@ -613,28 +641,36 @@ const StreamingJsonParser = struct {
},
State.StringEscapeHexUnicode4 => switch (c) {
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
'0' ... '9',
'A' ... 'F',
'a' ... 'f' => {
p.state = State.StringEscapeHexUnicode3;
},
else => return error.InvalidUnicodeHexSymbol,
},
State.StringEscapeHexUnicode3 => switch (c) {
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
'0' ... '9',
'A' ... 'F',
'a' ... 'f' => {
p.state = State.StringEscapeHexUnicode2;
},
else => return error.InvalidUnicodeHexSymbol,
},
State.StringEscapeHexUnicode2 => switch (c) {
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
'0' ... '9',
'A' ... 'F',
'a' ... 'f' => {
p.state = State.StringEscapeHexUnicode1;
},
else => return error.InvalidUnicodeHexSymbol,
},
State.StringEscapeHexUnicode1 => switch (c) {
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
'0' ... '9',
'A' ... 'F',
'a' ... 'f' => {
p.state = State.String;
},
else => return error.InvalidUnicodeHexSymbol,
@ -662,13 +698,14 @@ const StreamingJsonParser = struct {
p.number_is_integer = false;
p.state = State.NumberFractionalRequired;
},
'e', 'E' => {
'e',
'E' => {
p.number_is_integer = false;
p.state = State.NumberExponent;
},
else => {
p.state = p.after_value_state;
*token = Token.initNumber(p.count, p.number_is_integer);
token.* = Token.initNumber(p.count, p.number_is_integer);
return true;
},
}
@ -681,7 +718,8 @@ const StreamingJsonParser = struct {
p.number_is_integer = false;
p.state = State.NumberFractionalRequired;
},
'e', 'E' => {
'e',
'E' => {
p.number_is_integer = false;
p.state = State.NumberExponent;
},
@ -690,7 +728,7 @@ const StreamingJsonParser = struct {
},
else => {
p.state = p.after_value_state;
*token = Token.initNumber(p.count, p.number_is_integer);
token.* = Token.initNumber(p.count, p.number_is_integer);
return true;
},
}
@ -714,13 +752,14 @@ const StreamingJsonParser = struct {
'0' ... '9' => {
// another digit
},
'e', 'E' => {
'e',
'E' => {
p.number_is_integer = false;
p.state = State.NumberExponent;
},
else => {
p.state = p.after_value_state;
*token = Token.initNumber(p.count, p.number_is_integer);
token.* = Token.initNumber(p.count, p.number_is_integer);
return true;
},
}
@ -729,20 +768,22 @@ const StreamingJsonParser = struct {
State.NumberMaybeExponent => {
p.complete = p.after_value_state == State.TopLevelEnd;
switch (c) {
'e', 'E' => {
'e',
'E' => {
p.number_is_integer = false;
p.state = State.NumberExponent;
},
else => {
p.state = p.after_value_state;
*token = Token.initNumber(p.count, p.number_is_integer);
token.* = Token.initNumber(p.count, p.number_is_integer);
return true;
},
}
},
State.NumberExponent => switch (c) {
'-', '+', => {
'-',
'+' => {
p.complete = false;
p.state = State.NumberExponentDigitsRequired;
},
@ -773,7 +814,7 @@ const StreamingJsonParser = struct {
},
else => {
p.state = p.after_value_state;
*token = Token.initNumber(p.count, p.number_is_integer);
token.* = Token.initNumber(p.count, p.number_is_integer);
return true;
},
}
@ -793,7 +834,7 @@ const StreamingJsonParser = struct {
'e' => {
p.state = p.after_value_state;
p.complete = p.state == State.TopLevelEnd;
*token = Token.init(Token.Id.True, p.count + 1, 1);
token.* = Token.init(Token.Id.True, p.count + 1, 1);
},
else => {
return error.InvalidLiteral;
@ -819,7 +860,7 @@ const StreamingJsonParser = struct {
'e' => {
p.state = p.after_value_state;
p.complete = p.state == State.TopLevelEnd;
*token = Token.init(Token.Id.False, p.count + 1, 1);
token.* = Token.init(Token.Id.False, p.count + 1, 1);
},
else => {
return error.InvalidLiteral;
@ -840,7 +881,7 @@ const StreamingJsonParser = struct {
'l' => {
p.state = p.after_value_state;
p.complete = p.state == State.TopLevelEnd;
*token = Token.init(Token.Id.Null, p.count + 1, 1);
token.* = Token.init(Token.Id.Null, p.count + 1, 1);
},
else => {
return error.InvalidLiteral;
@ -895,7 +936,7 @@ pub const Value = union(enum) {
Object: ObjectMap,
pub fn dump(self: &const Value) void {
switch (*self) {
switch (self.*) {
Value.Null => {
std.debug.warn("null");
},
@ -950,7 +991,7 @@ pub const Value = union(enum) {
}
fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {
switch (*self) {
switch (self.*) {
Value.Null => {
std.debug.warn("null");
},
@ -1027,7 +1068,7 @@ const JsonParser = struct {
};
pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {
return JsonParser {
return JsonParser{
.allocator = allocator,
.state = State.Simple,
.copy_strings = copy_strings,
@ -1082,7 +1123,7 @@ const JsonParser = struct {
std.debug.assert(p.stack.len == 1);
return ValueTree {
return ValueTree{
.arena = arena,
.root = p.stack.at(0),
};
@ -1115,11 +1156,11 @@ const JsonParser = struct {
switch (token.id) {
Token.Id.ObjectBegin => {
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey;
},
Token.Id.ArrayBegin => {
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue;
},
Token.Id.String => {
@ -1133,12 +1174,12 @@ const JsonParser = struct {
p.state = State.ObjectKey;
},
Token.Id.True => {
_ = try object.put(key, Value { .Bool = true });
_ = try object.put(key, Value{ .Bool = true });
_ = p.stack.pop();
p.state = State.ObjectKey;
},
Token.Id.False => {
_ = try object.put(key, Value { .Bool = false });
_ = try object.put(key, Value{ .Bool = false });
_ = p.stack.pop();
p.state = State.ObjectKey;
},
@ -1165,11 +1206,11 @@ const JsonParser = struct {
try p.pushToParent(value);
},
Token.Id.ObjectBegin => {
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey;
},
Token.Id.ArrayBegin => {
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue;
},
Token.Id.String => {
@ -1179,10 +1220,10 @@ const JsonParser = struct {
try array.append(try p.parseNumber(token, input, i));
},
Token.Id.True => {
try array.append(Value { .Bool = true });
try array.append(Value{ .Bool = true });
},
Token.Id.False => {
try array.append(Value { .Bool = false });
try array.append(Value{ .Bool = false });
},
Token.Id.Null => {
try array.append(Value.Null);
@ -1194,11 +1235,11 @@ const JsonParser = struct {
},
State.Simple => switch (token.id) {
Token.Id.ObjectBegin => {
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey;
},
Token.Id.ArrayBegin => {
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue;
},
Token.Id.String => {
@ -1208,15 +1249,16 @@ const JsonParser = struct {
try p.stack.append(try p.parseNumber(token, input, i));
},
Token.Id.True => {
try p.stack.append(Value { .Bool = true });
try p.stack.append(Value{ .Bool = true });
},
Token.Id.False => {
try p.stack.append(Value { .Bool = false });
try p.stack.append(Value{ .Bool = false });
},
Token.Id.Null => {
try p.stack.append(Value.Null);
},
Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
Token.Id.ObjectEnd,
Token.Id.ArrayEnd => {
unreachable;
},
},
@ -1248,15 +1290,14 @@ const JsonParser = struct {
// TODO: We don't strictly have to copy values which do not contain any escape
// characters if flagged with the option.
const slice = token.slice(input, i);
return Value { .String = try mem.dupe(p.allocator, u8, slice) };
return Value{ .String = try mem.dupe(p.allocator, u8, slice) };
}
fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {
return if (token.number_is_integer)
Value { .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
else
@panic("TODO: fmt.parseFloat not yet implemented")
;
@panic("TODO: fmt.parseFloat not yet implemented");
}
};
@ -1267,21 +1308,21 @@ test "json parser dynamic" {
defer p.deinit();
const s =
\\{
\\ "Image": {
\\ "Width": 800,
\\ "Height": 600,
\\ "Title": "View from 15th Floor",
\\ "Thumbnail": {
\\ "Url": "http://www.example.com/image/481989943",
\\ "Height": 125,
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ }
\\}
;
\\{
\\ "Image": {
\\ "Width": 800,
\\ "Height": 600,
\\ "Title": "View from 15th Floor",
\\ "Thumbnail": {
\\ "Url": "http://www.example.com/image/481989943",
\\ "Height": 125,
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ }
\\}
;
var tree = try p.parse(s);
defer tree.deinit();

View File

@ -26,10 +26,10 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
data: T,
pub fn init(value: &const T) Node {
return Node {
return Node{
.prev = null,
.next = null,
.data = *value,
.data = value.*,
};
}
@ -45,18 +45,18 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
};
first: ?&Node,
last: ?&Node,
len: usize,
last: ?&Node,
len: usize,
/// Initialize a linked list.
///
/// Returns:
/// An empty linked list.
pub fn init() Self {
return Self {
return Self{
.first = null,
.last = null,
.len = 0,
.last = null,
.len = 0,
};
}
@ -131,7 +131,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
} else {
// Empty list.
list.first = new_node;
list.last = new_node;
list.last = new_node;
new_node.prev = null;
new_node.next = null;
@ -217,7 +217,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node {
comptime assert(!isIntrusive());
var node = try list.allocateNode(allocator);
*node = Node.init(data);
node.* = Node.init(data);
return node;
}
};
@ -227,11 +227,11 @@ test "basic linked list test" {
const allocator = debug.global_allocator;
var list = LinkedList(u32).init();
var one = try list.createNode(1, allocator);
var two = try list.createNode(2, allocator);
var one = try list.createNode(1, allocator);
var two = try list.createNode(2, allocator);
var three = try list.createNode(3, allocator);
var four = try list.createNode(4, allocator);
var five = try list.createNode(5, allocator);
var four = try list.createNode(4, allocator);
var five = try list.createNode(5, allocator);
defer {
list.destroyNode(one, allocator);
list.destroyNode(two, allocator);
@ -240,11 +240,11 @@ test "basic linked list test" {
list.destroyNode(five, allocator);
}
list.append(two); // {2}
list.append(five); // {2, 5}
list.prepend(one); // {1, 2, 5}
list.insertBefore(five, four); // {1, 2, 4, 5}
list.insertAfter(two, three); // {1, 2, 3, 4, 5}
list.append(two); // {2}
list.append(five); // {2, 5}
list.prepend(one); // {1, 2, 5}
list.insertBefore(five, four); // {1, 2, 4, 5}
list.insertAfter(two, three); // {1, 2, 3, 4, 5}
// Traverse forwards.
{
@ -266,13 +266,13 @@ test "basic linked list test" {
}
}
var first = list.popFirst(); // {2, 3, 4, 5}
var last = list.pop(); // {2, 3, 4}
list.remove(three); // {2, 4}
var first = list.popFirst(); // {2, 3, 4, 5}
var last = list.pop(); // {2, 3, 4}
list.remove(three); // {2, 4}
assert ((??list.first).data == 2);
assert ((??list.last ).data == 4);
assert (list.len == 2);
assert((??list.first).data == 2);
assert((??list.last).data == 4);
assert(list.len == 2);
}
const ElementList = IntrusiveLinkedList(Element, "link");
@ -285,17 +285,32 @@ test "basic intrusive linked list test" {
const allocator = debug.global_allocator;
var list = ElementList.init();
var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() };
var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() };
var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() };
var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() };
var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() };
var one = Element{
.value = 1,
.link = ElementList.Node.initIntrusive(),
};
var two = Element{
.value = 2,
.link = ElementList.Node.initIntrusive(),
};
var three = Element{
.value = 3,
.link = ElementList.Node.initIntrusive(),
};
var four = Element{
.value = 4,
.link = ElementList.Node.initIntrusive(),
};
var five = Element{
.value = 5,
.link = ElementList.Node.initIntrusive(),
};
list.append(&two.link); // {2}
list.append(&five.link); // {2, 5}
list.prepend(&one.link); // {1, 2, 5}
list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
list.append(&two.link); // {2}
list.append(&five.link); // {2, 5}
list.prepend(&one.link); // {1, 2, 5}
list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
// Traverse forwards.
{
@ -317,11 +332,11 @@ test "basic intrusive linked list test" {
}
}
var first = list.popFirst(); // {2, 3, 4, 5}
var last = list.pop(); // {2, 3, 4}
list.remove(&three.link); // {2, 4}
var first = list.popFirst(); // {2, 3, 4, 5}
var last = list.pop(); // {2, 3, 4}
list.remove(&three.link); // {2, 4}
assert ((??list.first).toData().value == 2);
assert ((??list.last ).toData().value == 4);
assert (list.len == 2);
assert((??list.first).toData().value == 2);
assert((??list.last).toData().value == 4);
assert(list.len == 2);
}

View File

@ -16,7 +16,7 @@ pub fn acos(x: var) @typeOf(x) {
}
fn r32(z: f32) f32 {
const pS0 = 1.6666586697e-01;
const pS0 = 1.6666586697e-01;
const pS1 = -4.2743422091e-02;
const pS2 = -8.6563630030e-03;
const qS1 = -7.0662963390e-01;
@ -74,16 +74,16 @@ fn acos32(x: f32) f32 {
}
fn r64(z: f64) f64 {
const pS0: f64 = 1.66666666666666657415e-01;
const pS0: f64 = 1.66666666666666657415e-01;
const pS1: f64 = -3.25565818622400915405e-01;
const pS2: f64 = 2.01212532134862925881e-01;
const pS2: f64 = 2.01212532134862925881e-01;
const pS3: f64 = -4.00555345006794114027e-02;
const pS4: f64 = 7.91534994289814532176e-04;
const pS5: f64 = 3.47933107596021167570e-05;
const pS4: f64 = 7.91534994289814532176e-04;
const pS5: f64 = 3.47933107596021167570e-05;
const qS1: f64 = -2.40339491173441421878e+00;
const qS2: f64 = 2.02094576023350569471e+00;
const qS2: f64 = 2.02094576023350569471e+00;
const qS3: f64 = -6.88283971605453293030e-01;
const qS4: f64 = 7.70381505559019352791e-02;
const qS4: f64 = 7.70381505559019352791e-02;
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));

View File

@ -17,7 +17,7 @@ pub fn asin(x: var) @typeOf(x) {
}
fn r32(z: f32) f32 {
const pS0 = 1.6666586697e-01;
const pS0 = 1.6666586697e-01;
const pS1 = -4.2743422091e-02;
const pS2 = -8.6563630030e-03;
const qS1 = -7.0662963390e-01;
@ -37,9 +37,9 @@ fn asin32(x: f32) f32 {
if (ix >= 0x3F800000) {
// |x| >= 1
if (ix == 0x3F800000) {
return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
} else {
return math.nan(f32); // asin(|x| > 1) is nan
return math.nan(f32); // asin(|x| > 1) is nan
}
}
@ -66,16 +66,16 @@ fn asin32(x: f32) f32 {
}
fn r64(z: f64) f64 {
const pS0: f64 = 1.66666666666666657415e-01;
const pS0: f64 = 1.66666666666666657415e-01;
const pS1: f64 = -3.25565818622400915405e-01;
const pS2: f64 = 2.01212532134862925881e-01;
const pS2: f64 = 2.01212532134862925881e-01;
const pS3: f64 = -4.00555345006794114027e-02;
const pS4: f64 = 7.91534994289814532176e-04;
const pS5: f64 = 3.47933107596021167570e-05;
const pS4: f64 = 7.91534994289814532176e-04;
const pS5: f64 = 3.47933107596021167570e-05;
const qS1: f64 = -2.40339491173441421878e+00;
const qS2: f64 = 2.02094576023350569471e+00;
const qS2: f64 = 2.02094576023350569471e+00;
const qS3: f64 = -6.88283971605453293030e-01;
const qS4: f64 = 7.70381505559019352791e-02;
const qS4: f64 = 7.70381505559019352791e-02;
const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));

View File

@ -31,7 +31,7 @@ pub fn atan2(comptime T: type, x: T, y: T) T {
}
fn atan2_32(y: f32, x: f32) f32 {
const pi: f32 = 3.1415927410e+00;
const pi: f32 = 3.1415927410e+00;
const pi_lo: f32 = -8.7422776573e-08;
if (math.isNan(x) or math.isNan(y)) {
@ -53,9 +53,10 @@ fn atan2_32(y: f32, x: f32) f32 {
if (iy == 0) {
switch (m) {
0, 1 => return y, // atan(+-0, +...)
2 => return pi, // atan(+0, -...)
3 => return -pi, // atan(-0, -...)
0,
1 => return y, // atan(+-0, +...)
2 => return pi, // atan(+0, -...)
3 => return -pi, // atan(-0, -...)
else => unreachable,
}
}
@ -71,18 +72,18 @@ fn atan2_32(y: f32, x: f32) f32 {
if (ix == 0x7F800000) {
if (iy == 0x7F800000) {
switch (m) {
0 => return pi / 4, // atan(+inf, +inf)
1 => return -pi / 4, // atan(-inf, +inf)
2 => return 3*pi / 4, // atan(+inf, -inf)
3 => return -3*pi / 4, // atan(-inf, -inf)
0 => return pi / 4, // atan(+inf, +inf)
1 => return -pi / 4, // atan(-inf, +inf)
2 => return 3 * pi / 4, // atan(+inf, -inf)
3 => return -3 * pi / 4, // atan(-inf, -inf)
else => unreachable,
}
} else {
switch (m) {
0 => return 0.0, // atan(+..., +inf)
1 => return -0.0, // atan(-..., +inf)
2 => return pi, // atan(+..., -inf)
3 => return -pi, // atan(-...f, -inf)
0 => return 0.0, // atan(+..., +inf)
1 => return -0.0, // atan(-..., +inf)
2 => return pi, // atan(+..., -inf)
3 => return -pi, // atan(-...f, -inf)
else => unreachable,
}
}
@ -107,16 +108,16 @@ fn atan2_32(y: f32, x: f32) f32 {
};
switch (m) {
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
else => unreachable,
}
}
fn atan2_64(y: f64, x: f64) f64 {
const pi: f64 = 3.1415926535897931160E+00;
const pi: f64 = 3.1415926535897931160E+00;
const pi_lo: f64 = 1.2246467991473531772E-16;
if (math.isNan(x) or math.isNan(y)) {
@ -143,9 +144,10 @@ fn atan2_64(y: f64, x: f64) f64 {
if (iy | ly == 0) {
switch (m) {
0, 1 => return y, // atan(+-0, +...)
2 => return pi, // atan(+0, -...)
3 => return -pi, // atan(-0, -...)
0,
1 => return y, // atan(+-0, +...)
2 => return pi, // atan(+0, -...)
3 => return -pi, // atan(-0, -...)
else => unreachable,
}
}
@ -161,18 +163,18 @@ fn atan2_64(y: f64, x: f64) f64 {
if (ix == 0x7FF00000) {
if (iy == 0x7FF00000) {
switch (m) {
0 => return pi / 4, // atan(+inf, +inf)
1 => return -pi / 4, // atan(-inf, +inf)
2 => return 3*pi / 4, // atan(+inf, -inf)
3 => return -3*pi / 4, // atan(-inf, -inf)
0 => return pi / 4, // atan(+inf, +inf)
1 => return -pi / 4, // atan(-inf, +inf)
2 => return 3 * pi / 4, // atan(+inf, -inf)
3 => return -3 * pi / 4, // atan(-inf, -inf)
else => unreachable,
}
} else {
switch (m) {
0 => return 0.0, // atan(+..., +inf)
1 => return -0.0, // atan(-..., +inf)
2 => return pi, // atan(+..., -inf)
3 => return -pi, // atan(-...f, -inf)
0 => return 0.0, // atan(+..., +inf)
1 => return -0.0, // atan(-..., +inf)
2 => return pi, // atan(+..., -inf)
3 => return -pi, // atan(-...f, -inf)
else => unreachable,
}
}
@ -197,10 +199,10 @@ fn atan2_64(y: f64, x: f64) f64 {
};
switch (m) {
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
else => unreachable,
}
}

View File

@ -58,15 +58,15 @@ fn cbrt32(x: f32) f32 {
}
fn cbrt64(x: f64) f64 {
const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^20
const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^20
const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^20
const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^20
// |1 / cbrt(x) - p(x)| < 2^(23.5)
const P0: f64 = 1.87595182427177009643;
const P0: f64 = 1.87595182427177009643;
const P1: f64 = -1.88497979543377169875;
const P2: f64 = 1.621429720105354466140;
const P2: f64 = 1.621429720105354466140;
const P3: f64 = -0.758397934778766047437;
const P4: f64 = 0.145996192886612446982;
const P4: f64 = 0.145996192886612446982;
var u = @bitCast(u64, x);
var hx = u32(u >> 32) & 0x7FFFFFFF;

View File

@ -56,7 +56,7 @@ fn ceil64(x: f64) f64 {
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
if (e >= 0x3FF+52 or x == 0) {
if (e >= 0x3FF + 52 or x == 0) {
return x;
}
@ -68,7 +68,7 @@ fn ceil64(x: f64) f64 {
y = x + math.f64_toint - math.f64_toint - x;
}
if (e <= 0x3FF-1) {
if (e <= 0x3FF - 1) {
math.forceEval(y);
if (u >> 63 != 0) {
return -0.0;

View File

@ -19,8 +19,8 @@ pub fn exp(z: var) Complex(@typeOf(z.re)) {
fn exp32(z: &const Complex(f32)) Complex(f32) {
@setFloatMode(this, @import("builtin").FloatMode.Strict);
const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.72283955
const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln2
const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.72283955
const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln2
const x = z.re;
const y = z.im;
@ -41,12 +41,10 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
// cexp(finite|nan +- i inf|nan) = nan + i nan
if ((hx & 0x7fffffff) != 0x7f800000) {
return Complex(f32).new(y - y, y - y);
}
// cexp(-inf +- i inf|nan) = 0 + i0
} // cexp(-inf +- i inf|nan) = 0 + i0
else if (hx & 0x80000000 != 0) {
return Complex(f32).new(0, 0);
}
// cexp(+inf +- i inf|nan) = inf + i nan
} // cexp(+inf +- i inf|nan) = inf + i nan
else {
return Complex(f32).new(x, y - y);
}
@ -55,8 +53,7 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
// 88.7 <= x <= 192 so must scale
if (hx >= exp_overflow and hx <= cexp_overflow) {
return ldexp_cexp(z, 0);
}
// - x < exp_overflow => exp(x) won't overflow (common)
} // - x < exp_overflow => exp(x) won't overflow (common)
// - x > cexp_overflow, so exp(x) * s overflows for s > 0
// - x = +-inf
// - x = nan
@ -67,8 +64,8 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
}
fn exp64(z: &const Complex(f64)) Complex(f64) {
const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 710
const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln2
const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 710
const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln2
const x = z.re;
const y = z.im;
@ -95,12 +92,10 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {
// cexp(finite|nan +- i inf|nan) = nan + i nan
if (lx != 0 or (hx & 0x7fffffff) != 0x7ff00000) {
return Complex(f64).new(y - y, y - y);
}
// cexp(-inf +- i inf|nan) = 0 + i0
} // cexp(-inf +- i inf|nan) = 0 + i0
else if (hx & 0x80000000 != 0) {
return Complex(f64).new(0, 0);
}
// cexp(+inf +- i inf|nan) = inf + i nan
} // cexp(+inf +- i inf|nan) = inf + i nan
else {
return Complex(f64).new(x, y - y);
}
@ -109,9 +104,8 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {
// 709.7 <= x <= 1454.3 so must scale
if (hx >= exp_overflow and hx <= cexp_overflow) {
const r = ldexp_cexp(z, 0);
return *r;
}
// - x < exp_overflow => exp(x) won't overflow (common)
return r.*;
} // - x < exp_overflow => exp(x) won't overflow (common)
// - x > cexp_overflow, so exp(x) * s overflows for s > 0
// - x = +-inf
// - x = nan

View File

@ -15,12 +15,12 @@ pub fn ldexp_cexp(z: var, expt: i32) Complex(@typeOf(z.re)) {
}
fn frexp_exp32(x: f32, expt: &i32) f32 {
const k = 235; // reduction constant
const kln2 = 162.88958740; // k * ln2
const k = 235; // reduction constant
const kln2 = 162.88958740; // k * ln2
const exp_x = math.exp(x - kln2);
const hx = @bitCast(u32, exp_x);
*expt = i32(hx >> 23) - (0x7f + 127) + k;
expt.* = i32(hx >> 23) - (0x7f + 127) + k;
return @bitCast(f32, (hx & 0x7fffff) | ((0x7f + 127) << 23));
}
@ -35,15 +35,12 @@ fn ldexp_cexp32(z: &const Complex(f32), expt: i32) Complex(f32) {
const half_expt2 = exptf - half_expt1;
const scale2 = @bitCast(f32, (0x7f + half_expt2) << 23);
return Complex(f32).new(
math.cos(z.im) * exp_x * scale1 * scale2,
math.sin(z.im) * exp_x * scale1 * scale2,
);
return Complex(f32).new(math.cos(z.im) * exp_x * scale1 * scale2, math.sin(z.im) * exp_x * scale1 * scale2);
}
fn frexp_exp64(x: f64, expt: &i32) f64 {
const k = 1799; // reduction constant
const kln2 = 1246.97177782734161156; // k * ln2
const k = 1799; // reduction constant
const kln2 = 1246.97177782734161156; // k * ln2
const exp_x = math.exp(x - kln2);
@ -51,7 +48,7 @@ fn frexp_exp64(x: f64, expt: &i32) f64 {
const hx = u32(fx >> 32);
const lx = @truncate(u32, fx);
*expt = i32(hx >> 20) - (0x3ff + 1023) + k;
expt.* = i32(hx >> 20) - (0x3ff + 1023) + k;
const high_word = (hx & 0xfffff) | ((0x3ff + 1023) << 20);
return @bitCast(f64, (u64(high_word) << 32) | lx);

View File

@ -18,20 +18,20 @@ pub fn cos(x: var) @typeOf(x) {
}
// sin polynomial coefficients
const S0 = 1.58962301576546568060E-10;
const S0 = 1.58962301576546568060E-10;
const S1 = -2.50507477628578072866E-8;
const S2 = 2.75573136213857245213E-6;
const S2 = 2.75573136213857245213E-6;
const S3 = -1.98412698295895385996E-4;
const S4 = 8.33333333332211858878E-3;
const S4 = 8.33333333332211858878E-3;
const S5 = -1.66666666666666307295E-1;
// cos polynomial coeffiecients
const C0 = -1.13585365213876817300E-11;
const C1 = 2.08757008419747316778E-9;
const C1 = 2.08757008419747316778E-9;
const C2 = -2.75573141792967388112E-7;
const C3 = 2.48015872888517045348E-5;
const C3 = 2.48015872888517045348E-5;
const C4 = -1.38888888888730564116E-3;
const C5 = 4.16666666666665929218E-2;
const C5 = 4.16666666666665929218E-2;
// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
//

View File

@ -57,7 +57,7 @@ fn floor64(x: f64) f64 {
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
if (e >= 0x3FF+52 or x == 0) {
if (e >= 0x3FF + 52 or x == 0) {
return x;
}
@ -69,7 +69,7 @@ fn floor64(x: f64) f64 {
y = x + math.f64_toint - math.f64_toint - x;
}
if (e <= 0x3FF-1) {
if (e <= 0x3FF - 1) {
math.forceEval(y);
if (u >> 63 != 0) {
return -1.0;

View File

@ -5,7 +5,7 @@ const assert = std.debug.assert;
pub fn fma(comptime T: type, x: T, y: T, z: T) T {
return switch (T) {
f32 => fma32(x, y, z),
f64 => fma64(x, y ,z),
f64 => fma64(x, y, z),
else => @compileError("fma not implemented for " ++ @typeName(T)),
};
}
@ -71,7 +71,10 @@ fn fma64(x: f64, y: f64, z: f64) f64 {
}
}
const dd = struct { hi: f64, lo: f64, };
const dd = struct {
hi: f64,
lo: f64,
};
fn dd_add(a: f64, b: f64) dd {
var ret: dd = undefined;

View File

@ -39,11 +39,11 @@ fn hypot32(x: f32, y: f32) f32 {
}
var z: f32 = 1.0;
if (ux >= (0x7F+60) << 23) {
if (ux >= (0x7F + 60) << 23) {
z = 0x1.0p90;
xx *= 0x1.0p-90;
yy *= 0x1.0p-90;
} else if (uy < (0x7F-60) << 23) {
} else if (uy < (0x7F - 60) << 23) {
z = 0x1.0p-90;
xx *= 0x1.0p-90;
yy *= 0x1.0p-90;
@ -57,8 +57,8 @@ fn sq(hi: &f64, lo: &f64, x: f64) void {
const xc = x * split;
const xh = x - xc + xc;
const xl = x - xh;
*hi = x * x;
*lo = xh * xh - *hi + 2 * xh * xl + xl * xl;
hi.* = x * x;
lo.* = xh * xh - hi.* + 2 * xh * xl + xl * xl;
}
fn hypot64(x: f64, y: f64) f64 {

View File

@ -47,12 +47,12 @@ pub fn forceEval(value: var) void {
f32 => {
var x: f32 = undefined;
const p = @ptrCast(&volatile f32, &x);
*p = x;
p.* = x;
},
f64 => {
var x: f64 = undefined;
const p = @ptrCast(&volatile f64, &x);
*p = x;
p.* = x;
},
else => {
@compileError("forceEval not implemented for " ++ @typeName(T));
@ -179,7 +179,6 @@ test "math" {
_ = @import("complex/index.zig");
}
pub fn min(x: var, y: var) @typeOf(x + y) {
return if (x < y) x else y;
}
@ -280,10 +279,10 @@ pub fn rotr(comptime T: type, x: T, r: var) T {
}
test "math.rotr" {
assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
}
@ -299,14 +298,13 @@ pub fn rotl(comptime T: type, x: T, r: var) T {
}
test "math.rotl" {
assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
}
pub fn Log2Int(comptime T: type) type {
return @IntType(false, log2(T.bit_count));
}
@ -323,14 +321,14 @@ fn testOverflow() void {
assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
}
pub fn absInt(x: var) !@typeOf(x) {
const T = @typeOf(x);
comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
comptime assert(T.is_signed); // must pass a signed integer to absInt
if (x == @minValue(@typeOf(x)))
if (x == @minValue(@typeOf(x))) {
return error.Overflow;
{
} else {
@setRuntimeSafety(false);
return if (x < 0) -x else x;
}
@ -349,10 +347,8 @@ pub const absFloat = @import("fabs.zig").fabs;
pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
if (denominator == 0)
return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
return error.Overflow;
if (denominator == 0) return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
return @divTrunc(numerator, denominator);
}
@ -372,10 +368,8 @@ fn testDivTrunc() void {
pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
if (denominator == 0)
return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
return error.Overflow;
if (denominator == 0) return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
return @divFloor(numerator, denominator);
}
@ -395,13 +389,10 @@ fn testDivFloor() void {
pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
if (denominator == 0)
return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
return error.Overflow;
if (denominator == 0) return error.DivisionByZero;
if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
const result = @divTrunc(numerator, denominator);
if (result * denominator != numerator)
return error.UnexpectedRemainder;
if (result * denominator != numerator) return error.UnexpectedRemainder;
return result;
}
@ -423,10 +414,8 @@ fn testDivExact() void {
pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
if (denominator == 0)
return error.DivisionByZero;
if (denominator < 0)
return error.NegativeDenominator;
if (denominator == 0) return error.DivisionByZero;
if (denominator < 0) return error.NegativeDenominator;
return @mod(numerator, denominator);
}
@ -448,10 +437,8 @@ fn testMod() void {
pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
if (denominator == 0)
return error.DivisionByZero;
if (denominator < 0)
return error.NegativeDenominator;
if (denominator == 0) return error.DivisionByZero;
if (denominator < 0) return error.NegativeDenominator;
return @rem(numerator, denominator);
}
@ -475,8 +462,7 @@ fn testRem() void {
/// Result is an unsigned integer.
pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
const uint = @IntType(false, @typeOf(x).bit_count);
if (x >= 0)
return uint(x);
if (x >= 0) return uint(x);
return uint(-(x + 1)) + 1;
}
@ -495,15 +481,12 @@ test "math.absCast" {
/// Returns the negation of the integer parameter.
/// Result is a signed integer.
pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
if (@typeOf(x).is_signed)
return negate(x);
if (@typeOf(x).is_signed) return negate(x);
const int = @IntType(true, @typeOf(x).bit_count);
if (x > -@minValue(int))
return error.Overflow;
if (x > -@minValue(int)) return error.Overflow;
if (x == -@minValue(int))
return @minValue(int);
if (x == -@minValue(int)) return @minValue(int);
return -int(x);
}
@ -546,7 +529,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T {
var x = value;
comptime var i = 1;
inline while(T.bit_count > i) : (i *= 2) {
inline while (T.bit_count > i) : (i *= 2) {
x |= (x >> i);
}

View File

@ -120,11 +120,9 @@ pub fn ln_64(x_: f64) f64 {
k -= 54;
x *= 0x1.0p54;
hx = u32(@bitCast(u64, ix) >> 32);
}
else if (hx >= 0x7FF00000) {
} else if (hx >= 0x7FF00000) {
return x;
}
else if (hx == 0x3FF00000 and ix << 32 == 0) {
} else if (hx == 0x3FF00000 and ix << 32 == 0) {
return 0;
}

View File

@ -35,10 +35,10 @@ pub fn log10(x: var) @typeOf(x) {
}
pub fn log10_32(x_: f32) f32 {
const ivln10hi: f32 = 4.3432617188e-01;
const ivln10lo: f32 = -3.1689971365e-05;
const log10_2hi: f32 = 3.0102920532e-01;
const log10_2lo: f32 = 7.9034151668e-07;
const ivln10hi: f32 = 4.3432617188e-01;
const ivln10lo: f32 = -3.1689971365e-05;
const log10_2hi: f32 = 3.0102920532e-01;
const log10_2lo: f32 = 7.9034151668e-07;
const Lg1: f32 = 0xaaaaaa.0p-24;
const Lg2: f32 = 0xccce13.0p-25;
const Lg3: f32 = 0x91e9ee.0p-25;
@ -95,8 +95,8 @@ pub fn log10_32(x_: f32) f32 {
}
pub fn log10_64(x_: f64) f64 {
const ivln10hi: f64 = 4.34294481878168880939e-01;
const ivln10lo: f64 = 2.50829467116452752298e-11;
const ivln10hi: f64 = 4.34294481878168880939e-01;
const ivln10lo: f64 = 2.50829467116452752298e-11;
const log10_2hi: f64 = 3.01029995663611771306e-01;
const log10_2lo: f64 = 3.69423907715893078616e-13;
const Lg1: f64 = 6.666666666666735130e-01;
@ -126,11 +126,9 @@ pub fn log10_64(x_: f64) f64 {
k -= 54;
x *= 0x1.0p54;
hx = u32(@bitCast(u64, x) >> 32);
}
else if (hx >= 0x7FF00000) {
} else if (hx >= 0x7FF00000) {
return x;
}
else if (hx == 0x3FF00000 and ix << 32 == 0) {
} else if (hx == 0x3FF00000 and ix << 32 == 0) {
return 0;
}

View File

@ -27,7 +27,10 @@ pub fn log2(x: var) @typeOf(x) {
TypeId.IntLiteral => comptime {
var result = 0;
var x_shifted = x;
while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {}
while (b: {
x_shifted >>= 1;
break :b x_shifted != 0;
}) : (result += 1) {}
return result;
},
TypeId.Int => {
@ -38,7 +41,7 @@ pub fn log2(x: var) @typeOf(x) {
}
pub fn log2_32(x_: f32) f32 {
const ivln2hi: f32 = 1.4428710938e+00;
const ivln2hi: f32 = 1.4428710938e+00;
const ivln2lo: f32 = -1.7605285393e-04;
const Lg1: f32 = 0xaaaaaa.0p-24;
const Lg2: f32 = 0xccce13.0p-25;

View File

@ -24,13 +24,13 @@ fn round32(x_: f32) f32 {
const e = (u >> 23) & 0xFF;
var y: f32 = undefined;
if (e >= 0x7F+23) {
if (e >= 0x7F + 23) {
return x;
}
if (u >> 31 != 0) {
x = -x;
}
if (e < 0x7F-1) {
if (e < 0x7F - 1) {
math.forceEval(x + math.f32_toint);
return 0 * @bitCast(f32, u);
}
@ -61,13 +61,13 @@ fn round64(x_: f64) f64 {
const e = (u >> 52) & 0x7FF;
var y: f64 = undefined;
if (e >= 0x3FF+52) {
if (e >= 0x3FF + 52) {
return x;
}
if (u >> 63 != 0) {
x = -x;
}
if (e < 0x3ff-1) {
if (e < 0x3ff - 1) {
math.forceEval(x + math.f64_toint);
return 0 * @bitCast(f64, u);
}

View File

@ -19,20 +19,20 @@ pub fn sin(x: var) @typeOf(x) {
}
// sin polynomial coefficients
const S0 = 1.58962301576546568060E-10;
const S0 = 1.58962301576546568060E-10;
const S1 = -2.50507477628578072866E-8;
const S2 = 2.75573136213857245213E-6;
const S2 = 2.75573136213857245213E-6;
const S3 = -1.98412698295895385996E-4;
const S4 = 8.33333333332211858878E-3;
const S4 = 8.33333333332211858878E-3;
const S5 = -1.66666666666666307295E-1;
// cos polynomial coeffiecients
const C0 = -1.13585365213876817300E-11;
const C1 = 2.08757008419747316778E-9;
const C1 = 2.08757008419747316778E-9;
const C2 = -2.75573141792967388112E-7;
const C3 = 2.48015872888517045348E-5;
const C3 = 2.48015872888517045348E-5;
const C4 = -1.38888888888730564116E-3;
const C5 = 4.16666666666665929218E-2;
const C5 = 4.16666666666665929218E-2;
// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
//

View File

@ -19,12 +19,12 @@ pub fn tan(x: var) @typeOf(x) {
}
const Tp0 = -1.30936939181383777646E4;
const Tp1 = 1.15351664838587416140E6;
const Tp1 = 1.15351664838587416140E6;
const Tp2 = -1.79565251976484877988E7;
const Tq1 = 1.36812963470692954678E4;
const Tq1 = 1.36812963470692954678E4;
const Tq2 = -1.32089234440210967447E6;
const Tq3 = 2.50083801823357915839E7;
const Tq3 = 2.50083801823357915839E7;
const Tq4 = -5.38695755929454629881E7;
// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.

View File

@ -6,14 +6,14 @@ const builtin = @import("builtin");
const mem = this;
pub const Allocator = struct {
const Error = error {OutOfMemory};
const Error = error{OutOfMemory};
/// Allocate byte_count bytes and return them in a slice, with the
/// slice's pointer aligned at least to alignment bytes.
/// The returned newly allocated memory is undefined.
/// `alignment` is guaranteed to be >= 1
/// `alignment` is guaranteed to be a power of 2
allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
allocFn: fn(self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
/// If `new_byte_count > old_mem.len`:
/// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
@ -26,10 +26,10 @@ pub const Allocator = struct {
/// The returned newly allocated memory is undefined.
/// `alignment` is guaranteed to be >= 1
/// `alignment` is guaranteed to be a power of 2
reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
reallocFn: fn(self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
freeFn: fn (self: &Allocator, old_mem: []u8) void,
freeFn: fn(self: &Allocator, old_mem: []u8) void,
fn create(self: &Allocator, comptime T: type) !&T {
if (@sizeOf(T) == 0) return &{};
@ -47,7 +47,7 @@ pub const Allocator = struct {
if (@sizeOf(T) == 0) return &{};
const slice = try self.alloc(T, 1);
const ptr = &slice[0];
*ptr = *init;
ptr.* = init.*;
return ptr;
}
@ -59,9 +59,7 @@ pub const Allocator = struct {
return self.alignedAlloc(T, @alignOf(T), n);
}
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
n: usize) ![]align(alignment) T
{
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
if (n == 0) {
return (&align(alignment) T)(undefined)[0..0];
}
@ -70,7 +68,7 @@ pub const Allocator = struct {
assert(byte_slice.len == byte_count);
// This loop gets optimized out in ReleaseFast mode
for (byte_slice) |*byte| {
*byte = undefined;
byte.* = undefined;
}
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
}
@ -79,9 +77,7 @@ pub const Allocator = struct {
return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
}
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
{
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
if (old_mem.len == 0) {
return self.alloc(T, n);
}
@ -97,7 +93,7 @@ pub const Allocator = struct {
if (n > old_mem.len) {
// This loop gets optimized out in ReleaseFast mode
for (byte_slice[old_byte_slice.len..]) |*byte| {
*byte = undefined;
byte.* = undefined;
}
}
return ([]T)(@alignCast(alignment, byte_slice));
@ -110,9 +106,7 @@ pub const Allocator = struct {
return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
}
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,
old_mem: []align(alignment) T, n: usize) []align(alignment) T
{
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
if (n == 0) {
self.free(old_mem);
return old_mem[0..0];
@ -131,8 +125,7 @@ pub const Allocator = struct {
fn free(self: &Allocator, memory: var) void {
const bytes = ([]const u8)(memory);
if (bytes.len == 0)
return;
if (bytes.len == 0) return;
const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
self.freeFn(self, non_const_ptr[0..bytes.len]);
}
@ -146,11 +139,13 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {
// this and automatically omit safety checks for loops
@setRuntimeSafety(false);
assert(dest.len >= source.len);
for (source) |s, i| dest[i] = s;
for (source) |s, i|
dest[i] = s;
}
pub fn set(comptime T: type, dest: []T, value: T) void {
for (dest) |*d| *d = value;
for (dest) |*d|
d.* = value;
}
/// Returns true if lhs < rhs, false otherwise
@ -229,8 +224,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
var i: usize = slice.len;
while (i != 0) {
i -= 1;
if (slice[i] == value)
return i;
if (slice[i] == value) return i;
}
return null;
}
@ -238,8 +232,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
var i: usize = start_index;
while (i < slice.len) : (i += 1) {
if (slice[i] == value)
return i;
if (slice[i] == value) return i;
}
return null;
}
@ -253,8 +246,7 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
while (i != 0) {
i -= 1;
for (values) |value| {
if (slice[i] == value)
return i;
if (slice[i] == value) return i;
}
}
return null;
@ -264,8 +256,7 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val
var i: usize = start_index;
while (i < slice.len) : (i += 1) {
for (values) |value| {
if (slice[i] == value)
return i;
if (slice[i] == value) return i;
}
}
return null;
@ -279,28 +270,23 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
/// To start looking at a different index, slice the haystack first.
/// TODO is there even a better algorithm for this?
pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
if (needle.len > haystack.len)
return null;
if (needle.len > haystack.len) return null;
var i: usize = haystack.len - needle.len;
while (true) : (i -= 1) {
if (mem.eql(T, haystack[i..i+needle.len], needle))
return i;
if (i == 0)
return null;
if (mem.eql(T, haystack[i..i + needle.len], needle)) return i;
if (i == 0) return null;
}
}
// TODO boyer-moore algorithm
pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
if (needle.len > haystack.len)
return null;
if (needle.len > haystack.len) return null;
var i: usize = start_index;
const end = haystack.len - needle.len;
while (i <= end) : (i += 1) {
if (eql(T, haystack[i .. i + needle.len], needle))
return i;
if (eql(T, haystack[i..i + needle.len], needle)) return i;
}
return null;
}
@ -355,9 +341,12 @@ pub fn readIntBE(comptime T: type, bytes: []const u8) T {
}
assert(bytes.len == @sizeOf(T));
var result: T = 0;
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
result = (result << 8) | T(bytes[i]);
}}
{
comptime var i = 0;
inline while (i < @sizeOf(T)) : (i += 1) {
result = (result << 8) | T(bytes[i]);
}
}
return result;
}
@ -369,9 +358,12 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) T {
}
assert(bytes.len == @sizeOf(T));
var result: T = 0;
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
result |= T(bytes[i]) << i * 8;
}}
{
comptime var i = 0;
inline while (i < @sizeOf(T)) : (i += 1) {
result |= T(bytes[i]) << i * 8;
}
}
return result;
}
@ -393,7 +385,7 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
},
builtin.Endian.Little => {
for (buf) |*b| {
*b = @truncate(u8, bits);
b.* = @truncate(u8, bits);
bits >>= 8;
}
},
@ -401,7 +393,6 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
assert(bits == 0);
}
pub fn hash_slice_u8(k: []const u8) u32 {
// FNV 32-bit hash
var h: u32 = 2166136261;
@ -420,7 +411,7 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
/// split(" abc def ghi ", " ")
/// Will return slices for "abc", "def", "ghi", null, in that order.
pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
return SplitIterator {
return SplitIterator{
.index = 0,
.buffer = buffer,
.split_bytes = split_bytes,
@ -436,7 +427,7 @@ test "mem.split" {
}
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);
return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
}
test "mem.startsWith" {
@ -445,10 +436,9 @@ test "mem.startsWith" {
}
pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len..], needle);
}
test "mem.endsWith" {
assert(endsWith(u8, "Needle in haystack", "haystack"));
assert(!endsWith(u8, "Bob", "Bo"));
@ -542,29 +532,47 @@ test "testReadInt" {
}
fn testReadIntImpl() void {
{
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
assert(readIntBE(u32, bytes) == 0x12345678);
assert(readIntBE(i32, bytes) == 0x12345678);
const bytes = []u8{
0x12,
0x34,
0x56,
0x78,
};
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
assert(readIntBE(u32, bytes) == 0x12345678);
assert(readIntBE(i32, bytes) == 0x12345678);
assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
assert(readIntLE(u32, bytes) == 0x78563412);
assert(readIntLE(i32, bytes) == 0x78563412);
assert(readIntLE(u32, bytes) == 0x78563412);
assert(readIntLE(i32, bytes) == 0x78563412);
}
{
const buf = []u8{0x00, 0x00, 0x12, 0x34};
const buf = []u8{
0x00,
0x00,
0x12,
0x34,
};
const answer = readInt(buf, u64, builtin.Endian.Big);
assert(answer == 0x00001234);
}
{
const buf = []u8{0x12, 0x34, 0x00, 0x00};
const buf = []u8{
0x12,
0x34,
0x00,
0x00,
};
const answer = readInt(buf, u64, builtin.Endian.Little);
assert(answer == 0x00003412);
}
{
const bytes = []u8{0xff, 0xfe};
assert(readIntBE(u16, bytes) == 0xfffe);
const bytes = []u8{
0xff,
0xfe,
};
assert(readIntBE(u16, bytes) == 0xfffe);
assert(readIntBE(i16, bytes) == -0x0002);
assert(readIntLE(u16, bytes) == 0xfeff);
assert(readIntLE(u16, bytes) == 0xfeff);
assert(readIntLE(i16, bytes) == -0x0101);
}
}
@ -577,19 +585,38 @@ fn testWriteIntImpl() void {
var bytes: [4]u8 = undefined;
writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
assert(eql(u8, bytes, []u8{
0x12,
0x34,
0x56,
0x78,
}));
writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
assert(eql(u8, bytes, []u8{
0x12,
0x34,
0x56,
0x78,
}));
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
assert(eql(u8, bytes, []u8{
0x00,
0x00,
0x12,
0x34,
}));
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
assert(eql(u8, bytes, []u8{
0x34,
0x12,
0x00,
0x00,
}));
}
pub fn min(comptime T: type, slice: []const T) T {
var best = slice[0];
for (slice[1..]) |item| {
@ -615,9 +642,9 @@ test "mem.max" {
}
pub fn swap(comptime T: type, a: &T, b: &T) void {
const tmp = *a;
*a = *b;
*b = tmp;
const tmp = a.*;
a.* = b.*;
b.* = tmp;
}
/// In-place order reversal of a slice
@ -630,10 +657,22 @@ pub fn reverse(comptime T: type, items: []T) void {
}
test "std.mem.reverse" {
var arr = []i32{ 5, 3, 1, 2, 4 };
var arr = []i32{
5,
3,
1,
2,
4,
};
reverse(i32, arr[0..]);
assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }));
assert(eql(i32, arr, []i32{
4,
2,
1,
3,
5,
}));
}
/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
@ -645,10 +684,22 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
}
test "std.mem.rotate" {
var arr = []i32{ 5, 3, 1, 2, 4 };
var arr = []i32{
5,
3,
1,
2,
4,
};
rotate(i32, arr[0..], 2);
assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
assert(eql(i32, arr, []i32{
1,
2,
4,
5,
3,
}));
}
// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by

View File

@ -19,37 +19,29 @@ pub const Address = struct {
os_addr: OsAddress,
pub fn initIp4(ip4: u32, port: u16) Address {
return Address {
.os_addr = posix.sockaddr {
.in = posix.sockaddr_in {
.family = posix.AF_INET,
.port = std.mem.endianSwapIfLe(u16, port),
.addr = ip4,
.zero = []u8{0} ** 8,
},
},
};
return Address{ .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{
.family = posix.AF_INET,
.port = std.mem.endianSwapIfLe(u16, port),
.addr = ip4,
.zero = []u8{0} ** 8,
} } };
}
pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
return Address {
return Address{
.family = posix.AF_INET6,
.os_addr = posix.sockaddr {
.in6 = posix.sockaddr_in6 {
.family = posix.AF_INET6,
.port = std.mem.endianSwapIfLe(u16, port),
.flowinfo = 0,
.addr = ip6.addr,
.scope_id = ip6.scope_id,
},
},
.os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{
.family = posix.AF_INET6,
.port = std.mem.endianSwapIfLe(u16, port),
.flowinfo = 0,
.addr = ip6.addr,
.scope_id = ip6.scope_id,
} },
};
}
pub fn initPosix(addr: &const posix.sockaddr) Address {
return Address {
.os_addr = *addr,
};
return Address{ .os_addr = addr.* };
}
pub fn format(self: &const Address, out_stream: var) !void {
@ -98,7 +90,7 @@ pub fn parseIp4(buf: []const u8) !u32 {
}
} else {
return error.InvalidCharacter;
}
}
}
if (index == 3 and saw_any_digits) {
out_ptr[index] = x;

View File

@ -49,7 +49,7 @@ pub const ChildProcess = struct {
err_pipe: if (is_windows) void else [2]i32,
llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
pub const SpawnError = error {
pub const SpawnError = error{
ProcessFdQuotaExceeded,
Unexpected,
NotDir,
@ -88,7 +88,7 @@ pub const ChildProcess = struct {
const child = try allocator.create(ChildProcess);
errdefer allocator.destroy(child);
*child = ChildProcess {
child.* = ChildProcess{
.allocator = allocator,
.argv = argv,
.pid = undefined,
@ -99,8 +99,10 @@ pub const ChildProcess = struct {
.term = null,
.env_map = null,
.cwd = null,
.uid = if (is_windows) {} else null,
.gid = if (is_windows) {} else null,
.uid = if (is_windows) {} else
null,
.gid = if (is_windows) {} else
null,
.stdin = null,
.stdout = null,
.stderr = null,
@ -193,9 +195,7 @@ pub const ChildProcess = struct {
/// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
/// If it succeeds, the caller owns result.stdout and result.stderr memory.
pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
env_map: ?&const BufMap, max_output_size: usize) !ExecResult
{
pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?&const BufMap, max_output_size: usize) !ExecResult {
const child = try ChildProcess.init(argv, allocator);
defer child.deinit();
@ -218,7 +218,7 @@ pub const ChildProcess = struct {
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
return ExecResult {
return ExecResult{
.term = try child.wait(),
.stdout = stdout.toOwnedSlice(),
.stderr = stderr.toOwnedSlice(),
@ -255,9 +255,9 @@ pub const ChildProcess = struct {
self.term = (SpawnError!Term)(x: {
var exit_code: windows.DWORD = undefined;
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
break :x Term { .Unknown = 0 };
break :x Term{ .Unknown = 0 };
} else {
break :x Term { .Exited = @bitCast(i32, exit_code)};
break :x Term{ .Exited = @bitCast(i32, exit_code) };
}
});
@ -288,9 +288,18 @@ pub const ChildProcess = struct {
}
fn cleanupStreams(self: &ChildProcess) void {
if (self.stdin) |*stdin| { stdin.close(); self.stdin = null; }
if (self.stdout) |*stdout| { stdout.close(); self.stdout = null; }
if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
if (self.stdin) |*stdin| {
stdin.close();
self.stdin = null;
}
if (self.stdout) |*stdout| {
stdout.close();
self.stdout = null;
}
if (self.stderr) |*stderr| {
stderr.close();
self.stderr = null;
}
}
fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
@ -317,25 +326,30 @@ pub const ChildProcess = struct {
fn statusToTerm(status: i32) Term {
return if (posix.WIFEXITED(status))
Term { .Exited = posix.WEXITSTATUS(status) }
Term{ .Exited = posix.WEXITSTATUS(status) }
else if (posix.WIFSIGNALED(status))
Term { .Signal = posix.WTERMSIG(status) }
Term{ .Signal = posix.WTERMSIG(status) }
else if (posix.WIFSTOPPED(status))
Term { .Stopped = posix.WSTOPSIG(status) }
Term{ .Stopped = posix.WSTOPSIG(status) }
else
Term { .Unknown = status }
;
Term{ .Unknown = status };
}
fn spawnPosix(self: &ChildProcess) !void {
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
errdefer if (self.stdin_behavior == StdIo.Pipe) {
destroyPipe(stdin_pipe);
};
const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
errdefer if (self.stdout_behavior == StdIo.Pipe) {
destroyPipe(stdout_pipe);
};
const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
errdefer if (self.stderr_behavior == StdIo.Pipe) {
destroyPipe(stderr_pipe);
};
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const dev_null_fd = if (any_ignore) blk: {
@ -346,7 +360,9 @@ pub const ChildProcess = struct {
} else blk: {
break :blk undefined;
};
defer { if (any_ignore) os.close(dev_null_fd); }
defer {
if (any_ignore) os.close(dev_null_fd);
}
var env_map_owned: BufMap = undefined;
var we_own_env_map: bool = undefined;
@ -358,7 +374,9 @@ pub const ChildProcess = struct {
env_map_owned = try os.getEnvMap(self.allocator);
break :x &env_map_owned;
};
defer { if (we_own_env_map) env_map_owned.deinit(); }
defer {
if (we_own_env_map) env_map_owned.deinit();
}
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
@ -369,23 +387,21 @@ pub const ChildProcess = struct {
const pid_err = posix.getErrno(pid_result);
if (pid_err > 0) {
return switch (pid_err) {
posix.EAGAIN, posix.ENOMEM, posix.ENOSYS => error.SystemResources,
posix.EAGAIN,
posix.ENOMEM,
posix.ENOSYS => error.SystemResources,
else => os.unexpectedErrorPosix(pid_err),
};
}
if (pid_result == 0) {
// we are the child
setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch
|err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch
|err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch
|err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
if (self.cwd) |cwd| {
os.changeCurDir(self.allocator, cwd) catch
|err| forkChildErrReport(err_pipe[1], err);
os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err);
}
if (self.gid) |gid| {
@ -396,8 +412,7 @@ pub const ChildProcess = struct {
os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
}
os.posixExecve(self.argv, env_map, self.allocator) catch
|err| forkChildErrReport(err_pipe[1], err);
os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
}
// we are the parent
@ -423,37 +438,41 @@ pub const ChildProcess = struct {
self.llnode = LinkedList(&ChildProcess).Node.init(self);
self.term = null;
if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
if (self.stdin_behavior == StdIo.Pipe) {
os.close(stdin_pipe[0]);
}
if (self.stdout_behavior == StdIo.Pipe) {
os.close(stdout_pipe[1]);
}
if (self.stderr_behavior == StdIo.Pipe) {
os.close(stderr_pipe[1]);
}
}
fn spawnWindows(self: &ChildProcess) !void {
const saAttr = windows.SECURITY_ATTRIBUTES {
const saAttr = windows.SECURITY_ATTRIBUTES{
.nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
.bInheritHandle = windows.TRUE,
.lpSecurityDescriptor = null,
};
const any_ignore = (self.stdin_behavior == StdIo.Ignore or
self.stdout_behavior == StdIo.Ignore or
self.stderr_behavior == StdIo.Ignore);
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const nul_handle = if (any_ignore) blk: {
const nul_file_path = "NUL";
var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
} else blk: {
break :blk undefined;
};
defer { if (any_ignore) os.close(nul_handle); }
defer {
if (any_ignore) os.close(nul_handle);
}
if (any_ignore) {
try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
}
var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
var g_hChildStd_IN_Wr: ?windows.HANDLE = null;
switch (self.stdin_behavior) {
@ -470,7 +489,9 @@ pub const ChildProcess = struct {
g_hChildStd_IN_Rd = null;
},
}
errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr); };
errdefer if (self.stdin_behavior == StdIo.Pipe) {
windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr);
};
var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
@ -488,7 +509,9 @@ pub const ChildProcess = struct {
g_hChildStd_OUT_Wr = null;
},
}
errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr); };
errdefer if (self.stdin_behavior == StdIo.Pipe) {
windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr);
};
var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
@ -506,12 +529,14 @@ pub const ChildProcess = struct {
g_hChildStd_ERR_Wr = null;
},
}
errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };
errdefer if (self.stdin_behavior == StdIo.Pipe) {
windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr);
};
const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
defer self.allocator.free(cmd_line);
var siStartInfo = windows.STARTUPINFOA {
var siStartInfo = windows.STARTUPINFOA{
.cb = @sizeOf(windows.STARTUPINFOA),
.hStdError = g_hChildStd_ERR_Wr,
.hStdOutput = g_hChildStd_OUT_Wr,
@ -534,19 +559,11 @@ pub const ChildProcess = struct {
};
var piProcInfo: windows.PROCESS_INFORMATION = undefined;
const cwd_slice = if (self.cwd) |cwd|
try cstr.addNullByte(self.allocator, cwd)
else
null
;
const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
defer if (cwd_slice) |cwd| self.allocator.free(cwd);
const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
const maybe_envp_buf = if (self.env_map) |env_map|
try os.createWindowsEnvBlock(self.allocator, env_map)
else
null
;
const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
@ -563,11 +580,8 @@ pub const ChildProcess = struct {
};
defer self.allocator.free(app_name);
windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,
&siStartInfo, &piProcInfo) catch |no_path_err|
{
if (no_path_err != error.FileNotFound)
return no_path_err;
windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
if (no_path_err != error.FileNotFound) return no_path_err;
const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
defer self.allocator.free(PATH);
@ -577,9 +591,7 @@ pub const ChildProcess = struct {
const joined_path = try os.path.join(self.allocator, search_path, app_name);
defer self.allocator.free(joined_path);
if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,
&siStartInfo, &piProcInfo)) |_|
{
if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo)) |_| {
break;
} else |err| if (err == error.FileNotFound) {
continue;
@ -609,9 +621,15 @@ pub const ChildProcess = struct {
self.thread_handle = piProcInfo.hThread;
self.term = null;
if (self.stdin_behavior == StdIo.Pipe) { os.close(??g_hChildStd_IN_Rd); }
if (self.stderr_behavior == StdIo.Pipe) { os.close(??g_hChildStd_ERR_Wr); }
if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }
if (self.stdin_behavior == StdIo.Pipe) {
os.close(??g_hChildStd_IN_Rd);
}
if (self.stderr_behavior == StdIo.Pipe) {
os.close(??g_hChildStd_ERR_Wr);
}
if (self.stdout_behavior == StdIo.Pipe) {
os.close(??g_hChildStd_OUT_Wr);
}
}
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
@ -622,18 +640,14 @@ pub const ChildProcess = struct {
StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),
}
}
};
fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,
lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void
{
if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
@ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)
{
fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8, lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void {
if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.FILE_NOT_FOUND, windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
windows.ERROR.FILE_NOT_FOUND,
windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
windows.ERROR.INVALID_PARAMETER => unreachable,
windows.ERROR.INVALID_NAME => error.InvalidName,
else => os.unexpectedErrorWindows(err),
@ -641,9 +655,6 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?
}
}
/// Caller must dealloc.
/// Guarantees a null byte at result[result.len].
fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 {
@ -653,8 +664,7 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
var buf_stream = &io.BufferOutStream.init(&buf).stream;
for (argv) |arg, arg_i| {
if (arg_i != 0)
try buf.appendByte(' ');
if (arg_i != 0) try buf.appendByte(' ');
if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
try buf.append(arg);
continue;
@ -688,7 +698,6 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
if (wr) |h| os.close(h);
}
// TODO: workaround for bug where the `const` from `&const` is dropped when the type is
// a namespace field lookup
const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
@ -717,8 +726,8 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S
try windowsMakePipe(&rd_h, &wr_h, sattr);
errdefer windowsDestroyPipe(rd_h, wr_h);
try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
*rd = rd_h;
*wr = wr_h;
rd.* = rd_h;
wr.* = wr_h;
}
fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
@ -727,8 +736,8 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const
try windowsMakePipe(&rd_h, &wr_h, sattr);
errdefer windowsDestroyPipe(rd_h, wr_h);
try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
*rd = rd_h;
*wr = wr_h;
rd.* = rd_h;
wr.* = wr_h;
}
fn makePipe() ![2]i32 {
@ -736,7 +745,8 @@ fn makePipe() ![2]i32 {
const err = posix.getErrno(posix.pipe(&fds));
if (err > 0) {
return switch (err) {
posix.EMFILE, posix.ENFILE => error.SystemResources,
posix.EMFILE,
posix.ENFILE => error.SystemResources,
else => os.unexpectedErrorPosix(err),
};
}
@ -744,8 +754,8 @@ fn makePipe() ![2]i32 {
}
fn destroyPipe(pipe: &const [2]i32) void {
os.close((*pipe)[0]);
os.close((*pipe)[1]);
os.close((pipe.*)[0]);
os.close((pipe.*)[1]);
}
// Child of fork calls this to report an error to the fork parent.

View File

@ -10,33 +10,56 @@ pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
pub const PROT_NONE = 0x00; /// [MC2] no permissions
pub const PROT_READ = 0x01; /// [MC2] pages can be read
pub const PROT_WRITE = 0x02; /// [MC2] pages can be written
pub const PROT_EXEC = 0x04; /// [MC2] pages can be executed
/// [MC2] no permissions
pub const PROT_NONE = 0x00;
/// [MC2] pages can be read
pub const PROT_READ = 0x01;
/// [MC2] pages can be written
pub const PROT_WRITE = 0x02;
/// [MC2] pages can be executed
pub const PROT_EXEC = 0x04;
pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
pub const MAP_FILE = 0x0000; /// map from file (default)
pub const MAP_FIXED = 0x0010; /// interpret addr exactly
pub const MAP_HASSEMAPHORE = 0x0200; /// region may contain semaphores
pub const MAP_PRIVATE = 0x0002; /// changes are private
pub const MAP_SHARED = 0x0001; /// share changes
pub const MAP_NOCACHE = 0x0400; /// don't cache pages for this mapping
pub const MAP_NORESERVE = 0x0040; /// don't reserve needed swap area
/// allocated from memory, swap space
pub const MAP_ANONYMOUS = 0x1000;
/// map from file (default)
pub const MAP_FILE = 0x0000;
/// interpret addr exactly
pub const MAP_FIXED = 0x0010;
/// region may contain semaphores
pub const MAP_HASSEMAPHORE = 0x0200;
/// changes are private
pub const MAP_PRIVATE = 0x0002;
/// share changes
pub const MAP_SHARED = 0x0001;
/// don't cache pages for this mapping
pub const MAP_NOCACHE = 0x0400;
/// don't reserve needed swap area
pub const MAP_NORESERVE = 0x0040;
pub const MAP_FAILED = @maxValue(usize);
pub const WNOHANG = 0x00000001; /// [XSI] no hang in wait/no child to reap
pub const WUNTRACED = 0x00000002; /// [XSI] notify on stop, untraced child
/// [XSI] no hang in wait/no child to reap
pub const WNOHANG = 0x00000001;
/// [XSI] notify on stop, untraced child
pub const WUNTRACED = 0x00000002;
pub const SA_ONSTACK = 0x0001; /// take signal on signal stack
pub const SA_RESTART = 0x0002; /// restart system on signal return
pub const SA_RESETHAND = 0x0004; /// reset to SIG_DFL when taking signal
pub const SA_NOCLDSTOP = 0x0008; /// do not generate SIGCHLD on child stop
pub const SA_NODEFER = 0x0010; /// don't mask the signal we're delivering
pub const SA_NOCLDWAIT = 0x0020; /// don't keep zombies around
pub const SA_SIGINFO = 0x0040; /// signal handler with SA_SIGINFO args
pub const SA_USERTRAMP = 0x0100; /// do not bounce off kernel's sigtramp
pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64bit regs information
/// take signal on signal stack
pub const SA_ONSTACK = 0x0001;
/// restart system on signal return
pub const SA_RESTART = 0x0002;
/// reset to SIG_DFL when taking signal
pub const SA_RESETHAND = 0x0004;
/// do not generate SIGCHLD on child stop
pub const SA_NOCLDSTOP = 0x0008;
/// don't mask the signal we're delivering
pub const SA_NODEFER = 0x0010;
/// don't keep zombies around
pub const SA_NOCLDWAIT = 0x0020;
/// signal handler with SA_SIGINFO args
pub const SA_SIGINFO = 0x0040;
/// do not bounce off kernel's sigtramp
pub const SA_USERTRAMP = 0x0100;
/// signal handler with SA_SIGINFO args with 64bit regs information
pub const SA_64REGSET = 0x0200;
pub const O_LARGEFILE = 0x0000;
pub const O_PATH = 0x0000;
@ -46,20 +69,34 @@ pub const X_OK = 1;
pub const W_OK = 2;
pub const R_OK = 4;
pub const O_RDONLY = 0x0000; /// open for reading only
pub const O_WRONLY = 0x0001; /// open for writing only
pub const O_RDWR = 0x0002; /// open for reading and writing
pub const O_NONBLOCK = 0x0004; /// do not block on open or for data to become available
pub const O_APPEND = 0x0008; /// append on each write
pub const O_CREAT = 0x0200; /// create file if it does not exist
pub const O_TRUNC = 0x0400; /// truncate size to 0
pub const O_EXCL = 0x0800; /// error if O_CREAT and the file exists
pub const O_SHLOCK = 0x0010; /// atomically obtain a shared lock
pub const O_EXLOCK = 0x0020; /// atomically obtain an exclusive lock
pub const O_NOFOLLOW = 0x0100; /// do not follow symlinks
pub const O_SYMLINK = 0x200000; /// allow open of symlinks
pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
/// open for reading only
pub const O_RDONLY = 0x0000;
/// open for writing only
pub const O_WRONLY = 0x0001;
/// open for reading and writing
pub const O_RDWR = 0x0002;
/// do not block on open or for data to become available
pub const O_NONBLOCK = 0x0004;
/// append on each write
pub const O_APPEND = 0x0008;
/// create file if it does not exist
pub const O_CREAT = 0x0200;
/// truncate size to 0
pub const O_TRUNC = 0x0400;
/// error if O_CREAT and the file exists
pub const O_EXCL = 0x0800;
/// atomically obtain a shared lock
pub const O_SHLOCK = 0x0010;
/// atomically obtain an exclusive lock
pub const O_EXLOCK = 0x0020;
/// do not follow symlinks
pub const O_NOFOLLOW = 0x0100;
/// allow open of symlinks
pub const O_SYMLINK = 0x200000;
/// descriptor requested for event notifications only
pub const O_EVTONLY = 0x8000;
/// mark as close-on-exec
pub const O_CLOEXEC = 0x1000000;
pub const O_ACCMODE = 3;
pub const O_ALERT = 536870912;
@ -87,52 +124,102 @@ pub const DT_LNK = 10;
pub const DT_SOCK = 12;
pub const DT_WHT = 14;
pub const SIG_BLOCK = 1; /// block specified signal set
pub const SIG_UNBLOCK = 2; /// unblock specified signal set
pub const SIG_SETMASK = 3; /// set specified signal set
/// block specified signal set
pub const SIG_BLOCK = 1;
/// unblock specified signal set
pub const SIG_UNBLOCK = 2;
/// set specified signal set
pub const SIG_SETMASK = 3;
pub const SIGHUP = 1; /// hangup
pub const SIGINT = 2; /// interrupt
pub const SIGQUIT = 3; /// quit
pub const SIGILL = 4; /// illegal instruction (not reset when caught)
pub const SIGTRAP = 5; /// trace trap (not reset when caught)
pub const SIGABRT = 6; /// abort()
pub const SIGPOLL = 7; /// pollable event ([XSR] generated, not supported)
pub const SIGIOT = SIGABRT; /// compatibility
pub const SIGEMT = 7; /// EMT instruction
pub const SIGFPE = 8; /// floating point exception
pub const SIGKILL = 9; /// kill (cannot be caught or ignored)
pub const SIGBUS = 10; /// bus error
pub const SIGSEGV = 11; /// segmentation violation
pub const SIGSYS = 12; /// bad argument to system call
pub const SIGPIPE = 13; /// write on a pipe with no one to read it
pub const SIGALRM = 14; /// alarm clock
pub const SIGTERM = 15; /// software termination signal from kill
pub const SIGURG = 16; /// urgent condition on IO channel
pub const SIGSTOP = 17; /// sendable stop signal not from tty
pub const SIGTSTP = 18; /// stop signal from tty
pub const SIGCONT = 19; /// continue a stopped process
pub const SIGCHLD = 20; /// to parent on child stop or exit
pub const SIGTTIN = 21; /// to readers pgrp upon background tty read
pub const SIGTTOU = 22; /// like TTIN for output if (tp->t_local&LTOSTOP)
pub const SIGIO = 23; /// input/output possible signal
pub const SIGXCPU = 24; /// exceeded CPU time limit
pub const SIGXFSZ = 25; /// exceeded file size limit
pub const SIGVTALRM = 26; /// virtual time alarm
pub const SIGPROF = 27; /// profiling time alarm
pub const SIGWINCH = 28; /// window size changes
pub const SIGINFO = 29; /// information request
pub const SIGUSR1 = 30; /// user defined signal 1
pub const SIGUSR2 = 31; /// user defined signal 2
/// hangup
pub const SIGHUP = 1;
/// interrupt
pub const SIGINT = 2;
/// quit
pub const SIGQUIT = 3;
/// illegal instruction (not reset when caught)
pub const SIGILL = 4;
/// trace trap (not reset when caught)
pub const SIGTRAP = 5;
/// abort()
pub const SIGABRT = 6;
/// pollable event ([XSR] generated, not supported)
pub const SIGPOLL = 7;
/// compatibility
pub const SIGIOT = SIGABRT;
/// EMT instruction
pub const SIGEMT = 7;
/// floating point exception
pub const SIGFPE = 8;
/// kill (cannot be caught or ignored)
pub const SIGKILL = 9;
/// bus error
pub const SIGBUS = 10;
/// segmentation violation
pub const SIGSEGV = 11;
/// bad argument to system call
pub const SIGSYS = 12;
/// write on a pipe with no one to read it
pub const SIGPIPE = 13;
/// alarm clock
pub const SIGALRM = 14;
/// software termination signal from kill
pub const SIGTERM = 15;
/// urgent condition on IO channel
pub const SIGURG = 16;
/// sendable stop signal not from tty
pub const SIGSTOP = 17;
/// stop signal from tty
pub const SIGTSTP = 18;
/// continue a stopped process
pub const SIGCONT = 19;
/// to parent on child stop or exit
pub const SIGCHLD = 20;
/// to readers pgrp upon background tty read
pub const SIGTTIN = 21;
/// like TTIN for output if (tp->t_local&LTOSTOP)
pub const SIGTTOU = 22;
/// input/output possible signal
pub const SIGIO = 23;
/// exceeded CPU time limit
pub const SIGXCPU = 24;
/// exceeded file size limit
pub const SIGXFSZ = 25;
/// virtual time alarm
pub const SIGVTALRM = 26;
/// profiling time alarm
pub const SIGPROF = 27;
/// window size changes
pub const SIGWINCH = 28;
/// information request
pub const SIGINFO = 29;
/// user defined signal 1
pub const SIGUSR1 = 30;
/// user defined signal 2
pub const SIGUSR2 = 31;
fn wstatus(x: i32) i32 { return x & 0o177; }
fn wstatus(x: i32) i32 {
return x & 0o177;
}
const wstopped = 0o177;
pub fn WEXITSTATUS(x: i32) i32 { return x >> 8; }
pub fn WTERMSIG(x: i32) i32 { return wstatus(x); }
pub fn WSTOPSIG(x: i32) i32 { return x >> 8; }
pub fn WIFEXITED(x: i32) bool { return wstatus(x) == 0; }
pub fn WIFSTOPPED(x: i32) bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
pub fn WIFSIGNALED(x: i32) bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
pub fn WEXITSTATUS(x: i32) i32 {
return x >> 8;
}
pub fn WTERMSIG(x: i32) i32 {
return wstatus(x);
}
pub fn WSTOPSIG(x: i32) i32 {
return x >> 8;
}
pub fn WIFEXITED(x: i32) bool {
return wstatus(x) == 0;
}
pub fn WIFSTOPPED(x: i32) bool {
return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
}
pub fn WIFSIGNALED(x: i32) bool {
return wstatus(x) != wstopped and wstatus(x) != 0;
}
/// Get the errno from a syscall return value, or 0 for no error.
pub fn getErrno(r: usize) usize {
@ -184,11 +271,8 @@ pub fn write(fd: i32, buf: &const u8, nbyte: usize) usize {
return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));
}
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32,
offset: isize) usize
{
const ptr_result = c.mmap(@ptrCast(&c_void, address), length,
@bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
const ptr_result = c.mmap(@ptrCast(&c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
return errnoWrap(isize_result);
}
@ -202,7 +286,7 @@ pub fn unlink(path: &const u8) usize {
}
pub fn getcwd(buf: &u8, size: usize) usize {
return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
}
pub fn waitpid(pid: i32, status: &i32, options: u32) usize {
@ -223,7 +307,6 @@ pub fn pipe(fds: &[2]i32) usize {
return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
}
pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
}
@ -269,7 +352,7 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
}
pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) usize {
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
}
pub fn setreuid(ruid: u32, euid: u32) usize {
@ -287,8 +370,8 @@ pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&s
pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
assert(sig != SIGKILL);
assert(sig != SIGSTOP);
var cact = c.Sigaction {
.handler = @ptrCast(extern fn(c_int)void, act.handler),
var cact = c.Sigaction{
.handler = @ptrCast(extern fn(c_int) void, act.handler),
.sa_flags = @bitCast(c_int, act.flags),
.sa_mask = act.mask,
};
@ -298,8 +381,8 @@ pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigacti
return result;
}
if (oact) |old| {
*old = Sigaction {
.handler = @ptrCast(extern fn(i32)void, coact.handler),
old.* = Sigaction{
.handler = @ptrCast(extern fn(i32) void, coact.handler),
.flags = @bitCast(u32, coact.sa_flags),
.mask = coact.sa_mask,
};
@ -319,23 +402,22 @@ pub const sockaddr = c.sockaddr;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = struct {
handler: extern fn(i32)void,
handler: extern fn(i32) void,
mask: sigset_t,
flags: u32,
};
pub fn sigaddset(set: &sigset_t, signo: u5) void {
*set |= u32(1) << (signo - 1);
set.* |= u32(1) << (signo - 1);
}
/// Takes the return value from a syscall and formats it back in the way
/// that the kernel represents it to libc. Errno was a mistake, let's make
/// it go away forever.
fn errnoWrap(value: isize) usize {
return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
}
pub const timezone = c.timezone;
pub const timeval = c.timeval;
pub const mach_timebase_info_data = c.mach_timebase_info_data;

View File

@ -137,7 +137,7 @@ pub fn getRandomBytes(buf: []u8) !void {
}
},
Os.zen => {
const randomness = []u8 {
const randomness = []u8{
42,
1,
7,
@ -265,7 +265,7 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
}
}
pub const PosixWriteError = error {
pub const PosixWriteError = error{
WouldBlock,
FileClosed,
DestinationAddressRequired,
@ -310,7 +310,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
}
}
pub const PosixOpenError = error {
pub const PosixOpenError = error{
OutOfMemory,
AccessDenied,
FileTooBig,
@ -477,7 +477,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, allocator:
return posixExecveErrnoToErr(err);
}
pub const PosixExecveError = error {
pub const PosixExecveError = error{
SystemResources,
AccessDenied,
InvalidExe,
@ -512,7 +512,7 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {
};
}
pub var linux_aux_raw = []usize {0} ** 38;
pub var linux_aux_raw = []usize{0} ** 38;
pub var posix_environ_raw: []&u8 = undefined;
/// Caller must free result when done.
@ -667,7 +667,7 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
}
}
pub const WindowsSymLinkError = error {
pub const WindowsSymLinkError = error{
OutOfMemory,
Unexpected,
};
@ -686,7 +686,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path
}
}
pub const PosixSymLinkError = error {
pub const PosixSymLinkError = error{
OutOfMemory,
AccessDenied,
DiskQuota,
@ -895,7 +895,7 @@ pub const AtomicFile = struct {
else => return err,
};
return AtomicFile {
return AtomicFile{
.allocator = allocator,
.file = file,
.tmp_path = tmp_path,
@ -1087,7 +1087,7 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
/// removes it. If it cannot be removed because it is a non-empty directory,
/// this function recursively removes its entries and then tries again.
/// TODO non-recursive implementation
const DeleteTreeError = error {
const DeleteTreeError = error{
OutOfMemory,
AccessDenied,
FileTooBig,
@ -1217,7 +1217,7 @@ pub const Dir = struct {
Os.ios => 0,
else => {},
};
return Dir {
return Dir{
.allocator = allocator,
.fd = fd,
.darwin_seek = darwin_seek_init,
@ -1294,7 +1294,7 @@ pub const Dir = struct {
posix.DT_WHT => Entry.Kind.Whiteout,
else => Entry.Kind.Unknown,
};
return Entry {
return Entry{
.name = name,
.kind = entry_kind,
};
@ -1355,7 +1355,7 @@ pub const Dir = struct {
posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
else => Entry.Kind.Unknown,
};
return Entry {
return Entry{
.name = name,
.kind = entry_kind,
};
@ -1465,7 +1465,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) !void {
};
}
pub const WindowsGetStdHandleErrs = error {
pub const WindowsGetStdHandleErrs = error{
NoStdHandles,
Unexpected,
};
@ -1489,7 +1489,7 @@ pub const ArgIteratorPosix = struct {
count: usize,
pub fn init() ArgIteratorPosix {
return ArgIteratorPosix {
return ArgIteratorPosix{
.index = 0,
.count = raw.len,
};
@ -1522,16 +1522,14 @@ pub const ArgIteratorWindows = struct {
quote_count: usize,
seen_quote_count: usize,
pub const NextError = error {
OutOfMemory,
};
pub const NextError = error{OutOfMemory};
pub fn init() ArgIteratorWindows {
return initWithCmdLine(windows.GetCommandLineA());
}
pub fn initWithCmdLine(cmd_line: &const u8) ArgIteratorWindows {
return ArgIteratorWindows {
return ArgIteratorWindows{
.index = 0,
.cmd_line = cmd_line,
.in_quote = false,
@ -1676,9 +1674,7 @@ pub const ArgIterator = struct {
inner: InnerType,
pub fn init() ArgIterator {
return ArgIterator {
.inner = InnerType.init(),
};
return ArgIterator{ .inner = InnerType.init() };
}
pub const NextError = ArgIteratorWindows.NextError;
@ -1757,33 +1753,33 @@ pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) void {
}
test "windows arg parsing" {
testWindowsCmdLine(c"a b\tc d", [][]const u8 {
testWindowsCmdLine(c"a b\tc d", [][]const u8{
"a",
"b",
"c",
"d",
});
testWindowsCmdLine(c"\"abc\" d e", [][]const u8 {
testWindowsCmdLine(c"\"abc\" d e", [][]const u8{
"abc",
"d",
"e",
});
testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8 {
testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{
"a\\\\\\b",
"de fg",
"h",
});
testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8 {
testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{
"a\\\"b",
"c",
"d",
});
testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8 {
testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{
"a\\\\b c",
"d",
"e",
});
testWindowsCmdLine(c"a b\tc \"d f", [][]const u8 {
testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{
"a",
"b",
"c",
@ -1791,7 +1787,7 @@ test "windows arg parsing" {
"f",
});
testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8 {
testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
".\\..\\zig-cache\\build",
"bin\\zig.exe",
".\\..",
@ -1811,7 +1807,7 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
// TODO make this a build variable that you can set
const unexpected_error_tracing = false;
const UnexpectedError = error {
const UnexpectedError = error{
/// The Operating System returned an undocumented error code.
Unexpected,
};
@ -1950,7 +1946,7 @@ pub fn isTty(handle: FileHandle) bool {
}
}
pub const PosixSocketError = error {
pub const PosixSocketError = error{
/// Permission to create a socket of the specified type and/or
/// protocol is denied.
PermissionDenied,
@ -1992,7 +1988,7 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
}
}
pub const PosixBindError = error {
pub const PosixBindError = error{
/// The address is protected, and the user is not the superuser.
/// For UNIX domain sockets: Search permission is denied on a component
/// of the path prefix.
@ -2065,7 +2061,7 @@ pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
}
}
const PosixListenError = error {
const PosixListenError = error{
/// Another socket is already listening on the same port.
/// For Internet domain sockets, the socket referred to by sockfd had not previously
/// been bound to an address and, upon attempting to bind it to an ephemeral port, it
@ -2098,7 +2094,7 @@ pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
}
}
pub const PosixAcceptError = error {
pub const PosixAcceptError = error{
/// The socket is marked nonblocking and no connections are present to be accepted.
WouldBlock,
@ -2165,7 +2161,7 @@ pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!
}
}
pub const LinuxEpollCreateError = error {
pub const LinuxEpollCreateError = error{
/// Invalid value specified in flags.
InvalidSyscall,
@ -2198,7 +2194,7 @@ pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
}
}
pub const LinuxEpollCtlError = error {
pub const LinuxEpollCtlError = error{
/// epfd or fd is not a valid file descriptor.
InvalidFileDescriptor,
@ -2271,7 +2267,7 @@ pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usiz
}
}
pub const PosixGetSockNameError = error {
pub const PosixGetSockNameError = error{
/// Insufficient resources were available in the system to perform the operation.
SystemResources,
@ -2295,7 +2291,7 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
}
}
pub const PosixConnectError = error {
pub const PosixConnectError = error{
/// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
/// file, or search permission is denied for one of the directories in the path prefix.
/// or
@ -2485,7 +2481,7 @@ pub const Thread = struct {
}
};
pub const SpawnThreadError = error {
pub const SpawnThreadError = error{
/// A system-imposed limit on the number of threads was encountered.
/// There are a number of limits that may trigger this error:
/// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
@ -2533,7 +2529,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
if (@sizeOf(Context) == 0) {
return startFn({});
} else {
return startFn(*@ptrCast(&Context, @alignCast(@alignOf(Context), arg)));
return startFn(@ptrCast(&Context, @alignCast(@alignOf(Context), arg)).*);
}
}
};
@ -2563,7 +2559,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
if (@sizeOf(Context) == 0) {
return startFn({});
} else {
return startFn(*@intToPtr(&const Context, ctx_addr));
return startFn(@intToPtr(&const Context, ctx_addr).*);
}
}
extern fn posixThreadMain(ctx: ?&c_void) ?&c_void {
@ -2571,7 +2567,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
_ = startFn({});
return null;
} else {
_ = startFn(*@ptrCast(&const Context, @alignCast(@alignOf(Context), ctx)));
_ = startFn(@ptrCast(&const Context, @alignCast(@alignOf(Context), ctx)).*);
return null;
}
}
@ -2591,7 +2587,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
stack_end -= stack_end % @alignOf(Context);
assert(stack_end >= stack_addr);
const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end));
*context_ptr = context;
context_ptr.* = context;
arg = stack_end;
}

View File

@ -30,96 +30,95 @@ pub const FUTEX_PRIVATE_FLAG = 128;
pub const FUTEX_CLOCK_REALTIME = 256;
pub const PROT_NONE = 0;
pub const PROT_READ = 1;
pub const PROT_WRITE = 2;
pub const PROT_EXEC = 4;
pub const PROT_NONE = 0;
pub const PROT_READ = 1;
pub const PROT_WRITE = 2;
pub const PROT_EXEC = 4;
pub const PROT_GROWSDOWN = 0x01000000;
pub const PROT_GROWSUP = 0x02000000;
pub const PROT_GROWSUP = 0x02000000;
pub const MAP_FAILED = @maxValue(usize);
pub const MAP_SHARED = 0x01;
pub const MAP_PRIVATE = 0x02;
pub const MAP_TYPE = 0x0f;
pub const MAP_FIXED = 0x10;
pub const MAP_ANONYMOUS = 0x20;
pub const MAP_NORESERVE = 0x4000;
pub const MAP_GROWSDOWN = 0x0100;
pub const MAP_DENYWRITE = 0x0800;
pub const MAP_FAILED = @maxValue(usize);
pub const MAP_SHARED = 0x01;
pub const MAP_PRIVATE = 0x02;
pub const MAP_TYPE = 0x0f;
pub const MAP_FIXED = 0x10;
pub const MAP_ANONYMOUS = 0x20;
pub const MAP_NORESERVE = 0x4000;
pub const MAP_GROWSDOWN = 0x0100;
pub const MAP_DENYWRITE = 0x0800;
pub const MAP_EXECUTABLE = 0x1000;
pub const MAP_LOCKED = 0x2000;
pub const MAP_POPULATE = 0x8000;
pub const MAP_NONBLOCK = 0x10000;
pub const MAP_STACK = 0x20000;
pub const MAP_HUGETLB = 0x40000;
pub const MAP_FILE = 0;
pub const MAP_LOCKED = 0x2000;
pub const MAP_POPULATE = 0x8000;
pub const MAP_NONBLOCK = 0x10000;
pub const MAP_STACK = 0x20000;
pub const MAP_HUGETLB = 0x40000;
pub const MAP_FILE = 0;
pub const F_OK = 0;
pub const X_OK = 1;
pub const W_OK = 2;
pub const R_OK = 4;
pub const WNOHANG = 1;
pub const WUNTRACED = 2;
pub const WSTOPPED = 2;
pub const WEXITED = 4;
pub const WNOHANG = 1;
pub const WUNTRACED = 2;
pub const WSTOPPED = 2;
pub const WEXITED = 4;
pub const WCONTINUED = 8;
pub const WNOWAIT = 0x1000000;
pub const WNOWAIT = 0x1000000;
pub const SA_NOCLDSTOP = 1;
pub const SA_NOCLDWAIT = 2;
pub const SA_SIGINFO = 4;
pub const SA_ONSTACK = 0x08000000;
pub const SA_RESTART = 0x10000000;
pub const SA_NODEFER = 0x40000000;
pub const SA_RESETHAND = 0x80000000;
pub const SA_RESTORER = 0x04000000;
pub const SA_NOCLDSTOP = 1;
pub const SA_NOCLDWAIT = 2;
pub const SA_SIGINFO = 4;
pub const SA_ONSTACK = 0x08000000;
pub const SA_RESTART = 0x10000000;
pub const SA_NODEFER = 0x40000000;
pub const SA_RESETHAND = 0x80000000;
pub const SA_RESTORER = 0x04000000;
pub const SIGHUP = 1;
pub const SIGINT = 2;
pub const SIGQUIT = 3;
pub const SIGILL = 4;
pub const SIGTRAP = 5;
pub const SIGABRT = 6;
pub const SIGIOT = SIGABRT;
pub const SIGBUS = 7;
pub const SIGFPE = 8;
pub const SIGKILL = 9;
pub const SIGUSR1 = 10;
pub const SIGSEGV = 11;
pub const SIGUSR2 = 12;
pub const SIGPIPE = 13;
pub const SIGALRM = 14;
pub const SIGTERM = 15;
pub const SIGHUP = 1;
pub const SIGINT = 2;
pub const SIGQUIT = 3;
pub const SIGILL = 4;
pub const SIGTRAP = 5;
pub const SIGABRT = 6;
pub const SIGIOT = SIGABRT;
pub const SIGBUS = 7;
pub const SIGFPE = 8;
pub const SIGKILL = 9;
pub const SIGUSR1 = 10;
pub const SIGSEGV = 11;
pub const SIGUSR2 = 12;
pub const SIGPIPE = 13;
pub const SIGALRM = 14;
pub const SIGTERM = 15;
pub const SIGSTKFLT = 16;
pub const SIGCHLD = 17;
pub const SIGCONT = 18;
pub const SIGSTOP = 19;
pub const SIGTSTP = 20;
pub const SIGTTIN = 21;
pub const SIGTTOU = 22;
pub const SIGURG = 23;
pub const SIGXCPU = 24;
pub const SIGXFSZ = 25;
pub const SIGCHLD = 17;
pub const SIGCONT = 18;
pub const SIGSTOP = 19;
pub const SIGTSTP = 20;
pub const SIGTTIN = 21;
pub const SIGTTOU = 22;
pub const SIGURG = 23;
pub const SIGXCPU = 24;
pub const SIGXFSZ = 25;
pub const SIGVTALRM = 26;
pub const SIGPROF = 27;
pub const SIGWINCH = 28;
pub const SIGIO = 29;
pub const SIGPOLL = 29;
pub const SIGPWR = 30;
pub const SIGSYS = 31;
pub const SIGPROF = 27;
pub const SIGWINCH = 28;
pub const SIGIO = 29;
pub const SIGPOLL = 29;
pub const SIGPWR = 30;
pub const SIGSYS = 31;
pub const SIGUNUSED = SIGSYS;
pub const O_RDONLY = 0o0;
pub const O_WRONLY = 0o1;
pub const O_RDWR = 0o2;
pub const O_RDWR = 0o2;
pub const SEEK_SET = 0;
pub const SEEK_CUR = 1;
pub const SEEK_END = 2;
pub const SIG_BLOCK = 0;
pub const SIG_BLOCK = 0;
pub const SIG_UNBLOCK = 1;
pub const SIG_SETMASK = 2;
@ -408,7 +407,6 @@ pub const DT_LNK = 10;
pub const DT_SOCK = 12;
pub const DT_WHT = 14;
pub const TCGETS = 0x5401;
pub const TCSETS = 0x5402;
pub const TCSETSW = 0x5403;
@ -539,23 +537,23 @@ pub const MS_BIND = 4096;
pub const MS_MOVE = 8192;
pub const MS_REC = 16384;
pub const MS_SILENT = 32768;
pub const MS_POSIXACL = (1<<16);
pub const MS_UNBINDABLE = (1<<17);
pub const MS_PRIVATE = (1<<18);
pub const MS_SLAVE = (1<<19);
pub const MS_SHARED = (1<<20);
pub const MS_RELATIME = (1<<21);
pub const MS_KERNMOUNT = (1<<22);
pub const MS_I_VERSION = (1<<23);
pub const MS_STRICTATIME = (1<<24);
pub const MS_LAZYTIME = (1<<25);
pub const MS_NOREMOTELOCK = (1<<27);
pub const MS_NOSEC = (1<<28);
pub const MS_BORN = (1<<29);
pub const MS_ACTIVE = (1<<30);
pub const MS_NOUSER = (1<<31);
pub const MS_POSIXACL = (1 << 16);
pub const MS_UNBINDABLE = (1 << 17);
pub const MS_PRIVATE = (1 << 18);
pub const MS_SLAVE = (1 << 19);
pub const MS_SHARED = (1 << 20);
pub const MS_RELATIME = (1 << 21);
pub const MS_KERNMOUNT = (1 << 22);
pub const MS_I_VERSION = (1 << 23);
pub const MS_STRICTATIME = (1 << 24);
pub const MS_LAZYTIME = (1 << 25);
pub const MS_NOREMOTELOCK = (1 << 27);
pub const MS_NOSEC = (1 << 28);
pub const MS_BORN = (1 << 29);
pub const MS_ACTIVE = (1 << 30);
pub const MS_NOUSER = (1 << 31);
pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME);
pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
pub const MS_MGC_VAL = 0xc0ed0000;
pub const MS_MGC_MSK = 0xffff0000;
@ -565,7 +563,6 @@ pub const MNT_DETACH = 2;
pub const MNT_EXPIRE = 4;
pub const UMOUNT_NOFOLLOW = 8;
pub const S_IFMT = 0o170000;
pub const S_IFDIR = 0o040000;
@ -626,15 +623,30 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
pub const TFD_TIMER_ABSTIME = 1;
pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
fn unsigned(s: i32) u32 { return @bitCast(u32, s); }
fn signed(s: u32) i32 { return @bitCast(i32, s); }
pub fn WEXITSTATUS(s: i32) i32 { return signed((unsigned(s) & 0xff00) >> 8); }
pub fn WTERMSIG(s: i32) i32 { return signed(unsigned(s) & 0x7f); }
pub fn WSTOPSIG(s: i32) i32 { return WEXITSTATUS(s); }
pub fn WIFEXITED(s: i32) bool { return WTERMSIG(s) == 0; }
pub fn WIFSTOPPED(s: i32) bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
fn unsigned(s: i32) u32 {
return @bitCast(u32, s);
}
fn signed(s: u32) i32 {
return @bitCast(i32, s);
}
pub fn WEXITSTATUS(s: i32) i32 {
return signed((unsigned(s) & 0xff00) >> 8);
}
pub fn WTERMSIG(s: i32) i32 {
return signed(unsigned(s) & 0x7f);
}
pub fn WSTOPSIG(s: i32) i32 {
return WEXITSTATUS(s);
}
pub fn WIFEXITED(s: i32) bool {
return WTERMSIG(s) == 0;
}
pub fn WIFSTOPPED(s: i32) bool {
return (u16)(((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
}
pub fn WIFSIGNALED(s: i32) bool {
return (unsigned(s) & 0xffff) -% 1 < 0xff;
}
pub const winsize = extern struct {
ws_row: u16,
@ -707,8 +719,7 @@ pub fn umount2(special: &const u8, flags: u32) usize {
}
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
@bitCast(usize, offset));
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), @bitCast(usize, offset));
}
pub fn munmap(address: usize, length: usize) usize {
@ -812,7 +823,8 @@ pub fn clock_gettime(clk_id: i32, tp: &timespec) usize {
if (@ptrToInt(f) != 0) {
const rc = f(clk_id, tp);
switch (rc) {
0, @bitCast(usize, isize(-EINVAL)) => return rc,
0,
@bitCast(usize, isize(-EINVAL)) => return rc,
else => {},
}
}
@ -823,8 +835,7 @@ var vdso_clock_gettime = init_vdso_clock_gettime;
extern fn init_vdso_clock_gettime(clk: i32, ts: &timespec) usize {
const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
_ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f,
builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
_ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
return f(clk, ts);
}
@ -918,18 +929,18 @@ pub fn getpid() i32 {
}
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
}
pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
assert(sig >= 1);
assert(sig != SIGKILL);
assert(sig != SIGSTOP);
var ksa = k_sigaction {
var ksa = k_sigaction{
.handler = act.handler,
.flags = act.flags | SA_RESTORER,
.mask = undefined,
.restorer = @ptrCast(extern fn()void, restore_rt),
.restorer = @ptrCast(extern fn() void, restore_rt),
};
var ksa_old: k_sigaction = undefined;
@memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);
@ -952,22 +963,22 @@ const all_mask = []usize{@maxValue(usize)};
const app_mask = []usize{0xfffffffc7fffffff};
const k_sigaction = extern struct {
handler: extern fn(i32)void,
handler: extern fn(i32) void,
flags: usize,
restorer: extern fn()void,
restorer: extern fn() void,
mask: [2]u32,
};
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = struct {
handler: extern fn(i32)void,
handler: extern fn(i32) void,
mask: sigset_t,
flags: u32,
};
pub const SIG_ERR = @intToPtr(extern fn(i32)void, @maxValue(usize));
pub const SIG_DFL = @intToPtr(extern fn(i32)void, 0);
pub const SIG_IGN = @intToPtr(extern fn(i32)void, 1);
pub const SIG_ERR = @intToPtr(extern fn(i32) void, @maxValue(usize));
pub const SIG_DFL = @intToPtr(extern fn(i32) void, 0);
pub const SIG_IGN = @intToPtr(extern fn(i32) void, 1);
pub const empty_sigset = []usize{0} ** sigset_t.len;
pub fn raise(sig: i32) usize {
@ -980,25 +991,25 @@ pub fn raise(sig: i32) usize {
}
fn blockAllSignals(set: &sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
}
fn blockAppSignals(set: &sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
}
fn restoreSignals(set: &sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);
_ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
}
pub fn sigaddset(set: &sigset_t, sig: u6) void {
const s = sig - 1;
(*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1));
(set.*)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1));
}
pub fn sigismember(set: &const sigset_t, sig: u6) bool {
const s = sig - 1;
return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
return ((set.*)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
}
pub const in_port_t = u16;
@ -1062,9 +1073,7 @@ pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
}
pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize
{
pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize {
return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
}
@ -1132,25 +1141,16 @@ pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {
return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
}
pub fn setxattr(path: &const u8, name: &const u8, value: &const void,
size: usize, flags: usize) usize {
return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
size, flags);
pub fn setxattr(path: &const u8, name: &const u8, value: &const void, size: usize, flags: usize) usize {
return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
}
pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void,
size: usize, flags: usize) usize {
return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
size, flags);
pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void, size: usize, flags: usize) usize {
return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
}
pub fn fsetxattr(fd: usize, name: &const u8, value: &const void,
size: usize, flags: usize) usize {
return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value),
size, flags);
pub fn fsetxattr(fd: usize, name: &const u8, value: &const void, size: usize, flags: usize) usize {
return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
}
pub fn removexattr(path: &const u8, name: &const u8) usize {
@ -1199,7 +1199,7 @@ pub fn timerfd_create(clockid: i32, flags: u32) usize {
pub const itimerspec = extern struct {
it_interval: timespec,
it_value: timespec
it_value: timespec,
};
pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {
@ -1211,30 +1211,30 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va
}
pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
pub const _LINUX_CAPABILITY_U32S_1 = 1;
pub const _LINUX_CAPABILITY_U32S_1 = 1;
pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
pub const _LINUX_CAPABILITY_U32S_2 = 2;
pub const _LINUX_CAPABILITY_U32S_2 = 2;
pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
pub const _LINUX_CAPABILITY_U32S_3 = 2;
pub const _LINUX_CAPABILITY_U32S_3 = 2;
pub const VFS_CAP_REVISION_MASK = 0xFF000000;
pub const VFS_CAP_REVISION_SHIFT = 24;
pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
pub const VFS_CAP_REVISION_MASK = 0xFF000000;
pub const VFS_CAP_REVISION_SHIFT = 24;
pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
pub const VFS_CAP_REVISION_1 = 0x01000000;
pub const VFS_CAP_U32_1 = 1;
pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1);
pub const VFS_CAP_U32_1 = 1;
pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
pub const VFS_CAP_REVISION_2 = 0x02000000;
pub const VFS_CAP_U32_2 = 2;
pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2);
pub const VFS_CAP_U32_2 = 2;
pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
pub const VFS_CAP_U32 = VFS_CAP_U32_2;
pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
pub const VFS_CAP_U32 = VFS_CAP_U32_2;
pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
pub const vfs_cap_data = extern struct {
//all of these are mandated as little endian
@ -1245,49 +1245,48 @@ pub const vfs_cap_data = extern struct {
};
magic_etc: u32,
data: [VFS_CAP_U32]Data,
data: [VFS_CAP_U32]Data,
};
pub const CAP_CHOWN = 0;
pub const CAP_DAC_OVERRIDE = 1;
pub const CAP_DAC_READ_SEARCH = 2;
pub const CAP_FOWNER = 3;
pub const CAP_FSETID = 4;
pub const CAP_KILL = 5;
pub const CAP_SETGID = 6;
pub const CAP_SETUID = 7;
pub const CAP_SETPCAP = 8;
pub const CAP_LINUX_IMMUTABLE = 9;
pub const CAP_NET_BIND_SERVICE = 10;
pub const CAP_NET_BROADCAST = 11;
pub const CAP_NET_ADMIN = 12;
pub const CAP_NET_RAW = 13;
pub const CAP_IPC_LOCK = 14;
pub const CAP_IPC_OWNER = 15;
pub const CAP_SYS_MODULE = 16;
pub const CAP_SYS_RAWIO = 17;
pub const CAP_SYS_CHROOT = 18;
pub const CAP_SYS_PTRACE = 19;
pub const CAP_SYS_PACCT = 20;
pub const CAP_SYS_ADMIN = 21;
pub const CAP_SYS_BOOT = 22;
pub const CAP_SYS_NICE = 23;
pub const CAP_SYS_RESOURCE = 24;
pub const CAP_SYS_TIME = 25;
pub const CAP_SYS_TTY_CONFIG = 26;
pub const CAP_MKNOD = 27;
pub const CAP_LEASE = 28;
pub const CAP_AUDIT_WRITE = 29;
pub const CAP_AUDIT_CONTROL = 30;
pub const CAP_SETFCAP = 31;
pub const CAP_MAC_OVERRIDE = 32;
pub const CAP_MAC_ADMIN = 33;
pub const CAP_SYSLOG = 34;
pub const CAP_WAKE_ALARM = 35;
pub const CAP_BLOCK_SUSPEND = 36;
pub const CAP_AUDIT_READ = 37;
pub const CAP_LAST_CAP = CAP_AUDIT_READ;
pub const CAP_CHOWN = 0;
pub const CAP_DAC_OVERRIDE = 1;
pub const CAP_DAC_READ_SEARCH = 2;
pub const CAP_FOWNER = 3;
pub const CAP_FSETID = 4;
pub const CAP_KILL = 5;
pub const CAP_SETGID = 6;
pub const CAP_SETUID = 7;
pub const CAP_SETPCAP = 8;
pub const CAP_LINUX_IMMUTABLE = 9;
pub const CAP_NET_BIND_SERVICE = 10;
pub const CAP_NET_BROADCAST = 11;
pub const CAP_NET_ADMIN = 12;
pub const CAP_NET_RAW = 13;
pub const CAP_IPC_LOCK = 14;
pub const CAP_IPC_OWNER = 15;
pub const CAP_SYS_MODULE = 16;
pub const CAP_SYS_RAWIO = 17;
pub const CAP_SYS_CHROOT = 18;
pub const CAP_SYS_PTRACE = 19;
pub const CAP_SYS_PACCT = 20;
pub const CAP_SYS_ADMIN = 21;
pub const CAP_SYS_BOOT = 22;
pub const CAP_SYS_NICE = 23;
pub const CAP_SYS_RESOURCE = 24;
pub const CAP_SYS_TIME = 25;
pub const CAP_SYS_TTY_CONFIG = 26;
pub const CAP_MKNOD = 27;
pub const CAP_LEASE = 28;
pub const CAP_AUDIT_WRITE = 29;
pub const CAP_AUDIT_CONTROL = 30;
pub const CAP_SETFCAP = 31;
pub const CAP_MAC_OVERRIDE = 32;
pub const CAP_MAC_ADMIN = 33;
pub const CAP_SYSLOG = 34;
pub const CAP_WAKE_ALARM = 35;
pub const CAP_BLOCK_SUSPEND = 36;
pub const CAP_AUDIT_READ = 37;
pub const CAP_LAST_CAP = CAP_AUDIT_READ;
pub fn cap_valid(u8: x) bool {
return x >= 0 and x <= CAP_LAST_CAP;

View File

@ -95,7 +95,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
/// Deinitialize with `deinit`
pub fn init(allocator: &Allocator) Self {
return Self {
return Self{
.allocator = allocator,
.len = 0,
.prealloc_segment = undefined,
@ -106,7 +106,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
pub fn deinit(self: &Self) void {
self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);
self.allocator.free(self.dynamic_segments);
*self = undefined;
self.* = undefined;
}
pub fn at(self: &Self, i: usize) &T {
@ -120,7 +120,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
pub fn push(self: &Self, item: &const T) !void {
const new_item_ptr = try self.addOne();
*new_item_ptr = *item;
new_item_ptr.* = item.*;
}
pub fn pushMany(self: &Self, items: []const T) !void {
@ -130,11 +130,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
}
pub fn pop(self: &Self) ?T {
if (self.len == 0)
return null;
if (self.len == 0) return null;
const index = self.len - 1;
const result = *self.uncheckedAt(index);
const result = self.uncheckedAt(index).*;
self.len = index;
return result;
}
@ -247,8 +246,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
shelf_size: usize,
pub fn next(it: &Iterator) ?&T {
if (it.index >= it.list.len)
return null;
if (it.index >= it.list.len) return null;
if (it.index < prealloc_item_count) {
const ptr = &it.list.prealloc_segment[it.index];
it.index += 1;
@ -272,12 +270,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
}
pub fn prev(it: &Iterator) ?&T {
if (it.index == 0)
return null;
if (it.index == 0) return null;
it.index -= 1;
if (it.index < prealloc_item_count)
return &it.list.prealloc_segment[it.index];
if (it.index < prealloc_item_count) return &it.list.prealloc_segment[it.index];
if (it.box_index == 0) {
it.shelf_index -= 1;
@ -309,7 +305,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
};
pub fn iterator(self: &Self, start_index: usize) Iterator {
var it = Iterator {
var it = Iterator{
.list = self,
.index = undefined,
.shelf_index = undefined,
@ -339,25 +335,31 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
var list = SegmentedList(i32, prealloc).init(allocator);
defer list.deinit();
{var i: usize = 0; while (i < 100) : (i += 1) {
try list.push(i32(i + 1));
assert(list.len == i + 1);
}}
{
var i: usize = 0;
while (i < 100) : (i += 1) {
try list.push(i32(i + 1));
assert(list.len == i + 1);
}
}
{var i: usize = 0; while (i < 100) : (i += 1) {
assert(*list.at(i) == i32(i + 1));
}}
{
var i: usize = 0;
while (i < 100) : (i += 1) {
assert(list.at(i).* == i32(i + 1));
}
}
{
var it = list.iterator(0);
var x: i32 = 0;
while (it.next()) |item| {
x += 1;
assert(*item == x);
assert(item.* == x);
}
assert(x == 100);
while (it.prev()) |item| : (x -= 1) {
assert(*item == x);
assert(item.* == x);
}
assert(x == 0);
}
@ -365,14 +367,18 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
assert(??list.pop() == 100);
assert(list.len == 99);
try list.pushMany([]i32 { 1, 2, 3 });
try list.pushMany([]i32{
1,
2,
3,
});
assert(list.len == 102);
assert(??list.pop() == 3);
assert(??list.pop() == 2);
assert(??list.pop() == 1);
assert(list.len == 99);
try list.pushMany([]const i32 {});
try list.pushMany([]const i32{});
assert(list.len == 99);
var i: i32 = 99;

View File

@ -5,15 +5,18 @@ const math = std.math;
const builtin = @import("builtin");
/// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required).
pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {
{var i: usize = 1; while (i < items.len) : (i += 1) {
const x = items[i];
var j: usize = i;
while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
items[j] = items[j - 1];
pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) void {
{
var i: usize = 1;
while (i < items.len) : (i += 1) {
const x = items[i];
var j: usize = i;
while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
items[j] = items[j - 1];
}
items[j] = x;
}
items[j] = x;
}}
}
}
const Range = struct {
@ -21,7 +24,10 @@ const Range = struct {
end: usize,
fn init(start: usize, end: usize) Range {
return Range { .start = start, .end = end };
return Range{
.start = start,
.end = end,
};
}
fn length(self: &const Range) usize {
@ -29,7 +35,6 @@ const Range = struct {
}
};
const Iterator = struct {
size: usize,
power_of_two: usize,
@ -42,7 +47,7 @@ const Iterator = struct {
fn init(size2: usize, min_level: usize) Iterator {
const power_of_two = math.floorPowerOfTwo(usize, size2);
const denominator = power_of_two / min_level;
return Iterator {
return Iterator{
.numerator = 0,
.decimal = 0,
.size = size2,
@ -68,7 +73,10 @@ const Iterator = struct {
self.decimal += 1;
}
return Range {.start = start, .end = self.decimal};
return Range{
.start = start,
.end = self.decimal,
};
}
fn finished(self: &Iterator) bool {
@ -100,7 +108,7 @@ const Pull = struct {
/// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required).
/// Currently implemented as block sort.
pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {
pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) void {
// Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c
var cache: [512]T = undefined;
@ -123,7 +131,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// http://pages.ripco.net/~jgamble/nw.html
var iterator = Iterator.init(items.len, 4);
while (!iterator.finished()) {
var order = []u8{0, 1, 2, 3, 4, 5, 6, 7};
var order = []u8{
0,
1,
2,
3,
4,
5,
6,
7,
};
const range = iterator.nextRange();
const sliced_items = items[range.start..];
@ -149,56 +166,56 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
swap(T, sliced_items, lessThan, &order, 3, 5);
swap(T, sliced_items, lessThan, &order, 3, 4);
},
7 => {
swap(T, sliced_items, lessThan, &order, 1, 2);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 5, 6);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 3, 5);
swap(T, sliced_items, lessThan, &order, 4, 6);
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 4, 5);
swap(T, sliced_items, lessThan, &order, 2, 6);
swap(T, sliced_items, lessThan, &order, 0, 4);
swap(T, sliced_items, lessThan, &order, 1, 5);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 2, 5);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 2, 3);
},
6 => {
swap(T, sliced_items, lessThan, &order, 1, 2);
swap(T, sliced_items, lessThan, &order, 4, 5);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 3, 5);
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 2, 5);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 1, 4);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 2, 3);
},
5 => {
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 2, 3);
swap(T, sliced_items, lessThan, &order, 1, 4);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 1, 2);
},
4 => {
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 2, 3);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 1, 2);
},
7 => {
swap(T, sliced_items, lessThan, &order, 1, 2);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 5, 6);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 3, 5);
swap(T, sliced_items, lessThan, &order, 4, 6);
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 4, 5);
swap(T, sliced_items, lessThan, &order, 2, 6);
swap(T, sliced_items, lessThan, &order, 0, 4);
swap(T, sliced_items, lessThan, &order, 1, 5);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 2, 5);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 2, 3);
},
6 => {
swap(T, sliced_items, lessThan, &order, 1, 2);
swap(T, sliced_items, lessThan, &order, 4, 5);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 3, 5);
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 2, 5);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 1, 4);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 2, 3);
},
5 => {
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 3, 4);
swap(T, sliced_items, lessThan, &order, 2, 4);
swap(T, sliced_items, lessThan, &order, 2, 3);
swap(T, sliced_items, lessThan, &order, 1, 4);
swap(T, sliced_items, lessThan, &order, 0, 3);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 1, 2);
},
4 => {
swap(T, sliced_items, lessThan, &order, 0, 1);
swap(T, sliced_items, lessThan, &order, 2, 3);
swap(T, sliced_items, lessThan, &order, 0, 2);
swap(T, sliced_items, lessThan, &order, 1, 3);
swap(T, sliced_items, lessThan, &order, 1, 2);
},
else => {},
}
}
@ -273,7 +290,6 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// we merged two levels at the same time, so we're done with this level already
// (iterator.nextLevel() is called again at the bottom of this outer merge loop)
_ = iterator.nextLevel();
} else {
iterator.begin();
while (!iterator.finished()) {
@ -303,7 +319,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// 8. redistribute the two internal buffers back into the items
var block_size: usize = math.sqrt(iterator.length());
var buffer_size = iterator.length()/block_size + 1;
var buffer_size = iterator.length() / block_size + 1;
// as an optimization, we really only need to pull out the internal buffers once for each level of merges
// after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
@ -316,8 +332,18 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
var start: usize = 0;
var pull_index: usize = 0;
var pull = []Pull{
Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},
Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},
Pull{
.from = 0,
.to = 0,
.count = 0,
.range = Range.init(0, 0),
},
Pull{
.from = 0,
.to = 0,
.count = 0,
.range = Range.init(0, 0),
},
};
var buffer1 = Range.init(0, 0);
@ -355,7 +381,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// these values will be pulled out to the start of A
last = A.start;
count = 1;
while (count < find) : ({last = index; count += 1;}) {
while (count < find) : ({
last = index;
count += 1;
}) {
index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
if (index == A.end) break;
}
@ -363,7 +392,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
if (count >= buffer_size) {
// keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
pull[pull_index] = Pull {
pull[pull_index] = Pull{
.range = Range.init(A.start, B.end),
.count = count,
.from = index,
@ -398,7 +427,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
} else if (pull_index == 0 and count > buffer1.length()) {
// keep track of the largest buffer we were able to find
buffer1 = Range.init(A.start, A.start + count);
pull[pull_index] = Pull {
pull[pull_index] = Pull{
.range = Range.init(A.start, B.end),
.count = count,
.from = index,
@ -410,7 +439,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// these values will be pulled out to the end of B
last = B.end - 1;
count = 1;
while (count < find) : ({last = index - 1; count += 1;}) {
while (count < find) : ({
last = index - 1;
count += 1;
}) {
index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
if (index == B.start) break;
}
@ -418,7 +450,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
if (count >= buffer_size) {
// keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
pull[pull_index] = Pull {
pull[pull_index] = Pull{
.range = Range.init(A.start, B.end),
.count = count,
.from = index,
@ -457,7 +489,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
} else if (pull_index == 0 and count > buffer1.length()) {
// keep track of the largest buffer we were able to find
buffer1 = Range.init(B.end - count, B.end);
pull[pull_index] = Pull {
pull[pull_index] = Pull{
.range = Range.init(A.start, B.end),
.count = count,
.from = index,
@ -496,7 +528,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// adjust block_size and buffer_size based on the values we were able to pull out
buffer_size = buffer1.length();
block_size = iterator.length()/buffer_size + 1;
block_size = iterator.length() / buffer_size + 1;
// the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
// so this was originally here to test the math for adjusting block_size above
@ -547,7 +579,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// swap the first value of each A block with the value in buffer1
var indexA = buffer1.start;
index = firstA.end;
while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
while (index < blockA.end) : ({
indexA += 1;
index += block_size;
}) {
mem.swap(T, &items[indexA], &items[index]);
}
@ -626,9 +661,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
// if there are no more A blocks remaining, this step is finished!
blockA.start += block_size;
if (blockA.length() == 0)
break;
if (blockA.length() == 0) break;
} else if (blockB.length() < block_size) {
// move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
// the cache is disabled here since it might contain the contents of the previous A block
@ -709,7 +742,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
}
// merge operation without a buffer
fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T, &const T) bool) void {
if (A_arg.length() == 0 or B_arg.length() == 0) return;
// this just repeatedly binary searches into B and rotates A into position.
@ -730,8 +763,8 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
// again, this is NOT a general-purpose solution it only works well in this case!
// kind of like how the O(n^2) insertion sort is used in some places
var A = *A_arg;
var B = *B_arg;
var A = A_arg.*;
var B = B_arg.*;
while (true) {
// find the first place in B where the first item in A needs to be inserted
@ -751,7 +784,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
}
// merge operation using an internal buffer
fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, buffer: &const Range) void {
fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, buffer: &const Range) void {
// whenever we find a value to add to the final array, swap it with the value that's already in that spot
// when this algorithm is finished, 'buffer' will contain its original contents, but in a different order
var A_count: usize = 0;
@ -787,9 +820,9 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
// combine a linear search with a binary search to reduce the number of comparisons in situations
// where have some idea as to how many unique values there are and where the next value might be
fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
if (range.length() == 0) return range.start;
const skip = math.max(range.length()/unique, usize(1));
const skip = math.max(range.length() / unique, usize(1));
var index = range.start + skip;
while (lessThan(items[index - 1], value)) : (index += skip) {
@ -801,9 +834,9 @@ fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const
return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
}
fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
if (range.length() == 0) return range.start;
const skip = math.max(range.length()/unique, usize(1));
const skip = math.max(range.length() / unique, usize(1));
var index = range.end - skip;
while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
@ -815,9 +848,9 @@ fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &cons
return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
}
fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
if (range.length() == 0) return range.start;
const skip = math.max(range.length()/unique, usize(1));
const skip = math.max(range.length() / unique, usize(1));
var index = range.start + skip;
while (!lessThan(value, items[index - 1])) : (index += skip) {
@ -829,9 +862,9 @@ fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const
return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
}
fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
if (range.length() == 0) return range.start;
const skip = math.max(range.length()/unique, usize(1));
const skip = math.max(range.length() / unique, usize(1));
var index = range.end - skip;
while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
@ -843,12 +876,12 @@ fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const
return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
}
fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {
fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool) usize {
var start = range.start;
var end = range.end - 1;
if (range.start >= range.end) return range.end;
while (start < end) {
const mid = start + (end - start)/2;
const mid = start + (end - start) / 2;
if (lessThan(items[mid], value)) {
start = mid + 1;
} else {
@ -861,12 +894,12 @@ fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Rang
return start;
}
fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {
fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool) usize {
var start = range.start;
var end = range.end - 1;
if (range.start >= range.end) return range.end;
while (start < end) {
const mid = start + (end - start)/2;
const mid = start + (end - start) / 2;
if (!lessThan(value, items[mid])) {
start = mid + 1;
} else {
@ -879,7 +912,7 @@ fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range
return start;
}
fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, into: []T) void {
fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, into: []T) void {
var A_index: usize = A.start;
var B_index: usize = B.start;
const A_last = A.end;
@ -909,7 +942,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
}
}
fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, cache: []T) void {
fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, cache: []T) void {
// A fits into the cache, so use that instead of the internal buffer
var A_index: usize = 0;
var B_index: usize = B.start;
@ -937,29 +970,27 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
mem.copy(T, items[insert_index..], cache[A_index..A_last]);
}
fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool, order: &[8]u8, x: usize, y: usize) void {
if (lessThan(items[y], items[x]) or
((*order)[x] > (*order)[y] and !lessThan(items[x], items[y])))
{
fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool, order: &[8]u8, x: usize, y: usize) void {
if (lessThan(items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(items[x], items[y]))) {
mem.swap(T, &items[x], &items[y]);
mem.swap(u8, &(*order)[x], &(*order)[y]);
mem.swap(u8, &(order.*)[x], &(order.*)[y]);
}
}
fn i32asc(lhs: &const i32, rhs: &const i32) bool {
return *lhs < *rhs;
return lhs.* < rhs.*;
}
fn i32desc(lhs: &const i32, rhs: &const i32) bool {
return *rhs < *lhs;
return rhs.* < lhs.*;
}
fn u8asc(lhs: &const u8, rhs: &const u8) bool {
return *lhs < *rhs;
return lhs.* < rhs.*;
}
fn u8desc(lhs: &const u8, rhs: &const u8) bool {
return *rhs < *lhs;
return rhs.* < lhs.*;
}
test "stable sort" {
@ -967,44 +998,125 @@ test "stable sort" {
comptime testStableSort();
}
fn testStableSort() void {
var expected = []IdAndValue {
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 2, .value = 0},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 2, .value = 2},
};
var cases = [][9]IdAndValue {
[]IdAndValue {
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 2, .value = 0},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 2, .value = 2},
var expected = []IdAndValue{
IdAndValue{
.id = 0,
.value = 0,
},
[]IdAndValue {
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 2, .value = 2},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 2, .value = 0},
IdAndValue{
.id = 1,
.value = 0,
},
IdAndValue{
.id = 2,
.value = 0,
},
IdAndValue{
.id = 0,
.value = 1,
},
IdAndValue{
.id = 1,
.value = 1,
},
IdAndValue{
.id = 2,
.value = 1,
},
IdAndValue{
.id = 0,
.value = 2,
},
IdAndValue{
.id = 1,
.value = 2,
},
IdAndValue{
.id = 2,
.value = 2,
},
};
var cases = [][9]IdAndValue{
[]IdAndValue{
IdAndValue{
.id = 0,
.value = 0,
},
IdAndValue{
.id = 0,
.value = 1,
},
IdAndValue{
.id = 0,
.value = 2,
},
IdAndValue{
.id = 1,
.value = 0,
},
IdAndValue{
.id = 1,
.value = 1,
},
IdAndValue{
.id = 1,
.value = 2,
},
IdAndValue{
.id = 2,
.value = 0,
},
IdAndValue{
.id = 2,
.value = 1,
},
IdAndValue{
.id = 2,
.value = 2,
},
},
[]IdAndValue{
IdAndValue{
.id = 0,
.value = 2,
},
IdAndValue{
.id = 0,
.value = 1,
},
IdAndValue{
.id = 0,
.value = 0,
},
IdAndValue{
.id = 1,
.value = 2,
},
IdAndValue{
.id = 1,
.value = 1,
},
IdAndValue{
.id = 1,
.value = 0,
},
IdAndValue{
.id = 2,
.value = 2,
},
IdAndValue{
.id = 2,
.value = 1,
},
IdAndValue{
.id = 2,
.value = 0,
},
},
};
for (cases) |*case| {
insertionSort(IdAndValue, (*case)[0..], cmpByValue);
for (*case) |item, i| {
insertionSort(IdAndValue, (case.*)[0..], cmpByValue);
for (case.*) |item, i| {
assert(item.id == expected[i].id);
assert(item.value == expected[i].value);
}
@ -1019,13 +1131,31 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) bool {
}
test "std.sort" {
const u8cases = [][]const []const u8 {
[][]const u8{"", ""},
[][]const u8{"a", "a"},
[][]const u8{"az", "az"},
[][]const u8{"za", "az"},
[][]const u8{"asdf", "adfs"},
[][]const u8{"one", "eno"},
const u8cases = [][]const []const u8{
[][]const u8{
"",
"",
},
[][]const u8{
"a",
"a",
},
[][]const u8{
"az",
"az",
},
[][]const u8{
"za",
"az",
},
[][]const u8{
"asdf",
"adfs",
},
[][]const u8{
"one",
"eno",
},
};
for (u8cases) |case| {
@ -1036,13 +1166,59 @@ test "std.sort" {
assert(mem.eql(u8, slice, case[1]));
}
const i32cases = [][]const []const i32 {
[][]const i32{[]i32{}, []i32{}},
[][]const i32{[]i32{1}, []i32{1}},
[][]const i32{[]i32{0, 1}, []i32{0, 1}},
[][]const i32{[]i32{1, 0}, []i32{0, 1}},
[][]const i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}},
[][]const i32{[]i32{2, 1, 3}, []i32{1, 2, 3}},
const i32cases = [][]const []const i32{
[][]const i32{
[]i32{},
[]i32{},
},
[][]const i32{
[]i32{1},
[]i32{1},
},
[][]const i32{
[]i32{
0,
1,
},
[]i32{
0,
1,
},
},
[][]const i32{
[]i32{
1,
0,
},
[]i32{
0,
1,
},
},
[][]const i32{
[]i32{
1,
-1,
0,
},
[]i32{
-1,
0,
1,
},
},
[][]const i32{
[]i32{
2,
1,
3,
},
[]i32{
1,
2,
3,
},
},
};
for (i32cases) |case| {
@ -1055,13 +1231,59 @@ test "std.sort" {
}
test "std.sort descending" {
const rev_cases = [][]const []const i32 {
[][]const i32{[]i32{}, []i32{}},
[][]const i32{[]i32{1}, []i32{1}},
[][]const i32{[]i32{0, 1}, []i32{1, 0}},
[][]const i32{[]i32{1, 0}, []i32{1, 0}},
[][]const i32{[]i32{1, -1, 0}, []i32{1, 0, -1}},
[][]const i32{[]i32{2, 1, 3}, []i32{3, 2, 1}},
const rev_cases = [][]const []const i32{
[][]const i32{
[]i32{},
[]i32{},
},
[][]const i32{
[]i32{1},
[]i32{1},
},
[][]const i32{
[]i32{
0,
1,
},
[]i32{
1,
0,
},
},
[][]const i32{
[]i32{
1,
0,
},
[]i32{
1,
0,
},
},
[][]const i32{
[]i32{
1,
-1,
0,
},
[]i32{
1,
0,
-1,
},
},
[][]const i32{
[]i32{
2,
1,
3,
},
[]i32{
3,
2,
1,
},
},
};
for (rev_cases) |case| {
@ -1074,10 +1296,22 @@ test "std.sort descending" {
}
test "another sort case" {
var arr = []i32{ 5, 3, 1, 2, 4 };
var arr = []i32{
5,
3,
1,
2,
4,
};
sort(i32, arr[0..], i32asc);
assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }));
assert(mem.eql(i32, arr, []i32{
1,
2,
3,
4,
5,
}));
}
test "sort fuzz testing" {
@ -1112,7 +1346,7 @@ fn fuzzTest(rng: &std.rand.Random) void {
}
}
pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {
pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) T {
var i: usize = 0;
var smallest = items[0];
for (items[1..]) |item| {
@ -1123,7 +1357,7 @@ pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const
return smallest;
}
pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {
pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) T {
var i: usize = 0;
var biggest = items[0];
for (items[1..]) |item| {

View File

@ -27,10 +27,10 @@ extern fn zen_start() noreturn {
nakedcc fn _start() noreturn {
switch (builtin.arch) {
builtin.Arch.x86_64 => {
argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
argc_ptr = asm ("lea (%%rsp), %[argc]" : [argc] "=r" (-> &usize));
},
builtin.Arch.i386 => {
argc_ptr = asm("lea (%%esp), %[argc]": [argc] "=r" (-> &usize));
argc_ptr = asm ("lea (%%esp), %[argc]" : [argc] "=r" (-> &usize));
},
else => @compileError("unsupported arch"),
}
@ -46,7 +46,7 @@ extern fn WinMainCRTStartup() noreturn {
}
fn posixCallMainAndExit() noreturn {
const argc = *argc_ptr;
const argc = argc_ptr.*;
const argv = @ptrCast(&&u8, &argc_ptr[1]);
const envp_nullable = @ptrCast(&?&u8, &argv[argc + 1]);
var envp_count: usize = 0;
@ -56,7 +56,7 @@ fn posixCallMainAndExit() noreturn {
const auxv = &@ptrCast(&usize, envp.ptr)[envp_count + 1];
var i: usize = 0;
while (auxv[i] != 0) : (i += 2) {
if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i+1];
if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i + 1];
}
std.debug.assert(std.os.linux_aux_raw[std.elf.AT_PAGESZ] == std.os.page_size);
}

View File

@ -36,12 +36,10 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t
const significand: rep_t = (aAbs & significandMask) | implicitBit;
// If either the value or the exponent is negative, the result is zero.
if (sign == -1 or exponent < 0)
return 0;
if (sign == -1 or exponent < 0) return 0;
// If the value is too large for the integer type, saturate.
if (c_uint(exponent) >= fixuint_t.bit_count)
return ~fixuint_t(0);
if (c_uint(exponent) >= fixuint_t.bit_count) return ~fixuint_t(0);
// If 0 <= exponent < significandBits, right shift to get the result.
// Otherwise, shift left.

View File

@ -9,4 +9,3 @@ pub extern fn __fixunsdfdi(a: f64) u64 {
test "import fixunsdfdi" {
_ = @import("fixunsdfdi_test.zig");
}

View File

@ -9,4 +9,3 @@ pub extern fn __fixunsdfsi(a: f64) u32 {
test "import fixunsdfsi" {
_ = @import("fixunsdfsi_test.zig");
}

View File

@ -9,4 +9,3 @@ pub extern fn __fixunssfti(a: f32) u128 {
test "import fixunssfti" {
_ = @import("fixunssfti_test.zig");
}

View File

@ -9,4 +9,3 @@ pub extern fn __fixunstfti(a: f128) u128 {
test "import fixunstfti" {
_ = @import("fixunstfti_test.zig");
}

View File

@ -92,9 +92,10 @@ pub fn setXmm0(comptime T: type, value: T) void {
const aligned_value: T align(16) = value;
asm volatile (
\\movaps (%[ptr]), %%xmm0
:
: [ptr] "r" (&aligned_value)
: "xmm0");
:
: [ptr] "r" (&aligned_value)
: "xmm0");
}
extern fn __udivdi3(a: u64, b: u64) u64 {
@ -283,26 +284,27 @@ extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) u32 {
@setRuntimeSafety(is_test);
const d = __udivsi3(a, b);
*rem = u32(i32(a) -% (i32(d) * i32(b)));
rem.* = u32(i32(a) -% (i32(d) * i32(b)));
return d;
}
extern fn __udivsi3(n: u32, d: u32) u32 {
@setRuntimeSafety(is_test);
const n_uword_bits: c_uint = u32.bit_count;
// special cases
if (d == 0)
return 0; // ?!
if (n == 0)
return 0;
if (d == 0) return 0; // ?!
if (n == 0) return 0;
var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
// 0 <= sr <= n_uword_bits - 1 or sr large
if (sr > n_uword_bits - 1) // d > r
if (sr > n_uword_bits - 1) {
// d > r
return 0;
if (sr == n_uword_bits - 1) // d == 1
}
if (sr == n_uword_bits - 1) {
// d == 1
return n;
}
sr += 1;
// 1 <= sr <= n_uword_bits - 1
// Not a special case
@ -341,139 +343,667 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
}
test "test_udivsi3" {
const cases = [][3]u32 {
[]u32{0x00000000, 0x00000001, 0x00000000},
[]u32{0x00000000, 0x00000002, 0x00000000},
[]u32{0x00000000, 0x00000003, 0x00000000},
[]u32{0x00000000, 0x00000010, 0x00000000},
[]u32{0x00000000, 0x078644FA, 0x00000000},
[]u32{0x00000000, 0x0747AE14, 0x00000000},
[]u32{0x00000000, 0x7FFFFFFF, 0x00000000},
[]u32{0x00000000, 0x80000000, 0x00000000},
[]u32{0x00000000, 0xFFFFFFFD, 0x00000000},
[]u32{0x00000000, 0xFFFFFFFE, 0x00000000},
[]u32{0x00000000, 0xFFFFFFFF, 0x00000000},
[]u32{0x00000001, 0x00000001, 0x00000001},
[]u32{0x00000001, 0x00000002, 0x00000000},
[]u32{0x00000001, 0x00000003, 0x00000000},
[]u32{0x00000001, 0x00000010, 0x00000000},
[]u32{0x00000001, 0x078644FA, 0x00000000},
[]u32{0x00000001, 0x0747AE14, 0x00000000},
[]u32{0x00000001, 0x7FFFFFFF, 0x00000000},
[]u32{0x00000001, 0x80000000, 0x00000000},
[]u32{0x00000001, 0xFFFFFFFD, 0x00000000},
[]u32{0x00000001, 0xFFFFFFFE, 0x00000000},
[]u32{0x00000001, 0xFFFFFFFF, 0x00000000},
[]u32{0x00000002, 0x00000001, 0x00000002},
[]u32{0x00000002, 0x00000002, 0x00000001},
[]u32{0x00000002, 0x00000003, 0x00000000},
[]u32{0x00000002, 0x00000010, 0x00000000},
[]u32{0x00000002, 0x078644FA, 0x00000000},
[]u32{0x00000002, 0x0747AE14, 0x00000000},
[]u32{0x00000002, 0x7FFFFFFF, 0x00000000},
[]u32{0x00000002, 0x80000000, 0x00000000},
[]u32{0x00000002, 0xFFFFFFFD, 0x00000000},
[]u32{0x00000002, 0xFFFFFFFE, 0x00000000},
[]u32{0x00000002, 0xFFFFFFFF, 0x00000000},
[]u32{0x00000003, 0x00000001, 0x00000003},
[]u32{0x00000003, 0x00000002, 0x00000001},
[]u32{0x00000003, 0x00000003, 0x00000001},
[]u32{0x00000003, 0x00000010, 0x00000000},
[]u32{0x00000003, 0x078644FA, 0x00000000},
[]u32{0x00000003, 0x0747AE14, 0x00000000},
[]u32{0x00000003, 0x7FFFFFFF, 0x00000000},
[]u32{0x00000003, 0x80000000, 0x00000000},
[]u32{0x00000003, 0xFFFFFFFD, 0x00000000},
[]u32{0x00000003, 0xFFFFFFFE, 0x00000000},
[]u32{0x00000003, 0xFFFFFFFF, 0x00000000},
[]u32{0x00000010, 0x00000001, 0x00000010},
[]u32{0x00000010, 0x00000002, 0x00000008},
[]u32{0x00000010, 0x00000003, 0x00000005},
[]u32{0x00000010, 0x00000010, 0x00000001},
[]u32{0x00000010, 0x078644FA, 0x00000000},
[]u32{0x00000010, 0x0747AE14, 0x00000000},
[]u32{0x00000010, 0x7FFFFFFF, 0x00000000},
[]u32{0x00000010, 0x80000000, 0x00000000},
[]u32{0x00000010, 0xFFFFFFFD, 0x00000000},
[]u32{0x00000010, 0xFFFFFFFE, 0x00000000},
[]u32{0x00000010, 0xFFFFFFFF, 0x00000000},
[]u32{0x078644FA, 0x00000001, 0x078644FA},
[]u32{0x078644FA, 0x00000002, 0x03C3227D},
[]u32{0x078644FA, 0x00000003, 0x028216FE},
[]u32{0x078644FA, 0x00000010, 0x0078644F},
[]u32{0x078644FA, 0x078644FA, 0x00000001},
[]u32{0x078644FA, 0x0747AE14, 0x00000001},
[]u32{0x078644FA, 0x7FFFFFFF, 0x00000000},
[]u32{0x078644FA, 0x80000000, 0x00000000},
[]u32{0x078644FA, 0xFFFFFFFD, 0x00000000},
[]u32{0x078644FA, 0xFFFFFFFE, 0x00000000},
[]u32{0x078644FA, 0xFFFFFFFF, 0x00000000},
[]u32{0x0747AE14, 0x00000001, 0x0747AE14},
[]u32{0x0747AE14, 0x00000002, 0x03A3D70A},
[]u32{0x0747AE14, 0x00000003, 0x026D3A06},
[]u32{0x0747AE14, 0x00000010, 0x00747AE1},
[]u32{0x0747AE14, 0x078644FA, 0x00000000},
[]u32{0x0747AE14, 0x0747AE14, 0x00000001},
[]u32{0x0747AE14, 0x7FFFFFFF, 0x00000000},
[]u32{0x0747AE14, 0x80000000, 0x00000000},
[]u32{0x0747AE14, 0xFFFFFFFD, 0x00000000},
[]u32{0x0747AE14, 0xFFFFFFFE, 0x00000000},
[]u32{0x0747AE14, 0xFFFFFFFF, 0x00000000},
[]u32{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF},
[]u32{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF},
[]u32{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA},
[]u32{0x7FFFFFFF, 0x00000010, 0x07FFFFFF},
[]u32{0x7FFFFFFF, 0x078644FA, 0x00000011},
[]u32{0x7FFFFFFF, 0x0747AE14, 0x00000011},
[]u32{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001},
[]u32{0x7FFFFFFF, 0x80000000, 0x00000000},
[]u32{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000},
[]u32{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000},
[]u32{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000},
[]u32{0x80000000, 0x00000001, 0x80000000},
[]u32{0x80000000, 0x00000002, 0x40000000},
[]u32{0x80000000, 0x00000003, 0x2AAAAAAA},
[]u32{0x80000000, 0x00000010, 0x08000000},
[]u32{0x80000000, 0x078644FA, 0x00000011},
[]u32{0x80000000, 0x0747AE14, 0x00000011},
[]u32{0x80000000, 0x7FFFFFFF, 0x00000001},
[]u32{0x80000000, 0x80000000, 0x00000001},
[]u32{0x80000000, 0xFFFFFFFD, 0x00000000},
[]u32{0x80000000, 0xFFFFFFFE, 0x00000000},
[]u32{0x80000000, 0xFFFFFFFF, 0x00000000},
[]u32{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD},
[]u32{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE},
[]u32{0xFFFFFFFD, 0x00000003, 0x55555554},
[]u32{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF},
[]u32{0xFFFFFFFD, 0x078644FA, 0x00000022},
[]u32{0xFFFFFFFD, 0x0747AE14, 0x00000023},
[]u32{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001},
[]u32{0xFFFFFFFD, 0x80000000, 0x00000001},
[]u32{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001},
[]u32{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000},
[]u32{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000},
[]u32{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE},
[]u32{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF},
[]u32{0xFFFFFFFE, 0x00000003, 0x55555554},
[]u32{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF},
[]u32{0xFFFFFFFE, 0x078644FA, 0x00000022},
[]u32{0xFFFFFFFE, 0x0747AE14, 0x00000023},
[]u32{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002},
[]u32{0xFFFFFFFE, 0x80000000, 0x00000001},
[]u32{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001},
[]u32{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001},
[]u32{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000},
[]u32{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF},
[]u32{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF},
[]u32{0xFFFFFFFF, 0x00000003, 0x55555555},
[]u32{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF},
[]u32{0xFFFFFFFF, 0x078644FA, 0x00000022},
[]u32{0xFFFFFFFF, 0x0747AE14, 0x00000023},
[]u32{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002},
[]u32{0xFFFFFFFF, 0x80000000, 0x00000001},
[]u32{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001},
[]u32{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001},
[]u32{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001},
const cases = [][3]u32{
[]u32{
0x00000000,
0x00000001,
0x00000000,
},
[]u32{
0x00000000,
0x00000002,
0x00000000,
},
[]u32{
0x00000000,
0x00000003,
0x00000000,
},
[]u32{
0x00000000,
0x00000010,
0x00000000,
},
[]u32{
0x00000000,
0x078644FA,
0x00000000,
},
[]u32{
0x00000000,
0x0747AE14,
0x00000000,
},
[]u32{
0x00000000,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x00000000,
0x80000000,
0x00000000,
},
[]u32{
0x00000000,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x00000000,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x00000000,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x00000001,
0x00000001,
0x00000001,
},
[]u32{
0x00000001,
0x00000002,
0x00000000,
},
[]u32{
0x00000001,
0x00000003,
0x00000000,
},
[]u32{
0x00000001,
0x00000010,
0x00000000,
},
[]u32{
0x00000001,
0x078644FA,
0x00000000,
},
[]u32{
0x00000001,
0x0747AE14,
0x00000000,
},
[]u32{
0x00000001,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x00000001,
0x80000000,
0x00000000,
},
[]u32{
0x00000001,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x00000001,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x00000001,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x00000002,
0x00000001,
0x00000002,
},
[]u32{
0x00000002,
0x00000002,
0x00000001,
},
[]u32{
0x00000002,
0x00000003,
0x00000000,
},
[]u32{
0x00000002,
0x00000010,
0x00000000,
},
[]u32{
0x00000002,
0x078644FA,
0x00000000,
},
[]u32{
0x00000002,
0x0747AE14,
0x00000000,
},
[]u32{
0x00000002,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x00000002,
0x80000000,
0x00000000,
},
[]u32{
0x00000002,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x00000002,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x00000002,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x00000003,
0x00000001,
0x00000003,
},
[]u32{
0x00000003,
0x00000002,
0x00000001,
},
[]u32{
0x00000003,
0x00000003,
0x00000001,
},
[]u32{
0x00000003,
0x00000010,
0x00000000,
},
[]u32{
0x00000003,
0x078644FA,
0x00000000,
},
[]u32{
0x00000003,
0x0747AE14,
0x00000000,
},
[]u32{
0x00000003,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x00000003,
0x80000000,
0x00000000,
},
[]u32{
0x00000003,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x00000003,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x00000003,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x00000010,
0x00000001,
0x00000010,
},
[]u32{
0x00000010,
0x00000002,
0x00000008,
},
[]u32{
0x00000010,
0x00000003,
0x00000005,
},
[]u32{
0x00000010,
0x00000010,
0x00000001,
},
[]u32{
0x00000010,
0x078644FA,
0x00000000,
},
[]u32{
0x00000010,
0x0747AE14,
0x00000000,
},
[]u32{
0x00000010,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x00000010,
0x80000000,
0x00000000,
},
[]u32{
0x00000010,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x00000010,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x00000010,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x078644FA,
0x00000001,
0x078644FA,
},
[]u32{
0x078644FA,
0x00000002,
0x03C3227D,
},
[]u32{
0x078644FA,
0x00000003,
0x028216FE,
},
[]u32{
0x078644FA,
0x00000010,
0x0078644F,
},
[]u32{
0x078644FA,
0x078644FA,
0x00000001,
},
[]u32{
0x078644FA,
0x0747AE14,
0x00000001,
},
[]u32{
0x078644FA,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x078644FA,
0x80000000,
0x00000000,
},
[]u32{
0x078644FA,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x078644FA,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x078644FA,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x0747AE14,
0x00000001,
0x0747AE14,
},
[]u32{
0x0747AE14,
0x00000002,
0x03A3D70A,
},
[]u32{
0x0747AE14,
0x00000003,
0x026D3A06,
},
[]u32{
0x0747AE14,
0x00000010,
0x00747AE1,
},
[]u32{
0x0747AE14,
0x078644FA,
0x00000000,
},
[]u32{
0x0747AE14,
0x0747AE14,
0x00000001,
},
[]u32{
0x0747AE14,
0x7FFFFFFF,
0x00000000,
},
[]u32{
0x0747AE14,
0x80000000,
0x00000000,
},
[]u32{
0x0747AE14,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x0747AE14,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x0747AE14,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x7FFFFFFF,
0x00000001,
0x7FFFFFFF,
},
[]u32{
0x7FFFFFFF,
0x00000002,
0x3FFFFFFF,
},
[]u32{
0x7FFFFFFF,
0x00000003,
0x2AAAAAAA,
},
[]u32{
0x7FFFFFFF,
0x00000010,
0x07FFFFFF,
},
[]u32{
0x7FFFFFFF,
0x078644FA,
0x00000011,
},
[]u32{
0x7FFFFFFF,
0x0747AE14,
0x00000011,
},
[]u32{
0x7FFFFFFF,
0x7FFFFFFF,
0x00000001,
},
[]u32{
0x7FFFFFFF,
0x80000000,
0x00000000,
},
[]u32{
0x7FFFFFFF,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x7FFFFFFF,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x7FFFFFFF,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0x80000000,
0x00000001,
0x80000000,
},
[]u32{
0x80000000,
0x00000002,
0x40000000,
},
[]u32{
0x80000000,
0x00000003,
0x2AAAAAAA,
},
[]u32{
0x80000000,
0x00000010,
0x08000000,
},
[]u32{
0x80000000,
0x078644FA,
0x00000011,
},
[]u32{
0x80000000,
0x0747AE14,
0x00000011,
},
[]u32{
0x80000000,
0x7FFFFFFF,
0x00000001,
},
[]u32{
0x80000000,
0x80000000,
0x00000001,
},
[]u32{
0x80000000,
0xFFFFFFFD,
0x00000000,
},
[]u32{
0x80000000,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0x80000000,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0xFFFFFFFD,
0x00000001,
0xFFFFFFFD,
},
[]u32{
0xFFFFFFFD,
0x00000002,
0x7FFFFFFE,
},
[]u32{
0xFFFFFFFD,
0x00000003,
0x55555554,
},
[]u32{
0xFFFFFFFD,
0x00000010,
0x0FFFFFFF,
},
[]u32{
0xFFFFFFFD,
0x078644FA,
0x00000022,
},
[]u32{
0xFFFFFFFD,
0x0747AE14,
0x00000023,
},
[]u32{
0xFFFFFFFD,
0x7FFFFFFF,
0x00000001,
},
[]u32{
0xFFFFFFFD,
0x80000000,
0x00000001,
},
[]u32{
0xFFFFFFFD,
0xFFFFFFFD,
0x00000001,
},
[]u32{
0xFFFFFFFD,
0xFFFFFFFE,
0x00000000,
},
[]u32{
0xFFFFFFFD,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0xFFFFFFFE,
0x00000001,
0xFFFFFFFE,
},
[]u32{
0xFFFFFFFE,
0x00000002,
0x7FFFFFFF,
},
[]u32{
0xFFFFFFFE,
0x00000003,
0x55555554,
},
[]u32{
0xFFFFFFFE,
0x00000010,
0x0FFFFFFF,
},
[]u32{
0xFFFFFFFE,
0x078644FA,
0x00000022,
},
[]u32{
0xFFFFFFFE,
0x0747AE14,
0x00000023,
},
[]u32{
0xFFFFFFFE,
0x7FFFFFFF,
0x00000002,
},
[]u32{
0xFFFFFFFE,
0x80000000,
0x00000001,
},
[]u32{
0xFFFFFFFE,
0xFFFFFFFD,
0x00000001,
},
[]u32{
0xFFFFFFFE,
0xFFFFFFFE,
0x00000001,
},
[]u32{
0xFFFFFFFE,
0xFFFFFFFF,
0x00000000,
},
[]u32{
0xFFFFFFFF,
0x00000001,
0xFFFFFFFF,
},
[]u32{
0xFFFFFFFF,
0x00000002,
0x7FFFFFFF,
},
[]u32{
0xFFFFFFFF,
0x00000003,
0x55555555,
},
[]u32{
0xFFFFFFFF,
0x00000010,
0x0FFFFFFF,
},
[]u32{
0xFFFFFFFF,
0x078644FA,
0x00000022,
},
[]u32{
0xFFFFFFFF,
0x0747AE14,
0x00000023,
},
[]u32{
0xFFFFFFFF,
0x7FFFFFFF,
0x00000002,
},
[]u32{
0xFFFFFFFF,
0x80000000,
0x00000001,
},
[]u32{
0xFFFFFFFF,
0xFFFFFFFD,
0x00000001,
},
[]u32{
0xFFFFFFFF,
0xFFFFFFFE,
0x00000001,
},
[]u32{
0xFFFFFFFF,
0xFFFFFFFF,
0x00000001,
},
};
for (cases) |case| {

View File

@ -1,7 +1,10 @@
const builtin = @import("builtin");
const is_test = builtin.is_test;
const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 };
const low = switch (builtin.endian) {
builtin.Endian.Big => 1,
builtin.Endian.Little => 0,
};
const high = 1 - low;
pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) DoubleInt {
@ -11,8 +14,8 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421
const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421
const n = @ptrCast(&const [2]SingleInt, &a).*; // TODO issue #421
const d = @ptrCast(&const [2]SingleInt, &b).*; // TODO issue #421
var q: [2]SingleInt = undefined;
var r: [2]SingleInt = undefined;
var sr: c_uint = undefined;
@ -23,7 +26,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// ---
// 0 X
if (maybe_rem) |rem| {
*rem = n[low] % d[low];
rem.* = n[low] % d[low];
}
return n[low] / d[low];
}
@ -31,7 +34,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// ---
// K X
if (maybe_rem) |rem| {
*rem = n[low];
rem.* = n[low];
}
return 0;
}
@ -42,7 +45,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// ---
// 0 0
if (maybe_rem) |rem| {
*rem = n[high] % d[low];
rem.* = n[high] % d[low];
}
return n[high] / d[low];
}
@ -54,7 +57,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
if (maybe_rem) |rem| {
r[high] = n[high] % d[high];
r[low] = 0;
*rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
rem.* = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
}
return n[high] / d[high];
}
@ -66,7 +69,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
if (maybe_rem) |rem| {
r[low] = n[low];
r[high] = n[high] & (d[high] - 1);
*rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
rem.* = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
}
return n[high] >> Log2SingleInt(@ctz(d[high]));
}
@ -77,7 +80,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// 0 <= sr <= SingleInt.bit_count - 2 or sr large
if (sr > SingleInt.bit_count - 2) {
if (maybe_rem) |rem| {
*rem = a;
rem.* = a;
}
return 0;
}
@ -98,7 +101,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
if ((d[low] & (d[low] - 1)) == 0) {
// d is a power of 2
if (maybe_rem) |rem| {
*rem = n[low] & (d[low] - 1);
rem.* = n[low] & (d[low] - 1);
}
if (d[low] == 1) {
return a;
@ -106,7 +109,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
sr = @ctz(d[low]);
q[high] = n[high] >> Log2SingleInt(sr);
q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
return *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]); // TODO issue #421
return @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421
}
// K X
// ---
@ -141,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// 0 <= sr <= SingleInt.bit_count - 1 or sr large
if (sr > SingleInt.bit_count - 1) {
if (maybe_rem) |rem| {
*rem = a;
rem.* = a;
}
return 0;
}
@ -170,25 +173,25 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
var r_all: DoubleInt = undefined;
while (sr > 0) : (sr -= 1) {
// r:q = ((r:q) << 1) | carry
r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));
r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));
q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));
q[low] = (q[low] << 1) | carry;
r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));
r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));
q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));
q[low] = (q[low] << 1) | carry;
// carry = 0;
// if (r.all >= b)
// {
// r.all -= b;
// carry = 1;
// }
r_all = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
r_all = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1);
carry = u32(s & 1);
r_all -= b & @bitCast(DoubleInt, s);
r = *@ptrCast(&[2]SingleInt, &r_all); // TODO issue #421
r = @ptrCast(&[2]SingleInt, &r_all).*; // TODO issue #421
}
const q_all = ((*@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0])) << 1) | carry; // TODO issue #421
const q_all = ((@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]).*) << 1) | carry; // TODO issue #421
if (maybe_rem) |rem| {
*rem = r_all;
rem.* = r_all;
}
return q_all;
}

View File

@ -9,7 +9,7 @@ pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) u128 {
pub extern fn __udivmodti4_windows_x86_64(a: &const u128, b: &const u128, maybe_rem: ?&u128) void {
@setRuntimeSafety(builtin.is_test);
compiler_rt.setXmm0(u128, udivmod(u128, *a, *b, maybe_rem));
compiler_rt.setXmm0(u128, udivmod(u128, a.*, b.*, maybe_rem));
}
test "import udivmodti4" {

View File

@ -11,5 +11,5 @@ pub extern fn __umodti3(a: u128, b: u128) u128 {
pub extern fn __umodti3_windows_x86_64(a: &const u128, b: &const u128) void {
@setRuntimeSafety(builtin.is_test);
compiler_rt.setXmm0(u128, __umodti3(*a, *b));
compiler_rt.setXmm0(u128, __umodti3(a.*, b.*));
}

View File

@ -40,7 +40,7 @@ pub const Tree = struct {
};
pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {
var loc = Location {
var loc = Location{
.line = 0,
.column = 0,
.line_start = start_index,
@ -71,7 +71,6 @@ pub const Tree = struct {
pub fn dump(self: &Tree) void {
self.root_node.base.dump(0);
}
};
pub const Error = union(enum) {
@ -95,7 +94,7 @@ pub const Error = union(enum) {
ExpectedCommaOrEnd: ExpectedCommaOrEnd,
pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
switch (*self) {
switch (self.*) {
// TODO https://github.com/zig-lang/zig/issues/683
@TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
@TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
@ -119,7 +118,7 @@ pub const Error = union(enum) {
}
pub fn loc(self: &Error) TokenIndex {
switch (*self) {
switch (self.*) {
// TODO https://github.com/zig-lang/zig/issues/683
@TagType(Error).InvalidToken => |x| return x.token,
@TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
@ -144,15 +143,12 @@ pub const Error = union(enum) {
pub const InvalidToken = SingleTokenError("Invalid token {}");
pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
pub const ExpectedAggregateKw = SingleTokenError("Expected " ++
@tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++
@tagName(Token.Id.Keyword_enum) ++ ", found {}");
pub const ExpectedAggregateKw = SingleTokenError("Expected " ++ @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++ @tagName(Token.Id.Keyword_enum) ++ ", found {}");
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++
@tagName(Token.Id.Identifier) ++ ", found {}");
pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++ @tagName(Token.Id.Identifier) ++ ", found {}");
pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
@ -165,8 +161,7 @@ pub const Error = union(enum) {
node: &Node,
pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}",
@tagName(self.node.id));
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", @tagName(self.node.id));
}
};
@ -174,8 +169,7 @@ pub const Error = union(enum) {
node: &Node,
pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
@tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++ @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
}
};
@ -445,17 +439,17 @@ pub const Node = struct {
pub fn iterate(self: &Root, index: usize) ?&Node {
if (index < self.decls.len) {
return *self.decls.at(index);
return self.decls.at(index).*;
}
return null;
}
pub fn firstToken(self: &Root) TokenIndex {
return if (self.decls.len == 0) self.eof_token else (*self.decls.at(0)).firstToken();
return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();
}
pub fn lastToken(self: &Root) TokenIndex {
return if (self.decls.len == 0) self.eof_token else (*self.decls.at(self.decls.len - 1)).lastToken();
return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken();
}
};
@ -545,7 +539,7 @@ pub const Node = struct {
pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
var i = index;
if (i < self.decls.len) return *self.decls.at(i);
if (i < self.decls.len) return self.decls.at(i).*;
i -= self.decls.len;
return null;
@ -598,10 +592,10 @@ pub const Node = struct {
i -= 1;
},
InitArg.None,
InitArg.Enum => { }
InitArg.Enum => {},
}
if (i < self.fields_and_decls.len) return *self.fields_and_decls.at(i);
if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
i -= self.fields_and_decls.len;
return null;
@ -814,7 +808,7 @@ pub const Node = struct {
i -= 1;
}
if (i < self.params.len) return *self.params.at(self.params.len - i - 1);
if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;
i -= self.params.len;
if (self.align_expr) |align_expr| {
@ -839,7 +833,6 @@ pub const Node = struct {
i -= 1;
}
return null;
}
@ -934,7 +927,7 @@ pub const Node = struct {
pub fn iterate(self: &Block, index: usize) ?&Node {
var i = index;
if (i < self.statements.len) return *self.statements.at(i);
if (i < self.statements.len) return self.statements.at(i).*;
i -= self.statements.len;
return null;
@ -1119,6 +1112,7 @@ pub const Node = struct {
base: Node,
switch_token: TokenIndex,
expr: &Node,
/// these can be SwitchCase nodes or LineComment nodes
cases: CaseList,
rbrace: TokenIndex,
@ -1131,7 +1125,7 @@ pub const Node = struct {
if (i < 1) return self.expr;
i -= 1;
if (i < self.cases.len) return *self.cases.at(i);
if (i < self.cases.len) return self.cases.at(i).*;
i -= self.cases.len;
return null;
@ -1157,7 +1151,7 @@ pub const Node = struct {
pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
var i = index;
if (i < self.items.len) return *self.items.at(i);
if (i < self.items.len) return self.items.at(i).*;
i -= self.items.len;
if (self.payload) |payload| {
@ -1172,7 +1166,7 @@ pub const Node = struct {
}
pub fn firstToken(self: &SwitchCase) TokenIndex {
return (*self.items.at(0)).firstToken();
return (self.items.at(0).*).firstToken();
}
pub fn lastToken(self: &SwitchCase) TokenIndex {
@ -1491,7 +1485,7 @@ pub const Node = struct {
BitNot,
BoolNot,
Cancel,
Deref,
PointerType,
MaybeType,
Negation,
NegationWrap,
@ -1533,7 +1527,6 @@ pub const Node = struct {
Op.BitNot,
Op.BoolNot,
Op.Cancel,
Op.Deref,
Op.MaybeType,
Op.Negation,
Op.NegationWrap,
@ -1593,6 +1586,7 @@ pub const Node = struct {
Slice: Slice,
ArrayInitializer: InitList,
StructInitializer: InitList,
Deref,
pub const InitList = SegmentedList(&Node, 2);
@ -1617,7 +1611,7 @@ pub const Node = struct {
switch (self.op) {
@TagType(Op).Call => |*call_info| {
if (i < call_info.params.len) return *call_info.params.at(i);
if (i < call_info.params.len) return call_info.params.at(i).*;
i -= call_info.params.len;
},
Op.ArrayAccess => |index_expr| {
@ -1634,11 +1628,11 @@ pub const Node = struct {
}
},
Op.ArrayInitializer => |*exprs| {
if (i < exprs.len) return *exprs.at(i);
if (i < exprs.len) return exprs.at(i).*;
i -= exprs.len;
},
Op.StructInitializer => |*fields| {
if (i < fields.len) return *fields.at(i);
if (i < fields.len) return fields.at(i).*;
i -= fields.len;
},
}
@ -1831,7 +1825,7 @@ pub const Node = struct {
pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
var i = index;
if (i < self.params.len) return *self.params.at(i);
if (i < self.params.len) return self.params.at(i).*;
i -= self.params.len;
return null;
@ -1874,11 +1868,11 @@ pub const Node = struct {
}
pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {
return *self.lines.at(0);
return self.lines.at(0).*;
}
pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {
return *self.lines.at(self.lines.len - 1);
return self.lines.at(self.lines.len - 1).*;
}
};
@ -1975,7 +1969,7 @@ pub const Node = struct {
const Kind = union(enum) {
Variable: &Identifier,
Return: &Node
Return: &Node,
};
pub fn iterate(self: &AsmOutput, index: usize) ?&Node {
@ -1995,7 +1989,7 @@ pub const Node = struct {
Kind.Return => |return_type| {
if (i < 1) return return_type;
i -= 1;
}
},
}
return null;
@ -2060,13 +2054,13 @@ pub const Node = struct {
pub fn iterate(self: &Asm, index: usize) ?&Node {
var i = index;
if (i < self.outputs.len) return &(*self.outputs.at(index)).base;
if (i < self.outputs.len) return &(self.outputs.at(index).*).base;
i -= self.outputs.len;
if (i < self.inputs.len) return &(*self.inputs.at(index)).base;
if (i < self.inputs.len) return &(self.inputs.at(index).*).base;
i -= self.inputs.len;
if (i < self.clobbers.len) return *self.clobbers.at(index);
if (i < self.clobbers.len) return self.clobbers.at(index).*;
i -= self.clobbers.len;
return null;
@ -2160,11 +2154,11 @@ pub const Node = struct {
}
pub fn firstToken(self: &DocComment) TokenIndex {
return *self.lines.at(0);
return self.lines.at(0).*;
}
pub fn lastToken(self: &DocComment) TokenIndex {
return *self.lines.at(self.lines.len - 1);
return self.lines.at(self.lines.len - 1).*;
}
};
@ -2193,4 +2187,3 @@ pub const Node = struct {
}
};
};

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ const Token = std.zig.Token;
const indent_delta = 4;
pub const Error = error {
pub const Error = error{
/// Ran out of memory allocating call stack frames to complete rendering.
OutOfMemory,
};
@ -17,9 +17,9 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(
var it = tree.root_node.decls.iterator(0);
while (it.next()) |decl| {
try renderTopLevelDecl(allocator, stream, tree, 0, *decl);
try renderTopLevelDecl(allocator, stream, tree, 0, decl.*);
if (it.peek()) |next_decl| {
const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -154,10 +154,10 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = block.statements.iterator(0);
while (it.next()) |statement| {
try stream.writeByteNTimes(' ', block_indent);
try renderStatement(allocator, stream, tree, block_indent, *statement);
try renderStatement(allocator, stream, tree, block_indent, statement.*);
if (it.peek()) |next_statement| {
const n = if (nodeLineOffset(tree, *statement, *next_statement) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, statement.*, next_statement.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -203,7 +203,6 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try stream.write(" ");
try renderExpression(allocator, stream, tree, indent, body);
}
},
ast.Node.Id.InfixOp => {
@ -307,12 +306,12 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
},
ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
ast.Node.PrefixOp.Op.Try => try stream.write("try "),
ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
ast.Node.PrefixOp.Op.PointerType => try stream.write("*"),
ast.Node.PrefixOp.Op.Await => try stream.write("await "),
ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
@ -336,7 +335,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = call_info.params.iterator(0);
while (it.next()) |param_node| {
try renderExpression(allocator, stream, tree, indent, *param_node);
try renderExpression(allocator, stream, tree, indent, param_node.*);
if (it.peek() != null) {
try stream.write(", ");
}
@ -352,6 +351,11 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try stream.write("]");
},
ast.Node.SuffixOp.Op.Deref => {
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
try stream.write(".*");
},
@TagType(ast.Node.SuffixOp.Op).Slice => |range| {
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
try stream.write("[");
@ -371,7 +375,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
}
if (field_inits.len == 1) {
const field_init = *field_inits.at(0);
const field_init = field_inits.at(0).*;
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
try stream.write("{ ");
@ -388,12 +392,12 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = field_inits.iterator(0);
while (it.next()) |field_init| {
try stream.writeByteNTimes(' ', new_indent);
try renderExpression(allocator, stream, tree, new_indent, *field_init);
if ((*field_init).id != ast.Node.Id.LineComment) {
try renderExpression(allocator, stream, tree, new_indent, field_init.*);
if ((field_init.*).id != ast.Node.Id.LineComment) {
try stream.write(",");
}
if (it.peek()) |next_field_init| {
const n = if (nodeLineOffset(tree, *field_init, *next_field_init) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, field_init.*, next_field_init.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -404,14 +408,13 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
},
ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
if (exprs.len == 0) {
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
try stream.write("{}");
return;
}
if (exprs.len == 1) {
const expr = *exprs.at(0);
const expr = exprs.at(0).*;
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
try stream.write("{");
@ -428,11 +431,11 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = exprs.iterator(0);
while (it.next()) |expr| {
try stream.writeByteNTimes(' ', new_indent);
try renderExpression(allocator, stream, tree, new_indent, *expr);
try renderExpression(allocator, stream, tree, new_indent, expr.*);
try stream.write(",");
if (it.peek()) |next_expr| {
const n = if (nodeLineOffset(tree, *expr, *next_expr) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, expr.*, next_expr.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -465,7 +468,6 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
ast.Node.ControlFlowExpression.Kind.Return => {
try stream.print("return");
},
}
if (flow_expr.rhs) |rhs| {
@ -571,7 +573,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
switch (container_decl.layout) {
ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
ast.Node.ContainerDecl.Layout.Auto => { },
ast.Node.ContainerDecl.Layout.Auto => {},
}
switch (container_decl.kind) {
@ -607,10 +609,10 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = container_decl.fields_and_decls.iterator(0);
while (it.next()) |decl| {
try stream.writeByteNTimes(' ', new_indent);
try renderTopLevelDecl(allocator, stream, tree, new_indent, *decl);
try renderTopLevelDecl(allocator, stream, tree, new_indent, decl.*);
if (it.peek()) |next_decl| {
const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -630,7 +632,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
}
if (err_set_decl.decls.len == 1) blk: {
const node = *err_set_decl.decls.at(0);
const node = err_set_decl.decls.at(0).*;
// if there are any doc comments or same line comments
// don't try to put it all on one line
@ -640,7 +642,6 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
break :blk;
}
try stream.write("error{");
try renderTopLevelDecl(allocator, stream, tree, indent, node);
try stream.write("}");
@ -653,12 +654,12 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = err_set_decl.decls.iterator(0);
while (it.next()) |node| {
try stream.writeByteNTimes(' ', new_indent);
try renderTopLevelDecl(allocator, stream, tree, new_indent, *node);
if ((*node).id != ast.Node.Id.LineComment) {
try renderTopLevelDecl(allocator, stream, tree, new_indent, node.*);
if ((node.*).id != ast.Node.Id.LineComment) {
try stream.write(",");
}
if (it.peek()) |next_node| {
const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -672,9 +673,9 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
try stream.print("\n");
var i : usize = 0;
var i: usize = 0;
while (i < multiline_str_literal.lines.len) : (i += 1) {
const t = *multiline_str_literal.lines.at(i);
const t = multiline_str_literal.lines.at(i).*;
try stream.writeByteNTimes(' ', indent + indent_delta);
try stream.print("{}", tree.tokenSlice(t));
}
@ -691,7 +692,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = builtin_call.params.iterator(0);
while (it.next()) |param_node| {
try renderExpression(allocator, stream, tree, indent, *param_node);
try renderExpression(allocator, stream, tree, indent, param_node.*);
if (it.peek() != null) {
try stream.write(", ");
}
@ -736,7 +737,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = fn_proto.params.iterator(0);
while (it.next()) |param_decl_node| {
try renderParamDecl(allocator, stream, tree, indent, *param_decl_node);
try renderParamDecl(allocator, stream, tree, indent, param_decl_node.*);
if (it.peek() != null) {
try stream.write(", ");
@ -760,7 +761,6 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try renderExpression(allocator, stream, tree, indent, node);
},
}
},
ast.Node.Id.PromiseType => {
@ -797,10 +797,10 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = switch_node.cases.iterator(0);
while (it.next()) |node| {
try stream.writeByteNTimes(' ', new_indent);
try renderExpression(allocator, stream, tree, new_indent, *node);
try renderExpression(allocator, stream, tree, new_indent, node.*);
if (it.peek()) |next_node| {
const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);
try stream.writeByteNTimes('\n', n);
}
}
@ -815,7 +815,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
var it = switch_case.items.iterator(0);
while (it.next()) |node| {
try renderExpression(allocator, stream, tree, indent, *node);
try renderExpression(allocator, stream, tree, indent, node.*);
if (it.peek() != null) {
try stream.write(",\n");
@ -864,8 +864,10 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try stream.print("{}", tree.tokenSlice(else_node.else_token));
const block_body = switch (else_node.body.id) {
ast.Node.Id.Block, ast.Node.Id.If,
ast.Node.Id.For, ast.Node.Id.While,
ast.Node.Id.Block,
ast.Node.Id.If,
ast.Node.Id.For,
ast.Node.Id.While,
ast.Node.Id.Switch => true,
else => false,
};
@ -990,7 +992,11 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try renderExpression(allocator, stream, tree, indent, if_node.body);
switch (if_node.body.id) {
ast.Node.Id.Block, ast.Node.Id.If, ast.Node.Id.For, ast.Node.Id.While, ast.Node.Id.Switch => {
ast.Node.Id.Block,
ast.Node.Id.If,
ast.Node.Id.For,
ast.Node.Id.While,
ast.Node.Id.Switch => {
if (if_node.@"else") |@"else"| {
if (if_node.body.id == ast.Node.Id.Block) {
try stream.write(" ");
@ -1013,7 +1019,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
try renderExpression(allocator, stream, tree, indent, @"else".body);
}
}
},
}
},
@ -1036,11 +1042,11 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
{
var it = asm_node.outputs.iterator(0);
while (it.next()) |asm_output| {
const node = &(*asm_output).base;
const node = &(asm_output.*).base;
try renderExpression(allocator, stream, tree, indent_extra, node);
if (it.peek()) |next_asm_output| {
const next_node = &(*next_asm_output).base;
const next_node = &(next_asm_output.*).base;
const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
try stream.writeByte(',');
try stream.writeByteNTimes('\n', n);
@ -1056,11 +1062,11 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
{
var it = asm_node.inputs.iterator(0);
while (it.next()) |asm_input| {
const node = &(*asm_input).base;
const node = &(asm_input.*).base;
try renderExpression(allocator, stream, tree, indent_extra, node);
if (it.peek()) |next_asm_input| {
const next_node = &(*next_asm_input).base;
const next_node = &(next_asm_input.*).base;
const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
try stream.writeByte(',');
try stream.writeByteNTimes('\n', n);
@ -1076,7 +1082,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
{
var it = asm_node.clobbers.iterator(0);
while (it.next()) |node| {
try renderExpression(allocator, stream, tree, indent_once, *node);
try renderExpression(allocator, stream, tree, indent_once, node.*);
if (it.peek() != null) {
try stream.write(", ");
@ -1245,8 +1251,7 @@ fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@type
const comment = node.doc_comments ?? return;
var it = comment.lines.iterator(0);
while (it.next()) |line_token_index| {
try stream.print("{}\n", tree.tokenSlice(*line_token_index));
try stream.print("{}\n", tree.tokenSlice(line_token_index.*));
try stream.writeByteNTimes(' ', indent);
}
}

View File

@ -35,6 +35,7 @@ comptime {
_ = @import("cases/namespace_depends_on_compile_var/index.zig");
_ = @import("cases/new_stack_call.zig");
_ = @import("cases/null.zig");
_ = @import("cases/pointers.zig");
_ = @import("cases/pub_enum/index.zig");
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
_ = @import("cases/reflection.zig");

View File

@ -10,7 +10,9 @@ test "global variable alignment" {
assert(@typeOf(slice) == []align(4) u8);
}
fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
fn derp() align(@sizeOf(usize) * 2) i32 {
return 1234;
}
fn noop1() align(1) void {}
fn noop4() align(4) void {}
@ -22,7 +24,6 @@ test "function alignment" {
noop4();
}
var baz: packed struct {
a: u32,
b: u32,
@ -32,7 +33,6 @@ test "packed struct alignment" {
assert(@typeOf(&baz.b) == &align(1) u32);
}
const blah: packed struct {
a: u3,
b: u3,
@ -53,29 +53,43 @@ test "implicitly decreasing pointer alignment" {
assert(addUnaligned(&a, &b) == 7);
}
fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) u32 { return *a + *b; }
fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) u32 {
return a.* + b.*;
}
test "implicitly decreasing slice alignment" {
const a: u32 align(4) = 3;
const b: u32 align(8) = 4;
assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
}
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; }
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
return a[0] + b[0];
}
test "specifying alignment allows pointer cast" {
testBytesAlign(0x33);
}
fn testBytesAlign(b: u8) void {
var bytes align(4) = []u8{b, b, b, b};
var bytes align(4) = []u8 {
b,
b,
b,
b,
};
const ptr = @ptrCast(&u32, &bytes[0]);
assert(*ptr == 0x33333333);
assert(ptr.* == 0x33333333);
}
test "specifying alignment allows slice cast" {
testBytesAlignSlice(0x33);
}
fn testBytesAlignSlice(b: u8) void {
var bytes align(4) = []u8{b, b, b, b};
var bytes align(4) = []u8 {
b,
b,
b,
b,
};
const slice = ([]u32)(bytes[0..]);
assert(slice[0] == 0x33333333);
}
@ -89,11 +103,14 @@ fn expectsOnly1(x: &align(1) u32) void {
expects4(@alignCast(4, x));
}
fn expects4(x: &align(4) u32) void {
*x += 1;
x.* += 1;
}
test "@alignCast slices" {
var array align(4) = []u32{1, 1};
var array align(4) = []u32 {
1,
1,
};
const slice = array[0..];
sliceExpectsOnly1(slice);
assert(slice[0] == 2);
@ -105,31 +122,34 @@ fn sliceExpects4(slice: []align(4) u32) void {
slice[0] += 1;
}
test "implicitly decreasing fn alignment" {
testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
testImplicitlyDecreaseFnAlign(alignedBig, 5678);
}
fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
fn testImplicitlyDecreaseFnAlign(ptr: fn() align(1) i32, answer: i32) void {
assert(ptr() == answer);
}
fn alignedSmall() align(8) i32 { return 1234; }
fn alignedBig() align(16) i32 { return 5678; }
fn alignedSmall() align(8) i32 {
return 1234;
}
fn alignedBig() align(16) i32 {
return 5678;
}
test "@alignCast functions" {
assert(fnExpectsOnly1(simple4) == 0x19);
}
fn fnExpectsOnly1(ptr: fn()align(1) i32) i32 {
fn fnExpectsOnly1(ptr: fn() align(1) i32) i32 {
return fnExpects4(@alignCast(4, ptr));
}
fn fnExpects4(ptr: fn()align(4) i32) i32 {
fn fnExpects4(ptr: fn() align(4) i32) i32 {
return ptr();
}
fn simple4() align(4) i32 { return 0x19; }
fn simple4() align(4) i32 {
return 0x19;
}
test "generic function with align param" {
assert(whyWouldYouEverDoThis(1) == 0x1);
@ -137,8 +157,9 @@ test "generic function with align param" {
assert(whyWouldYouEverDoThis(8) == 0x1);
}
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { return 0x1; }
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
return 0x1;
}
test "@ptrCast preserves alignment of bigger source" {
var x: u32 align(16) = 1234;
@ -146,24 +167,38 @@ test "@ptrCast preserves alignment of bigger source" {
assert(@typeOf(ptr) == &align(16) u8);
}
test "compile-time known array index has best alignment possible" {
// take full advantage of over-alignment
var array align(4) = []u8 {1, 2, 3, 4};
var array align(4) = []u8 {
1,
2,
3,
4,
};
assert(@typeOf(&array[0]) == &align(4) u8);
assert(@typeOf(&array[1]) == &u8);
assert(@typeOf(&array[2]) == &align(2) u8);
assert(@typeOf(&array[3]) == &u8);
// because align is too small but we still figure out to use 2
var bigger align(2) = []u64{1, 2, 3, 4};
var bigger align(2) = []u64 {
1,
2,
3,
4,
};
assert(@typeOf(&bigger[0]) == &align(2) u64);
assert(@typeOf(&bigger[1]) == &align(2) u64);
assert(@typeOf(&bigger[2]) == &align(2) u64);
assert(@typeOf(&bigger[3]) == &align(2) u64);
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
var smaller align(2) = []u32{1, 2, 3, 4};
var smaller align(2) = []u32 {
1,
2,
3,
4,
};
testIndex(&smaller[0], 0, &align(2) u32);
testIndex(&smaller[0], 1, &align(2) u32);
testIndex(&smaller[0], 2, &align(2) u32);
@ -182,7 +217,6 @@ fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) void {
assert(@typeOf(&ptr[index]) == T);
}
test "alignstack" {
assert(fnWithAlignedStack() == 1234);
}

View File

@ -1,7 +1,11 @@
const assert = @import("std").debug.assert;
const builtin = @import("builtin");
const Foo = struct { x: u32, y: u32, z: u32, };
const Foo = struct {
x: u32,
y: u32,
z: u32,
};
test "@alignOf(T) before referencing T" {
comptime assert(@alignOf(Foo) != @maxValue(usize));

View File

@ -2,9 +2,9 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
test "arrays" {
var array : [5]u32 = undefined;
var array: [5]u32 = undefined;
var i : u32 = 0;
var i: u32 = 0;
while (i < 5) {
array[i] = i + 1;
i = array[i];
@ -34,24 +34,41 @@ test "void arrays" {
}
test "array literal" {
const hex_mult = []u16{4096, 256, 16, 1};
const hex_mult = []u16 {
4096,
256,
16,
1,
};
assert(hex_mult.len == 4);
assert(hex_mult[1] == 256);
}
test "array dot len const expr" {
assert(comptime x: {break :x some_array.len == 4;});
assert(comptime x: {
break :x some_array.len == 4;
});
}
const ArrayDotLenConstExpr = struct {
y: [some_array.len]u8,
};
const some_array = []u8 {0, 1, 2, 3};
const some_array = []u8 {
0,
1,
2,
3,
};
test "nested arrays" {
const array_of_strings = [][]const u8 {"hello", "this", "is", "my", "thing"};
const array_of_strings = [][]const u8 {
"hello",
"this",
"is",
"my",
"thing",
};
for (array_of_strings) |s, i| {
if (i == 0) assert(mem.eql(u8, s, "hello"));
if (i == 1) assert(mem.eql(u8, s, "this"));
@ -61,7 +78,6 @@ test "nested arrays" {
}
}
var s_array: [8]Sub = undefined;
const Sub = struct {
b: u8,
@ -70,7 +86,9 @@ const Str = struct {
a: []Sub,
};
test "set global var array via slice embedded in struct" {
var s = Str { .a = s_array[0..]};
var s = Str {
.a = s_array[0..],
};
s.a[0].b = 1;
s.a[1].b = 2;
@ -82,7 +100,10 @@ test "set global var array via slice embedded in struct" {
}
test "array literal with specified size" {
var array = [2]u8{1, 2};
var array = [2]u8 {
1,
2,
};
assert(array[0] == 1);
assert(array[1] == 2);
}

View File

@ -10,5 +10,9 @@ fn testBitCast_i32_u32() void {
assert(conv2(@maxValue(u32)) == -1);
}
fn conv(x: i32) u32 { return @bitCast(u32, x); }
fn conv2(x: u32) i32 { return @bitCast(i32, x); }
fn conv(x: i32) u32 {
return @bitCast(u32, x);
}
fn conv2(x: u32) i32 {
return @bitCast(i32, x);
}

View File

@ -1,9 +1,20 @@
const E = union(enum) { A: [9]u8, B: u64, };
const S = struct { x: u8, y: E, };
const E = union(enum) {
A: [9]u8,
B: u64,
};
const S = struct {
x: u8,
y: E,
};
const assert = @import("std").debug.assert;
test "bug 394 fixed" {
const x = S { .x = 3, .y = E {.B = 1 } };
const x = S {
.x = 3,
.y = E {
.B = 1,
},
};
assert(x.x == 3);
}

View File

@ -8,5 +8,5 @@ test "function with &const parameter with type dereferenced by namespace" {
}
fn foo(x: &const other_file.Integer) void {
std.debug.assert(*x == 1234);
std.debug.assert(x.* == 1234);
}

View File

@ -14,12 +14,15 @@ test "nullable if after an if in a switch prong of a switch with 2 prongs in an
}
fn foo(a: bool, b: bool) void {
var prefix_op = PrefixOp { .AddrOf = Value { .align_expr = 1234 } };
if (a) {
} else {
var prefix_op = PrefixOp {
.AddrOf = Value {
.align_expr = 1234,
},
};
if (a) {} else {
switch (prefix_op) {
PrefixOp.AddrOf => |addr_of_info| {
if (b) { }
if (b) {}
if (addr_of_info.align_expr) |align_expr| {
assert(align_expr == 1234);
}

View File

@ -1,10 +1,10 @@
const CountBy = struct {
a: usize,
const One = CountBy {
.a = 1,
};
pub fn counter(self: &const CountBy) Counter {
return Counter {
.i = 0,
@ -14,7 +14,7 @@ const CountBy = struct {
const Counter = struct {
i: usize,
pub fn count(self: &Counter) bool {
self.i += 1;
return self.i <= 10;
@ -24,8 +24,8 @@ const Counter = struct {
fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
comptime {
var cnt = cb.counter();
if(cnt.i != 0) @compileError("Counter instance reused!");
while(cnt.count()){}
if (cnt.i != 0) @compileError("Counter instance reused!");
while (cnt.count()) {}
}
}

View File

@ -12,8 +12,7 @@ const ZigTable = struct {
zero_case: fn(&Random, f64) f64,
};
fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64,
comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64, comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
var tables: ZigTable = undefined;
tables.is_symmetric = is_symmetric;
@ -26,12 +25,12 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
for (tables.x[2..256]) |*entry, i| {
const last = tables.x[2 + i - 1];
*entry = f_inv(v / last + f(last));
entry.* = f_inv(v / last + f(last));
}
tables.x[256] = 0;
for (tables.f[0..]) |*entry, i| {
*entry = f(tables.x[i]);
entry.* = f(tables.x[i]);
}
return tables;
@ -40,9 +39,15 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
const norm_r = 3.6541528853610088;
const norm_v = 0.00492867323399;
fn norm_f(x: f64) f64 { return math.exp(-x * x / 2.0); }
fn norm_f_inv(y: f64) f64 { return math.sqrt(-2.0 * math.ln(y)); }
fn norm_zero_case(random: &Random, u: f64) f64 { return 0.0; }
fn norm_f(x: f64) f64 {
return math.exp(-x * x / 2.0);
}
fn norm_f_inv(y: f64) f64 {
return math.sqrt(-2.0 * math.ln(y));
}
fn norm_zero_case(random: &Random, u: f64) f64 {
return 0.0;
}
const NormalDist = blk: {
@setEvalBranchQuota(30000);

View File

@ -17,7 +17,7 @@ test "pointer reinterpret const float to int" {
const float: f64 = 5.99999999999994648725e-01;
const float_ptr = &float;
const int_ptr = @ptrCast(&const i32, float_ptr);
const int_val = *int_ptr;
const int_val = int_ptr.*;
assert(int_val == 858993411);
}
@ -29,25 +29,31 @@ test "implicitly cast a pointer to a const pointer of it" {
}
fn funcWithConstPtrPtr(x: &const &i32) void {
**x += 1;
x.*.* += 1;
}
test "implicitly cast a container to a const pointer of it" {
const z = Struct(void) { .x = void{} };
const z = Struct(void) {
.x = void{},
};
assert(0 == @sizeOf(@typeOf(z)));
assert(void{} == Struct(void).pointer(z).x);
assert(void{} == Struct(void).pointer(&z).x);
assert(void{} == Struct(void).maybePointer(z).x);
assert(void{} == Struct(void).maybePointer(&z).x);
assert(void{} == Struct(void).maybePointer(null).x);
const s = Struct(u8) { .x = 42 };
const s = Struct(u8) {
.x = 42,
};
assert(0 != @sizeOf(@typeOf(s)));
assert(42 == Struct(u8).pointer(s).x);
assert(42 == Struct(u8).pointer(&s).x);
assert(42 == Struct(u8).maybePointer(s).x);
assert(42 == Struct(u8).maybePointer(&s).x);
assert(0 == Struct(u8).maybePointer(null).x);
const u = Union { .x = 42 };
const u = Union {
.x = 42,
};
assert(42 == Union.pointer(u).x);
assert(42 == Union.pointer(&u).x);
assert(42 == Union.maybePointer(u).x);
@ -67,12 +73,14 @@ fn Struct(comptime T: type) type {
x: T,
fn pointer(self: &const Self) Self {
return *self;
return self.*;
}
fn maybePointer(self: ?&const Self) Self {
const none = Self { .x = if (T == void) void{} else 0 };
return *(self ?? &none);
const none = Self {
.x = if (T == void) void{} else 0,
};
return (self ?? &none).*;
}
};
}
@ -81,12 +89,14 @@ const Union = union {
x: u8,
fn pointer(self: &const Union) Union {
return *self;
return self.*;
}
fn maybePointer(self: ?&const Union) Union {
const none = Union { .x = 0 };
return *(self ?? &none);
const none = Union {
.x = 0,
};
return (self ?? &none).*;
}
};
@ -95,11 +105,11 @@ const Enum = enum {
Some,
fn pointer(self: &const Enum) Enum {
return *self;
return self.*;
}
fn maybePointer(self: ?&const Enum) Enum {
return *(self ?? &Enum.None);
return (self ?? &Enum.None).*;
}
};
@ -108,19 +118,21 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
const Self = this;
x: u8,
fn constConst(p: &const &const Self) u8 {
return (*p).x;
return (p.*).x;
}
fn maybeConstConst(p: ?&const &const Self) u8 {
return (*??p).x;
return ((??p).*).x;
}
fn constConstConst(p: &const &const &const Self) u8 {
return (**p).x;
return (p.*.*).x;
}
fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
return (**??p).x;
return ((??p).*.*).x;
}
};
const s = S { .x = 42 };
const s = S {
.x = 42,
};
const p = &s;
const q = &p;
const r = &q;
@ -154,7 +166,6 @@ fn boolToStr(b: bool) []const u8 {
return if (b) "true" else "false";
}
test "peer resolve array and const slice" {
testPeerResolveArrayConstSlice(true);
comptime testPeerResolveArrayConstSlice(true);
@ -168,12 +179,12 @@ fn testPeerResolveArrayConstSlice(b: bool) void {
test "integer literal to &const int" {
const x: &const i32 = 3;
assert(*x == 3);
assert(x.* == 3);
}
test "string literal to &const []const u8" {
const x: &const []const u8 = "hello";
assert(mem.eql(u8, *x, "hello"));
assert(mem.eql(u8, x.*, "hello"));
}
test "implicitly cast from T to error!?T" {
@ -191,7 +202,9 @@ fn castToMaybeTypeError(z: i32) void {
const f = z;
const g: error!?i32 = f;
const a = A{ .a = z };
const a = A {
.a = z,
};
const b: error!?A = a;
assert((??(b catch unreachable)).a == 1);
}
@ -205,7 +218,6 @@ fn implicitIntLitToMaybe() void {
const g: error!?i32 = 1;
}
test "return null from fn() error!?&T" {
const a = returnNullFromMaybeTypeErrorRef();
const b = returnNullLitFromMaybeTypeErrorRef();
@ -235,7 +247,6 @@ fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
return usize(3);
}
test "peer type resolution: [0]u8 and []const u8" {
assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
@ -246,7 +257,7 @@ test "peer type resolution: [0]u8 and []const u8" {
}
fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
if (a) {
return []const u8 {};
return []const u8{};
}
return slice[0..1];
@ -261,7 +272,6 @@ fn castToMaybeSlice() ?[]const u8 {
return "hi";
}
test "implicitly cast from [0]T to error![]T" {
testCastZeroArrayToErrSliceMut();
comptime testCastZeroArrayToErrSliceMut();
@ -329,7 +339,6 @@ fn foo(args: ...) void {
assert(@typeOf(args[0]) == &const [5]u8);
}
test "peer type resolution: error and [N]T" {
// TODO: implicit error!T to error!U where T can implicitly cast to U
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
@ -378,7 +387,12 @@ fn cast128Float(x: u128) f128 {
}
test "const slice widen cast" {
const bytes align(4) = []u8{0x12, 0x12, 0x12, 0x12};
const bytes align(4) = []u8 {
0x12,
0x12,
0x12,
0x12,
};
const u32_value = ([]const u32)(bytes[0..])[0];
assert(u32_value == 0x12121212);

View File

@ -36,7 +36,7 @@ async fn testAsyncSeq() void {
suspend;
seq('d');
}
var points = []u8{0} ** "abcdefg".len;
var points = []u8 {0} ** "abcdefg".len;
var index: usize = 0;
fn seq(c: u8) void {
@ -94,7 +94,7 @@ async fn await_another() i32 {
return 1234;
}
var await_points = []u8{0} ** "abcdefghi".len;
var await_points = []u8 {0} ** "abcdefghi".len;
var await_seq_index: usize = 0;
fn await_seq(c: u8) void {
@ -102,7 +102,6 @@ fn await_seq(c: u8) void {
await_seq_index += 1;
}
var early_final_result: i32 = 0;
test "coroutine await early return" {
@ -126,7 +125,7 @@ async fn early_another() i32 {
return 1234;
}
var early_points = []u8{0} ** "abcdef".len;
var early_points = []u8 {0} ** "abcdef".len;
var early_seq_index: usize = 0;
fn early_seq(c: u8) void {
@ -175,8 +174,8 @@ test "async fn pointer in a struct field" {
}
async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
defer *y += 2;
*y += 1;
defer y.* += 2;
y.* += 1;
suspend;
}
@ -205,7 +204,8 @@ test "error return trace across suspend points - async return" {
cancel p2;
}
fn nonFailing() promise->error!void {
// TODO https://github.com/zig-lang/zig/issues/760
fn nonFailing() (promise->error!void) {
return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
}
@ -239,7 +239,7 @@ async fn testBreakFromSuspend(my_result: &i32) void {
s: suspend |p| {
break :s;
}
*my_result += 1;
my_result.* += 1;
suspend;
*my_result += 1;
my_result.* += 1;
}

View File

@ -5,9 +5,18 @@ var index: usize = undefined;
fn runSomeErrorDefers(x: bool) !bool {
index = 0;
defer {result[index] = 'a'; index += 1;}
errdefer {result[index] = 'b'; index += 1;}
defer {result[index] = 'c'; index += 1;}
defer {
result[index] = 'a';
index += 1;
}
errdefer {
result[index] = 'b';
index += 1;
}
defer {
result[index] = 'c';
index += 1;
}
return if (x) x else error.FalseNotAllowed;
}

View File

@ -2,8 +2,15 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
test "enum type" {
const foo1 = Foo{ .One = 13};
const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
const foo1 = Foo {
.One = 13,
};
const foo2 = Foo {
.Two = Point {
.x = 1234,
.y = 5678,
},
};
const bar = Bar.B;
assert(bar == Bar.B);
@ -41,26 +48,31 @@ const Bar = enum {
};
fn returnAnInt(x: i32) Foo {
return Foo { .One = x };
return Foo {
.One = x,
};
}
test "constant enum with payload" {
var empty = AnEnumWithPayload {.Empty = {}};
var full = AnEnumWithPayload {.Full = 13};
var empty = AnEnumWithPayload {
.Empty = {},
};
var full = AnEnumWithPayload {
.Full = 13,
};
shouldBeEmpty(empty);
shouldBeNotEmpty(full);
}
fn shouldBeEmpty(x: &const AnEnumWithPayload) void {
switch (*x) {
switch (x.*) {
AnEnumWithPayload.Empty => {},
else => unreachable,
}
}
fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {
switch (*x) {
switch (x.*) {
AnEnumWithPayload.Empty => unreachable,
else => {},
}
@ -71,8 +83,6 @@ const AnEnumWithPayload = union(enum) {
Full: i32,
};
const Number = enum {
Zero,
One,
@ -93,7 +103,6 @@ fn shouldEqual(n: Number, expected: u3) void {
assert(u3(n) == expected);
}
test "int to enum" {
testIntToEnumEval(3);
}
@ -108,7 +117,6 @@ const IntToEnumNumber = enum {
Four,
};
test "@tagName" {
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
@ -124,7 +132,6 @@ const BareNumber = enum {
Three,
};
test "enum alignment" {
comptime {
assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
@ -137,47 +144,529 @@ const AlignTestEnum = union(enum) {
B: u64,
};
const ValueCount1 = enum { I0 };
const ValueCount2 = enum { I0, I1 };
const ValueCount1 = enum {
I0,
};
const ValueCount2 = enum {
I0,
I1,
};
const ValueCount256 = enum {
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
I250, I251, I252, I253, I254, I255
I0,
I1,
I2,
I3,
I4,
I5,
I6,
I7,
I8,
I9,
I10,
I11,
I12,
I13,
I14,
I15,
I16,
I17,
I18,
I19,
I20,
I21,
I22,
I23,
I24,
I25,
I26,
I27,
I28,
I29,
I30,
I31,
I32,
I33,
I34,
I35,
I36,
I37,
I38,
I39,
I40,
I41,
I42,
I43,
I44,
I45,
I46,
I47,
I48,
I49,
I50,
I51,
I52,
I53,
I54,
I55,
I56,
I57,
I58,
I59,
I60,
I61,
I62,
I63,
I64,
I65,
I66,
I67,
I68,
I69,
I70,
I71,
I72,
I73,
I74,
I75,
I76,
I77,
I78,
I79,
I80,
I81,
I82,
I83,
I84,
I85,
I86,
I87,
I88,
I89,
I90,
I91,
I92,
I93,
I94,
I95,
I96,
I97,
I98,
I99,
I100,
I101,
I102,
I103,
I104,
I105,
I106,
I107,
I108,
I109,
I110,
I111,
I112,
I113,
I114,
I115,
I116,
I117,
I118,
I119,
I120,
I121,
I122,
I123,
I124,
I125,
I126,
I127,
I128,
I129,
I130,
I131,
I132,
I133,
I134,
I135,
I136,
I137,
I138,
I139,
I140,
I141,
I142,
I143,
I144,
I145,
I146,
I147,
I148,
I149,
I150,
I151,
I152,
I153,
I154,
I155,
I156,
I157,
I158,
I159,
I160,
I161,
I162,
I163,
I164,
I165,
I166,
I167,
I168,
I169,
I170,
I171,
I172,
I173,
I174,
I175,
I176,
I177,
I178,
I179,
I180,
I181,
I182,
I183,
I184,
I185,
I186,
I187,
I188,
I189,
I190,
I191,
I192,
I193,
I194,
I195,
I196,
I197,
I198,
I199,
I200,
I201,
I202,
I203,
I204,
I205,
I206,
I207,
I208,
I209,
I210,
I211,
I212,
I213,
I214,
I215,
I216,
I217,
I218,
I219,
I220,
I221,
I222,
I223,
I224,
I225,
I226,
I227,
I228,
I229,
I230,
I231,
I232,
I233,
I234,
I235,
I236,
I237,
I238,
I239,
I240,
I241,
I242,
I243,
I244,
I245,
I246,
I247,
I248,
I249,
I250,
I251,
I252,
I253,
I254,
I255,
};
const ValueCount257 = enum {
I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
I250, I251, I252, I253, I254, I255, I256
I0,
I1,
I2,
I3,
I4,
I5,
I6,
I7,
I8,
I9,
I10,
I11,
I12,
I13,
I14,
I15,
I16,
I17,
I18,
I19,
I20,
I21,
I22,
I23,
I24,
I25,
I26,
I27,
I28,
I29,
I30,
I31,
I32,
I33,
I34,
I35,
I36,
I37,
I38,
I39,
I40,
I41,
I42,
I43,
I44,
I45,
I46,
I47,
I48,
I49,
I50,
I51,
I52,
I53,
I54,
I55,
I56,
I57,
I58,
I59,
I60,
I61,
I62,
I63,
I64,
I65,
I66,
I67,
I68,
I69,
I70,
I71,
I72,
I73,
I74,
I75,
I76,
I77,
I78,
I79,
I80,
I81,
I82,
I83,
I84,
I85,
I86,
I87,
I88,
I89,
I90,
I91,
I92,
I93,
I94,
I95,
I96,
I97,
I98,
I99,
I100,
I101,
I102,
I103,
I104,
I105,
I106,
I107,
I108,
I109,
I110,
I111,
I112,
I113,
I114,
I115,
I116,
I117,
I118,
I119,
I120,
I121,
I122,
I123,
I124,
I125,
I126,
I127,
I128,
I129,
I130,
I131,
I132,
I133,
I134,
I135,
I136,
I137,
I138,
I139,
I140,
I141,
I142,
I143,
I144,
I145,
I146,
I147,
I148,
I149,
I150,
I151,
I152,
I153,
I154,
I155,
I156,
I157,
I158,
I159,
I160,
I161,
I162,
I163,
I164,
I165,
I166,
I167,
I168,
I169,
I170,
I171,
I172,
I173,
I174,
I175,
I176,
I177,
I178,
I179,
I180,
I181,
I182,
I183,
I184,
I185,
I186,
I187,
I188,
I189,
I190,
I191,
I192,
I193,
I194,
I195,
I196,
I197,
I198,
I199,
I200,
I201,
I202,
I203,
I204,
I205,
I206,
I207,
I208,
I209,
I210,
I211,
I212,
I213,
I214,
I215,
I216,
I217,
I218,
I219,
I220,
I221,
I222,
I223,
I224,
I225,
I226,
I227,
I228,
I229,
I230,
I231,
I232,
I233,
I234,
I235,
I236,
I237,
I238,
I239,
I240,
I241,
I242,
I243,
I244,
I245,
I246,
I247,
I248,
I249,
I250,
I251,
I252,
I253,
I254,
I255,
I256,
};
test "enum sizes" {
@ -189,11 +678,11 @@ test "enum sizes" {
}
}
const Small2 = enum (u2) {
const Small2 = enum(u2) {
One,
Two,
};
const Small = enum (u2) {
const Small = enum(u2) {
One,
Two,
Three,
@ -213,8 +702,7 @@ test "set enum tag type" {
}
}
const A = enum (u3) {
const A = enum(u3) {
One,
Two,
Three,
@ -225,7 +713,7 @@ const A = enum (u3) {
Four2,
};
const B = enum (u3) {
const B = enum(u3) {
One3,
Two3,
Three3,
@ -236,7 +724,7 @@ const B = enum (u3) {
Four23,
};
const C = enum (u2) {
const C = enum(u2) {
One4,
Two4,
Three4,
@ -389,7 +877,9 @@ test "enum with tag values don't require parens" {
}
test "enum with 1 field but explicit tag type should still have the tag type" {
const Enum = enum(u8) { B = 2 };
const Enum = enum(u8) {
B = 2,
};
comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
}

View File

@ -7,7 +7,7 @@ const ET = union(enum) {
UINT: u32,
pub fn print(a: &const ET, buf: []u8) error!usize {
return switch (*a) {
return switch (a.*) {
ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
};
@ -15,8 +15,12 @@ const ET = union(enum) {
};
test "enum with members" {
const a = ET { .SINT = -42 };
const b = ET { .UINT = 42 };
const a = ET {
.SINT = -42,
};
const b = ET {
.UINT = 42,
};
var buf: [20]u8 = undefined;
assert((a.print(buf[0..]) catch unreachable) == 3);

View File

@ -30,14 +30,12 @@ test "@errorName" {
assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
}
test "error values" {
const a = i32(error.err1);
const b = i32(error.err2);
assert(a != b);
}
test "redefinition of error values allowed" {
shouldBeNotEqual(error.AnError, error.SecondError);
}
@ -45,7 +43,6 @@ fn shouldBeNotEqual(a: error, b: error) void {
if (a == b) unreachable;
}
test "error binary operator" {
const a = errBinaryOperatorG(true) catch 3;
const b = errBinaryOperatorG(false) catch 3;
@ -56,20 +53,20 @@ fn errBinaryOperatorG(x: bool) error!isize {
return if (x) error.ItBroke else isize(10);
}
test "unwrap simple value from error" {
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
assert(i == 13);
}
fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
fn unwrapSimpleValueFromErrorDo() error!isize {
return 13;
}
test "error return in assignment" {
doErrReturnInAssignment() catch unreachable;
}
fn doErrReturnInAssignment() error!void {
var x : i32 = undefined;
var x: i32 = undefined;
x = try makeANonErr();
}
@ -95,7 +92,10 @@ test "error set type " {
comptime testErrorSetType();
}
const MyErrSet = error {OutOfMemory, FileNotFound};
const MyErrSet = error {
OutOfMemory,
FileNotFound,
};
fn testErrorSetType() void {
assert(@memberCount(MyErrSet) == 2);
@ -109,14 +109,19 @@ fn testErrorSetType() void {
}
}
test "explicit error set cast" {
testExplicitErrorSetCast(Set1.A);
comptime testExplicitErrorSetCast(Set1.A);
}
const Set1 = error{A, B};
const Set2 = error{A, C};
const Set1 = error {
A,
B,
};
const Set2 = error {
A,
C,
};
fn testExplicitErrorSetCast(set1: Set1) void {
var x = Set2(set1);
@ -129,7 +134,8 @@ test "comptime test error for empty error set" {
comptime testComptimeTestErrorEmptySet(1234);
}
const EmptyErrorSet = error {};
const EmptyErrorSet = error {
};
fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
if (x) |v| assert(v == 1234) else |err| @compileError("bad");
@ -145,7 +151,9 @@ test "comptime err to int of error set with only 1 possible value" {
testErrToIntWithOnePossibleValue(error.A, u32(error.A));
comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
}
fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void {
fn testErrToIntWithOnePossibleValue(x: error {
A,
}, comptime value: u32) void {
if (u32(x) != value) {
@compileError("bad");
}
@ -176,7 +184,6 @@ fn quux_1() !i32 {
return error.C;
}
test "error: fn returning empty error set can be passed as fn returning any error" {
entry();
comptime entry();
@ -186,24 +193,24 @@ fn entry() void {
foo2(bar2);
}
fn foo2(f: fn()error!void) void {
fn foo2(f: fn() error!void) void {
const x = f();
}
fn bar2() (error{}!void) { }
fn bar2() (error {
}!void) {}
test "error: Zero sized error set returned with value payload crash" {
_ = foo3(0);
_ = comptime foo3(0);
}
const Error = error{};
const Error = error {
};
fn foo3(b: usize) Error!usize {
return b;
}
test "error: Infer error set from literals" {
_ = nullLiteral("n") catch |err| handleErrors(err);
_ = floatLiteral("n") catch |err| handleErrors(err);
@ -215,29 +222,26 @@ test "error: Infer error set from literals" {
fn handleErrors(err: var) noreturn {
switch (err) {
error.T => {}
error.T => {},
}
unreachable;
}
fn nullLiteral(str: []const u8) !?i64 {
if (str[0] == 'n')
return null;
if (str[0] == 'n') return null;
return error.T;
}
fn floatLiteral(str: []const u8) !?f64 {
if (str[0] == 'n')
return 1.0;
if (str[0] == 'n') return 1.0;
return error.T;
}
fn intLiteral(str: []const u8) !?i64 {
if (str[0] == 'n')
return 1;
if (str[0] == 'n') return 1;
return error.T;
}

View File

@ -11,8 +11,6 @@ fn fibonacci(x: i32) i32 {
return fibonacci(x - 1) + fibonacci(x - 2);
}
fn unwrapAndAddOne(blah: ?i32) i32 {
return ??blah + 1;
}
@ -40,13 +38,13 @@ test "inline variable gets result of const if" {
assert(gimme1or2(false) == 2);
}
test "static function evaluation" {
assert(statically_added_number == 3);
}
const statically_added_number = staticAdd(1, 2);
fn staticAdd(a: i32, b: i32) i32 { return a + b; }
fn staticAdd(a: i32, b: i32) i32 {
return a + b;
}
test "const expr eval on single expr blocks" {
assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
@ -64,9 +62,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
return result;
}
test "statically initialized list" {
assert(static_point_list[0].x == 1);
assert(static_point_list[0].y == 2);
@ -77,7 +72,10 @@ const Point = struct {
x: i32,
y: i32,
};
const static_point_list = []Point { makePoint(1, 2), makePoint(3, 4) };
const static_point_list = []Point {
makePoint(1, 2),
makePoint(3, 4),
};
fn makePoint(x: i32, y: i32) Point {
return Point {
.x = x,
@ -85,7 +83,6 @@ fn makePoint(x: i32, y: i32) Point {
};
}
test "static eval list init" {
assert(static_vec3.data[2] == 1.0);
assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
@ -96,17 +93,19 @@ pub const Vec3 = struct {
};
pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
return Vec3 {
.data = []f32 { x, y, z, },
.data = []f32 {
x,
y,
z,
},
};
}
test "constant expressions" {
var array : [array_size]u8 = undefined;
var array: [array_size]u8 = undefined;
assert(@sizeOf(@typeOf(array)) == 20);
}
const array_size : u8 = 20;
const array_size: u8 = 20;
test "constant struct with negation" {
assert(vertices[0].x == -0.6);
@ -119,12 +118,29 @@ const Vertex = struct {
b: f32,
};
const vertices = []Vertex {
Vertex { .x = -0.6, .y = -0.4, .r = 1.0, .g = 0.0, .b = 0.0 },
Vertex { .x = 0.6, .y = -0.4, .r = 0.0, .g = 1.0, .b = 0.0 },
Vertex { .x = 0.0, .y = 0.6, .r = 0.0, .g = 0.0, .b = 1.0 },
Vertex {
.x = -0.6,
.y = -0.4,
.r = 1.0,
.g = 0.0,
.b = 0.0,
},
Vertex {
.x = 0.6,
.y = -0.4,
.r = 0.0,
.g = 1.0,
.b = 0.0,
},
Vertex {
.x = 0.0,
.y = 0.6,
.r = 0.0,
.g = 0.0,
.b = 1.0,
},
};
test "statically initialized struct" {
st_init_str_foo.x += 1;
assert(st_init_str_foo.x == 14);
@ -133,15 +149,21 @@ const StInitStrFoo = struct {
x: i32,
y: bool,
};
var st_init_str_foo = StInitStrFoo { .x = 13, .y = true, };
var st_init_str_foo = StInitStrFoo {
.x = 13,
.y = true,
};
test "statically initalized array literal" {
const y : [4]u8 = st_init_arr_lit_x;
const y: [4]u8 = st_init_arr_lit_x;
assert(y[3] == 4);
}
const st_init_arr_lit_x = []u8{1,2,3,4};
const st_init_arr_lit_x = []u8 {
1,
2,
3,
4,
};
test "const slice" {
comptime {
@ -198,14 +220,29 @@ const CmdFn = struct {
func: fn(i32) i32,
};
const cmd_fns = []CmdFn{
CmdFn {.name = "one", .func = one},
CmdFn {.name = "two", .func = two},
CmdFn {.name = "three", .func = three},
const cmd_fns = []CmdFn {
CmdFn {
.name = "one",
.func = one,
},
CmdFn {
.name = "two",
.func = two,
},
CmdFn {
.name = "three",
.func = three,
},
};
fn one(value: i32) i32 { return value + 1; }
fn two(value: i32) i32 { return value + 2; }
fn three(value: i32) i32 { return value + 3; }
fn one(value: i32) i32 {
return value + 1;
}
fn two(value: i32) i32 {
return value + 2;
}
fn three(value: i32) i32 {
return value + 3;
}
fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
var result: i32 = start_value;
@ -229,7 +266,7 @@ test "eval @setRuntimeSafety at compile-time" {
assert(result == 1234);
}
fn fnWithSetRuntimeSafety() i32{
fn fnWithSetRuntimeSafety() i32 {
@setRuntimeSafety(true);
return 1234;
}
@ -244,7 +281,6 @@ fn fnWithFloatMode() f32 {
return 1234.0;
}
const SimpleStruct = struct {
field: i32,
@ -253,7 +289,9 @@ const SimpleStruct = struct {
}
};
var simple_struct = SimpleStruct{ .field = 1234, };
var simple_struct = SimpleStruct {
.field = 1234,
};
const bound_fn = simple_struct.method;
@ -261,8 +299,6 @@ test "call method on bound fn referring to var instance" {
assert(bound_fn() == 1237);
}
test "ptr to local array argument at comptime" {
comptime {
var bytes: [10]u8 = undefined;
@ -277,7 +313,6 @@ fn modifySomeBytes(bytes: []u8) void {
bytes[9] = 'b';
}
test "comparisons 0 <= uint and 0 > uint should be comptime" {
testCompTimeUIntComparisons(1234);
}
@ -296,8 +331,6 @@ fn testCompTimeUIntComparisons(x: u32) void {
}
}
test "const ptr to variable data changes at runtime" {
assert(foo_ref.name[0] == 'a');
foo_ref.name = "b";
@ -308,11 +341,11 @@ const Foo = struct {
name: []const u8,
};
var foo_contents = Foo { .name = "a", };
var foo_contents = Foo {
.name = "a",
};
const foo_ref = &foo_contents;
test "create global array with for loop" {
assert(global_array[5] == 5 * 5);
assert(global_array[9] == 9 * 9);
@ -321,7 +354,7 @@ test "create global array with for loop" {
const global_array = x: {
var result: [10]usize = undefined;
for (result) |*item, index| {
*item = index * index;
item.* = index * index;
}
break :x result;
};
@ -379,7 +412,7 @@ test "f128 at compile time is lossy" {
pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
return struct {
pub const Node = struct { };
pub const Node = struct {};
};
}
@ -401,10 +434,10 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
comptime var i: usize = 0;
inline while (i < 4) : (i += 1) {
s[i] = 0;
s[i] |= u32(b[i*4+0]) << 24;
s[i] |= u32(b[i*4+1]) << 16;
s[i] |= u32(b[i*4+2]) << 8;
s[i] |= u32(b[i*4+3]) << 0;
s[i] |= u32(b[i * 4 + 0]) << 24;
s[i] |= u32(b[i * 4 + 1]) << 16;
s[i] |= u32(b[i * 4 + 2]) << 8;
s[i] |= u32(b[i * 4 + 3]) << 0;
}
}
@ -413,7 +446,7 @@ test "binary math operator in partially inlined function" {
var b: [16]u8 = undefined;
for (b) |*r, i|
*r = u8(i + 1);
r.* = u8(i + 1);
copyWithPartialInline(s[0..], b[0..]);
assert(s[0] == 0x1020304);
@ -422,7 +455,6 @@ test "binary math operator in partially inlined function" {
assert(s[3] == 0xd0e0f10);
}
test "comptime function with the same args is memoized" {
comptime {
assert(MakeType(i32) == MakeType(i32));
@ -447,12 +479,12 @@ test "comptime function with mutable pointer is not memoized" {
}
fn increment(value: &i32) void {
*value += 1;
value.* += 1;
}
fn generateTable(comptime T: type) [1010]T {
var res : [1010]T = undefined;
var i : usize = 0;
var res: [1010]T = undefined;
var i: usize = 0;
while (i < 1010) : (i += 1) {
res[i] = T(i);
}
@ -496,9 +528,10 @@ const SingleFieldStruct = struct {
}
};
test "const ptr to comptime mutable data is not memoized" {
comptime {
var foo = SingleFieldStruct {.x = 1};
var foo = SingleFieldStruct {
.x = 1,
};
assert(foo.read_x() == 1);
foo.x = 2;
assert(foo.read_x() == 2);

View File

@ -7,7 +7,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {
return a + b;
}
test "local variables" {
testLocVars(2);
}
@ -16,7 +15,6 @@ fn testLocVars(b: i32) void {
if (a + b != 3) unreachable;
}
test "void parameters" {
voidFun(1, void{}, 2, {});
}
@ -27,9 +25,8 @@ fn voidFun(a: i32, b: void, c: i32, d: void) void {
return vv;
}
test "mutable local variables" {
var zero : i32 = 0;
var zero: i32 = 0;
assert(zero == 0);
var i = i32(0);
@ -41,7 +38,7 @@ test "mutable local variables" {
test "separate block scopes" {
{
const no_conflict : i32 = 5;
const no_conflict: i32 = 5;
assert(no_conflict == 5);
}
@ -56,8 +53,7 @@ test "call function with empty string" {
acceptsString("");
}
fn acceptsString(foo: []u8) void { }
fn acceptsString(foo: []u8) void {}
fn @"weird function name"() i32 {
return 1234;
@ -70,31 +66,43 @@ test "implicit cast function unreachable return" {
wantsFnWithVoid(fnWithUnreachable);
}
fn wantsFnWithVoid(f: fn() void) void { }
fn wantsFnWithVoid(f: fn() void) void {}
fn fnWithUnreachable() noreturn {
unreachable;
}
test "function pointers" {
const fns = []@typeOf(fn1) { fn1, fn2, fn3, fn4, };
const fns = []@typeOf(fn1) {
fn1,
fn2,
fn3,
fn4,
};
for (fns) |f, i| {
assert(f() == u32(i) + 5);
}
}
fn fn1() u32 {return 5;}
fn fn2() u32 {return 6;}
fn fn3() u32 {return 7;}
fn fn4() u32 {return 8;}
fn fn1() u32 {
return 5;
}
fn fn2() u32 {
return 6;
}
fn fn3() u32 {
return 7;
}
fn fn4() u32 {
return 8;
}
test "inline function call" {
assert(@inlineCall(add, 3, 9) == 12);
}
fn add(a: i32, b: i32) i32 { return a + b; }
fn add(a: i32, b: i32) i32 {
return a + b;
}
test "number literal as an argument" {
numberLiteralArg(3);
@ -110,4 +118,4 @@ test "assign inline fn to const variable" {
a();
}
inline fn inlineFn() void { }
inline fn inlineFn() void {}

View File

@ -3,8 +3,14 @@ const assert = std.debug.assert;
const mem = std.mem;
test "continue in for loop" {
const array = []i32 {1, 2, 3, 4, 5};
var sum : i32 = 0;
const array = []i32 {
1,
2,
3,
4,
5,
};
var sum: i32 = 0;
for (array) |x| {
sum += x;
if (x < 3) {
@ -24,17 +30,39 @@ test "for loop with pointer elem var" {
}
fn mangleString(s: []u8) void {
for (s) |*c| {
*c += 1;
c.* += 1;
}
}
test "basic for loop" {
const expected_result = []u8{9, 8, 7, 6, 0, 1, 2, 3, 9, 8, 7, 6, 0, 1, 2, 3 };
const expected_result = []u8 {
9,
8,
7,
6,
0,
1,
2,
3,
9,
8,
7,
6,
0,
1,
2,
3,
};
var buffer: [expected_result.len]u8 = undefined;
var buf_index: usize = 0;
const array = []u8 {9, 8, 7, 6};
const array = []u8 {
9,
8,
7,
6,
};
for (array) |item| {
buffer[buf_index] = item;
buf_index += 1;
@ -65,7 +93,8 @@ fn testBreakOuter() void {
var array = "aoeu";
var count: usize = 0;
outer: for (array) |_| {
for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
// TODO shouldn't get error for redeclaring "_"
for (array) |_2| {
count += 1;
break :outer;
}
@ -82,7 +111,8 @@ fn testContinueOuter() void {
var array = "aoeu";
var counter: usize = 0;
outer: for (array) |_| {
for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
// TODO shouldn't get error for redeclaring "_"
for (array) |_2| {
counter += 1;
continue :outer;
}

View File

@ -37,7 +37,6 @@ test "fn with comptime args" {
assert(sameButWithFloats(0.43, 0.49) == 0.49);
}
test "var params" {
assert(max_i32(12, 34) == 34);
assert(max_f64(1.2, 3.4) == 3.4);
@ -60,7 +59,6 @@ fn max_f64(a: f64, b: f64) f64 {
return max_var(a, b);
}
pub fn List(comptime T: type) type {
return SmallList(T, 8);
}
@ -82,10 +80,15 @@ test "function with return type type" {
assert(list2.prealloc_items.len == 8);
}
test "generic struct" {
var a1 = GenNode(i32) {.value = 13, .next = null,};
var b1 = GenNode(bool) {.value = true, .next = null,};
var a1 = GenNode(i32) {
.value = 13,
.next = null,
};
var b1 = GenNode(bool) {
.value = true,
.next = null,
};
assert(a1.value == 13);
assert(a1.value == a1.getVal());
assert(b1.getVal());
@ -94,7 +97,9 @@ fn GenNode(comptime T: type) type {
return struct {
value: T,
next: ?&GenNode(T),
fn getVal(n: &const GenNode(T)) T { return n.value; }
fn getVal(n: &const GenNode(T)) T {
return n.value;
}
};
}
@ -107,7 +112,6 @@ fn GenericDataThing(comptime count: isize) type {
};
}
test "use generic param in generic param" {
assert(aGenericFn(i32, 3, 4) == 7);
}
@ -115,21 +119,31 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
return a + b;
}
test "generic fn with implicit cast" {
assert(getFirstByte(u8, []u8 {13}) == 13);
assert(getFirstByte(u16, []u16 {0, 13}) == 0);
assert(getFirstByte(u16, []u16 {
0,
13,
}) == 0);
}
fn getByte(ptr: ?&const u8) u8 {
return (??ptr).*;
}
fn getByte(ptr: ?&const u8) u8 {return *??ptr;}
fn getFirstByte(comptime T: type, mem: []const T) u8 {
return getByte(@ptrCast(&const u8, &mem[0]));
}
const foos = []fn(var) bool {
foo1,
foo2,
};
const foos = []fn(var) bool { foo1, foo2 };
fn foo1(arg: var) bool { return arg; }
fn foo2(arg: var) bool { return !arg; }
fn foo1(arg: var) bool {
return arg;
}
fn foo2(arg: var) bool {
return !arg;
}
test "array of generic fns" {
assert(foos[0](true));

View File

@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
}
}
test "else if expression" {
assert(elseIfExpressionF(1) == 1);
}

View File

@ -1 +1,3 @@
pub fn foo() i32 { return 1234; }
pub fn foo() i32 {
return 1234;
}

View File

@ -11,7 +11,9 @@ fn foo(id: u64) !i32 {
};
}
fn getErrInt() error!i32 { return 0; }
fn getErrInt() error!i32 {
return 0;
}
test "ir block deps" {
assert((foo(1) catch unreachable) == 0);

View File

@ -28,25 +28,12 @@ fn testDivision() void {
assert(divTrunc(f32, -5.0, 3.0) == -1.0);
comptime {
assert(
1194735857077236777412821811143690633098347576 %
508740759824825164163191790951174292733114988 ==
177254337427586449086438229241342047632117600);
assert(@rem(-1194735857077236777412821811143690633098347576,
508740759824825164163191790951174292733114988) ==
-177254337427586449086438229241342047632117600);
assert(1194735857077236777412821811143690633098347576 /
508740759824825164163191790951174292733114988 ==
2);
assert(@divTrunc(-1194735857077236777412821811143690633098347576,
508740759824825164163191790951174292733114988) ==
-2);
assert(@divTrunc(1194735857077236777412821811143690633098347576,
-508740759824825164163191790951174292733114988) ==
-2);
assert(@divTrunc(-1194735857077236777412821811143690633098347576,
-508740759824825164163191790951174292733114988) ==
2);
assert(1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600);
assert(@rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600);
assert(1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2);
assert(@divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2);
assert(@divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2);
assert(@divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2);
assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
}
}
@ -114,18 +101,28 @@ fn ctz(x: var) usize {
test "assignment operators" {
var i: u32 = 0;
i += 5; assert(i == 5);
i -= 2; assert(i == 3);
i *= 20; assert(i == 60);
i /= 3; assert(i == 20);
i %= 11; assert(i == 9);
i <<= 1; assert(i == 18);
i >>= 2; assert(i == 4);
i += 5;
assert(i == 5);
i -= 2;
assert(i == 3);
i *= 20;
assert(i == 60);
i /= 3;
assert(i == 20);
i %= 11;
assert(i == 9);
i <<= 1;
assert(i == 18);
i >>= 2;
assert(i == 4);
i = 6;
i &= 5; assert(i == 4);
i ^= 6; assert(i == 2);
i &= 5;
assert(i == 4);
i ^= 6;
assert(i == 2);
i = 6;
i |= 3; assert(i == 7);
i |= 3;
assert(i == 7);
}
test "three expr in a row" {
@ -138,7 +135,7 @@ fn testThreeExprInARow(f: bool, t: bool) void {
assertFalse(1 | 2 | 4 != 7);
assertFalse(3 ^ 6 ^ 8 != 13);
assertFalse(7 & 14 & 28 != 4);
assertFalse(9 << 1 << 2 != 9 << 3);
assertFalse(9 << 1 << 2 != 9 << 3);
assertFalse(90 >> 1 >> 2 != 90 >> 3);
assertFalse(100 - 1 + 1000 != 1099);
assertFalse(5 * 4 / 2 % 3 != 1);
@ -150,7 +147,6 @@ fn assertFalse(b: bool) void {
assert(!b);
}
test "const number literal" {
const one = 1;
const eleven = ten + one;
@ -159,8 +155,6 @@ test "const number literal" {
}
const ten = 10;
test "unsigned wrapping" {
testUnsignedWrappingEval(@maxValue(u32));
comptime testUnsignedWrappingEval(@maxValue(u32));
@ -214,8 +208,12 @@ const DivResult = struct {
};
test "binary not" {
assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
assert(comptime x: {
break :x ~u16(0b1010101010101010) == 0b0101010101010101;
});
assert(comptime x: {
break :x ~u64(2147483647) == 18446744071562067968;
});
testBinaryNot(0b1010101010101010);
}
@ -319,27 +317,15 @@ fn testShrExact(x: u8) void {
test "big number addition" {
comptime {
assert(
35361831660712422535336160538497375248 +
101752735581729509668353361206450473702 ==
137114567242441932203689521744947848950);
assert(
594491908217841670578297176641415611445982232488944558774612 +
390603545391089362063884922208143568023166603618446395589768 ==
985095453608931032642182098849559179469148836107390954364380);
assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
}
}
test "big number multiplication" {
comptime {
assert(
45960427431263824329884196484953148229 *
128339149605334697009938835852565949723 ==
5898522172026096622534201617172456926982464453350084962781392314016180490567);
assert(
594491908217841670578297176641415611445982232488944558774612 *
390603545391089362063884922208143568023166603618446395589768 ==
232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
assert(45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567);
assert(594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
}
}
@ -405,7 +391,9 @@ test "f128" {
comptime test_f128();
}
fn make_f128(x: f128) f128 { return x; }
fn make_f128(x: f128) f128 {
return x;
}
fn test_f128() void {
assert(@sizeOf(f128) == 16);

View File

@ -4,6 +4,7 @@ const cstr = @import("std").cstr;
const builtin = @import("builtin");
// normal comment
/// this is a documentation comment
/// doc comment line 2
fn emptyFunctionWithComments() void {}
@ -16,8 +17,7 @@ comptime {
@export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
}
extern fn disabledExternFn() void {
}
extern fn disabledExternFn() void {}
test "call disabled extern fn" {
disabledExternFn();
@ -110,17 +110,29 @@ fn testShortCircuit(f: bool, t: bool) void {
var hit_3 = f;
var hit_4 = f;
if (t or x: {assert(f); break :x f;}) {
if (t or x: {
assert(f);
break :x f;
}) {
hit_1 = t;
}
if (f or x: { hit_2 = t; break :x f; }) {
if (f or x: {
hit_2 = t;
break :x f;
}) {
assert(f);
}
if (t and x: { hit_3 = t; break :x f; }) {
if (t and x: {
hit_3 = t;
break :x f;
}) {
assert(f);
}
if (f and x: {assert(f); break :x f;}) {
if (f and x: {
assert(f);
break :x f;
}) {
assert(f);
} else {
hit_4 = t;
@ -146,8 +158,8 @@ test "return string from function" {
assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
}
const g1 : i32 = 1233 + 1;
var g2 : i32 = 0;
const g1: i32 = 1233 + 1;
var g2: i32 = 0;
test "global variables" {
assert(g2 == 0);
@ -155,10 +167,9 @@ test "global variables" {
assert(g2 == 1234);
}
test "memcpy and memset intrinsics" {
var foo : [20]u8 = undefined;
var bar : [20]u8 = undefined;
var foo: [20]u8 = undefined;
var bar: [20]u8 = undefined;
@memset(&foo[0], 'A', foo.len);
@memcpy(&bar[0], &foo[0], bar.len);
@ -167,12 +178,14 @@ test "memcpy and memset intrinsics" {
}
test "builtin static eval" {
const x : i32 = comptime x: {break :x 1 + 2 + 3;};
const x: i32 = comptime x: {
break :x 1 + 2 + 3;
};
assert(x == comptime 6);
}
test "slicing" {
var array : [20]i32 = undefined;
var array: [20]i32 = undefined;
array[5] = 1234;
@ -187,15 +200,15 @@ test "slicing" {
if (slice_rest.len != 10) unreachable;
}
test "constant equal function pointers" {
const alias = emptyFn;
assert(comptime x: {break :x emptyFn == alias;});
assert(comptime x: {
break :x emptyFn == alias;
});
}
fn emptyFn() void {}
test "hex escape" {
assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
}
@ -219,7 +232,7 @@ test "string escapes" {
}
test "multiline string" {
const s1 =
const s1 =
\\one
\\two)
\\three
@ -229,7 +242,7 @@ test "multiline string" {
}
test "multiline C string" {
const s1 =
const s1 =
c\\one
c\\two)
c\\three
@ -238,18 +251,16 @@ test "multiline C string" {
assert(cstr.cmp(s1, s2) == 0);
}
test "type equality" {
assert(&const u8 != &u8);
}
const global_a: i32 = 1234;
const global_b: &const i32 = &global_a;
const global_c: &const f32 = @ptrCast(&const f32, global_b);
test "compile time global reinterpret" {
const d = @ptrCast(&const i32, global_c);
assert(*d == 1234);
assert(d.* == 1234);
}
test "explicit cast maybe pointers" {
@ -261,12 +272,11 @@ test "generic malloc free" {
const a = memAlloc(u8, 10) catch unreachable;
memFree(u8, a);
}
var some_mem : [100]u8 = undefined;
var some_mem: [100]u8 = undefined;
fn memAlloc(comptime T: type, n: usize) error![]T {
return @ptrCast(&T, &some_mem[0])[0..n];
}
fn memFree(comptime T: type, memory: []T) void { }
fn memFree(comptime T: type, memory: []T) void {}
test "cast undefined" {
const array: [100]u8 = undefined;
@ -275,32 +285,35 @@ test "cast undefined" {
}
fn testCastUndefined(x: []const u8) void {}
test "cast small unsigned to larger signed" {
assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
}
fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; }
fn castSmallUnsignedToLargerSigned2(x: u16) i64 { return x; }
fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
return x;
}
fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
return x;
}
test "implicit cast after unreachable" {
assert(outer() == 1234);
}
fn inner() i32 { return 1234; }
fn inner() i32 {
return 1234;
}
fn outer() i64 {
return inner();
}
test "pointer dereferencing" {
var x = i32(3);
const y = &x;
*y += 1;
y.* += 1;
assert(x == 4);
assert(*y == 4);
assert(y.* == 4);
}
test "call result of if else expression" {
@ -310,9 +323,12 @@ test "call result of if else expression" {
fn f2(x: bool) []const u8 {
return (if (x) fA else fB)();
}
fn fA() []const u8 { return "a"; }
fn fB() []const u8 { return "b"; }
fn fA() []const u8 {
return "a";
}
fn fB() []const u8 {
return "b";
}
test "const expression eval handling of variables" {
var x = true;
@ -321,8 +337,6 @@ test "const expression eval handling of variables" {
}
}
test "constant enum initialization with differing sizes" {
test3_1(test3_foo);
test3_2(test3_bar);
@ -336,10 +350,17 @@ const Test3Point = struct {
x: i32,
y: i32,
};
const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
const test3_bar = Test3Foo { .Two = 13};
const test3_foo = Test3Foo {
.Three = Test3Point {
.x = 3,
.y = 4,
},
};
const test3_bar = Test3Foo {
.Two = 13,
};
fn test3_1(f: &const Test3Foo) void {
switch (*f) {
switch (f.*) {
Test3Foo.Three => |pt| {
assert(pt.x == 3);
assert(pt.y == 4);
@ -348,7 +369,7 @@ fn test3_1(f: &const Test3Foo) void {
}
}
fn test3_2(f: &const Test3Foo) void {
switch (*f) {
switch (f.*) {
Test3Foo.Two => |x| {
assert(x == 13);
},
@ -356,23 +377,19 @@ fn test3_2(f: &const Test3Foo) void {
}
}
test "character literals" {
assert('\'' == single_quote);
}
const single_quote = '\'';
test "take address of parameter" {
testTakeAddressOfParameter(12.34);
}
fn testTakeAddressOfParameter(f: f32) void {
const f_ptr = &f;
assert(*f_ptr == 12.34);
assert(f_ptr.* == 12.34);
}
test "pointer comparison" {
const a = ([]const u8)("a");
const b = &a;
@ -382,23 +399,30 @@ fn ptrEql(a: &const []const u8, b: &const []const u8) bool {
return a == b;
}
test "C string concatenation" {
const a = c"OK" ++ c" IT " ++ c"WORKED";
const b = c"OK IT WORKED";
const len = cstr.len(b);
const len_with_null = len + 1;
{var i: u32 = 0; while (i < len_with_null) : (i += 1) {
assert(a[i] == b[i]);
}}
{
var i: u32 = 0;
while (i < len_with_null) : (i += 1) {
assert(a[i] == b[i]);
}
}
assert(a[len] == 0);
assert(b[len] == 0);
}
test "cast slice to u8 slice" {
assert(@sizeOf(i32) == 4);
var big_thing_array = []i32{1, 2, 3, 4};
var big_thing_array = []i32 {
1,
2,
3,
4,
};
const big_thing_slice: []i32 = big_thing_array[0..];
const bytes = ([]u8)(big_thing_slice);
assert(bytes.len == 4 * 4);
@ -421,25 +445,22 @@ test "pointer to void return type" {
}
fn testPointerToVoidReturnType() error!void {
const a = testPointerToVoidReturnType2();
return *a;
return a.*;
}
const test_pointer_to_void_return_type_x = void{};
fn testPointerToVoidReturnType2() &const void {
return &test_pointer_to_void_return_type_x;
}
test "non const ptr to aliased type" {
const int = i32;
assert(?&int == ?&i32);
}
test "array 2D const double ptr" {
const rect_2d_vertexes = [][1]f32 {
[]f32{1.0},
[]f32{2.0},
[]f32 {1.0},
[]f32 {2.0},
};
testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
}
@ -450,10 +471,21 @@ fn testArray2DConstDoublePtr(ptr: &const f32) void {
}
const Tid = builtin.TypeId;
const AStruct = struct { x: i32, };
const AnEnum = enum { One, Two, };
const AUnionEnum = union(enum) { One: i32, Two: void, };
const AUnion = union { One: void, Two: void };
const AStruct = struct {
x: i32,
};
const AnEnum = enum {
One,
Two,
};
const AUnionEnum = union(enum) {
One: i32,
Two: void,
};
const AUnion = union {
One: void,
Two: void,
};
test "@typeId" {
comptime {
@ -481,9 +513,11 @@ test "@typeId" {
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
assert(@typeId(AUnionEnum) == Tid.Union);
assert(@typeId(AUnion) == Tid.Union);
assert(@typeId(fn()void) == Tid.Fn);
assert(@typeId(fn() void) == Tid.Fn);
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
assert(@typeId(@typeOf(x: {
break :x this;
})) == Tid.Block);
// TODO bound fn
// TODO arg tuple
// TODO opaque
@ -499,8 +533,7 @@ test "@canImplicitCast" {
}
test "@typeName" {
const Struct = struct {
};
const Struct = struct {};
const Union = union {
unused: u8,
};
@ -525,14 +558,19 @@ fn TypeFromFn(comptime T: type) type {
test "volatile load and store" {
var number: i32 = 1234;
const ptr = (&volatile i32)(&number);
*ptr += 1;
assert(*ptr == 1235);
ptr.* += 1;
assert(ptr.* == 1235);
}
test "slice string literal has type []const u8" {
comptime {
assert(@typeOf("aoeu"[0..]) == []const u8);
const array = []i32{1, 2, 3, 4};
const array = []i32 {
1,
2,
3,
4,
};
assert(@typeOf(array[0..]) == []const i32);
}
}
@ -544,12 +582,15 @@ const GDTEntry = struct {
field: i32,
};
var gdt = []GDTEntry {
GDTEntry {.field = 1},
GDTEntry {.field = 2},
GDTEntry {
.field = 1,
},
GDTEntry {
.field = 2,
},
};
var global_ptr = &gdt[0];
// can't really run this test but we can make sure it has no compile error
// and generates code
const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
@ -584,7 +625,7 @@ test "comptime if inside runtime while which unconditionally breaks" {
}
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
while (cond) {
if (false) { }
if (false) {}
break;
}
}
@ -607,7 +648,9 @@ fn testStructInFn() void {
kind: BlockKind,
};
var block = Block { .kind = 1234 };
var block = Block {
.kind = 1234,
};
block.kind += 1;
@ -617,7 +660,9 @@ fn testStructInFn() void {
fn fnThatClosesOverLocalConst() type {
const c = 1;
return struct {
fn g() i32 { return c; }
fn g() i32 {
return c;
}
};
}
@ -635,22 +680,29 @@ fn thisIsAColdFn() void {
@setCold(true);
}
const PackedStruct = packed struct { a: u8, b: u8, };
const PackedUnion = packed union { a: u8, b: u32, };
const PackedEnum = packed enum { A, B, };
const PackedStruct = packed struct {
a: u8,
b: u8,
};
const PackedUnion = packed union {
a: u8,
b: u32,
};
const PackedEnum = packed enum {
A,
B,
};
test "packed struct, enum, union parameters in extern function" {
testPackedStuff(
PackedStruct{.a = 1, .b = 2},
PackedUnion{.a = 1},
PackedEnum.A,
);
}
export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {
testPackedStuff(PackedStruct {
.a = 1,
.b = 2,
}, PackedUnion {
.a = 1,
}, PackedEnum.A);
}
export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {}
test "slicing zero length array" {
const s1 = ""[0..];
@ -661,7 +713,6 @@ test "slicing zero length array" {
assert(mem.eql(u32, s2, []u32{}));
}
const addr1 = @ptrCast(&const u8, emptyFn);
test "comptime cast fn to ptr" {
const addr2 = @ptrCast(&const u8, emptyFn);

View File

@ -8,7 +8,7 @@ test "namespace depends on compile var" {
assert(!some_namespace.a_bool);
}
}
const some_namespace = switch(builtin.os) {
const some_namespace = switch (builtin.os) {
builtin.Os.linux => @import("a.zig"),
else => @import("b.zig"),
};

View File

@ -19,7 +19,7 @@ fn targetFunction(x: i32) usize {
var local_variable: i32 = 42;
const ptr = &local_variable;
*ptr += 1;
ptr.* += 1;
assert(local_variable == 43);
return @ptrToInt(ptr);

View File

@ -1,7 +1,7 @@
const assert = @import("std").debug.assert;
test "nullable type" {
const x : ?bool = true;
const x: ?bool = true;
if (x) |y| {
if (y) {
@ -13,13 +13,13 @@ test "nullable type" {
unreachable;
}
const next_x : ?i32 = null;
const next_x: ?i32 = null;
const z = next_x ?? 1234;
assert(z == 1234);
const final_x : ?i32 = 13;
const final_x: ?i32 = 13;
const num = final_x ?? unreachable;
@ -30,19 +30,17 @@ test "test maybe object and get a pointer to the inner value" {
var maybe_bool: ?bool = true;
if (maybe_bool) |*b| {
*b = false;
b.* = false;
}
assert(??maybe_bool == false);
}
test "rhs maybe unwrap return" {
const x: ?bool = true;
const y = x ?? return;
}
test "maybe return" {
maybeReturnImpl();
comptime maybeReturnImpl();
@ -50,8 +48,7 @@ test "maybe return" {
fn maybeReturnImpl() void {
assert(??foo(1235));
if (foo(null) != null)
unreachable;
if (foo(null) != null) unreachable;
assert(!??foo(1234));
}
@ -60,12 +57,16 @@ fn foo(x: ?i32) ?bool {
return value > 1234;
}
test "if var maybe pointer" {
assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);
assert(shouldBeAPlus1(Particle {
.a = 14,
.b = 1,
.c = 1,
.d = 1,
}) == 15);
}
fn shouldBeAPlus1(p: &const Particle) u64 {
var maybe_particle: ?Particle = *p;
var maybe_particle: ?Particle = p.*;
if (maybe_particle) |*particle| {
particle.a += 1;
}
@ -81,7 +82,6 @@ const Particle = struct {
d: u64,
};
test "null literal outside function" {
const is_null = here_is_a_null_literal.context == null;
assert(is_null);
@ -96,7 +96,6 @@ const here_is_a_null_literal = SillyStruct {
.context = null,
};
test "test null runtime" {
testTestNullRuntime(null);
}
@ -123,8 +122,6 @@ fn bar(x: ?void) ?void {
}
}
const StructWithNullable = struct {
field: ?i32,
};

14
test/cases/pointers.zig Normal file
View File

@ -0,0 +1,14 @@
const std = @import("std");
const assert = std.debug.assert;
test "dereference pointer" {
comptime testDerefPtr();
testDerefPtr();
}
fn testDerefPtr() void {
var x: i32 = 1234;
var y = &x;
y.* += 1;
assert(x == 1235);
}

View File

@ -23,7 +23,7 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
if (c) {
const output_path = b;
if (c2) { }
if (c2) {}
a(output_path);
}

View File

@ -23,7 +23,9 @@ test "reflection: function return type, var args, and param types" {
}
}
fn dummy(a: bool, b: i32, c: f32) i32 { return 1234; }
fn dummy(a: bool, b: i32, c: f32) i32 {
return 1234;
}
fn dummy_varargs(args: ...) void {}
test "reflection: struct member types and names" {
@ -54,7 +56,6 @@ test "reflection: enum member types and names" {
assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
}
}
test "reflection: @field" {

Some files were not shown because too many files have changed in this diff Show More