mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge pull request #1019 from zig-lang/pointer-reform
Pointer Reform - change prefix deref syntax to postfix deref syntax
This commit is contained in:
commit
83a7809478
59
build.zig
59
build.zig
@ -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,
|
||||
|
||||
@ -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 = &x;
|
||||
*x == 1234</code></pre>
|
||||
x.* == 1234</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -1258,7 +1258,7 @@ const ptr = &x;
|
||||
<td>
|
||||
<pre><code class="zig">const x: u32 = 1234;
|
||||
const ptr = &x;
|
||||
*x == 1234</code></pre>
|
||||
x.* == 1234</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -1267,8 +1267,8 @@ const ptr = &x;
|
||||
{#header_open|Precedence#}
|
||||
<pre><code>x() x[] x.y
|
||||
a!b
|
||||
!x -x -%x ~x *x &x ?x ??x
|
||||
x{}
|
||||
!x -x -%x ~x &x ?x ??x
|
||||
x{} x.*
|
||||
! * / % ** *%
|
||||
+ - ++ +% -%
|
||||
<< >>
|
||||
@ -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(&u32, f32(12.34))</code></pre>
|
||||
<pre><code class="zig">@ptrCast(&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) -> 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) -> 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) -> 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>
|
||||
@ -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) -> 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("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") 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 = "!" | "-" | "~" | "*" | ("&" 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
|
||||
|
||||
|
||||
@ -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",
|
||||
};
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
|
||||
14
src/ir.cpp
14
src/ir.cpp
@ -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:
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
207
std/build.zig
207
std/build.zig
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
|
||||
106
std/heap.zig
106
std/heap.zig
@ -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));
|
||||
|
||||
|
||||
65
std/io.zig
65
std/io.zig
@ -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 => {
|
||||
|
||||
207
std/json.zig
207
std/json.zig
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)));
|
||||
|
||||
@ -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)));
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
//
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
//
|
||||
|
||||
@ -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.
|
||||
|
||||
197
std/mem.zig
197
std/mem.zig
@ -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
|
||||
|
||||
40
std/net.zig
40
std/net.zig
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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<OSTOP)
|
||||
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<OSTOP)
|
||||
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: ?×pec) 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;
|
||||
|
||||
@ -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
|
||||
/// pro‐tocol 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;
|
||||
}
|
||||
|
||||
|
||||
@ -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: ×pec) 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: ×pec) 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;
|
||||
|
||||
@ -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;
|
||||
|
||||
564
std/sort.zig
564
std/sort.zig
@ -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| {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -9,4 +9,3 @@ pub extern fn __fixunsdfdi(a: f64) u64 {
|
||||
test "import fixunsdfdi" {
|
||||
_ = @import("fixunsdfdi_test.zig");
|
||||
}
|
||||
|
||||
|
||||
@ -9,4 +9,3 @@ pub extern fn __fixunsdfsi(a: f64) u32 {
|
||||
test "import fixunsdfsi" {
|
||||
_ = @import("fixunsdfsi_test.zig");
|
||||
}
|
||||
|
||||
|
||||
@ -9,4 +9,3 @@ pub extern fn __fixunssfti(a: f32) u128 {
|
||||
test "import fixunssfti" {
|
||||
_ = @import("fixunssfti_test.zig");
|
||||
}
|
||||
|
||||
|
||||
@ -9,4 +9,3 @@ pub extern fn __fixunstfti(a: f128) u128 {
|
||||
test "import fixunstfti" {
|
||||
_ = @import("fixunstfti_test.zig");
|
||||
}
|
||||
|
||||
|
||||
@ -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| {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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" {
|
||||
|
||||
@ -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.*));
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
2083
std/zig/parse.zig
2083
std/zig/parse.zig
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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()) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test "else if expression" {
|
||||
assert(elseIfExpressionF(1) == 1);
|
||||
}
|
||||
|
||||
@ -1 +1,3 @@
|
||||
pub fn foo() i32 { return 1234; }
|
||||
pub fn foo() i32 {
|
||||
return 1234;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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"),
|
||||
};
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
14
test/cases/pointers.zig
Normal 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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user