Merge pull request #2 from ziglang/master

sync with ziglang
This commit is contained in:
tgschultz 2018-05-30 08:26:13 -05:00 committed by GitHub
commit 8174f972a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
198 changed files with 15449 additions and 9432 deletions

View File

@ -196,7 +196,7 @@ else()
if(MSVC)
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
else()
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment")
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment -Wno-class-memaccess -Wno-unknown-warning-option")
endif()
set_target_properties(embedded_lld_lib PROPERTIES
COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}

View File

@ -1,9 +1,9 @@
![ZIG](http://ziglang.org/zig-logo.svg)
![ZIG](https://ziglang.org/zig-logo.svg)
A programming language designed for robustness, optimality, and
clarity.
[ziglang.org](http://ziglang.org)
[ziglang.org](https://ziglang.org)
## Feature Highlights
@ -114,7 +114,7 @@ libc. Create demo games using Zig.
## Building
[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)
[![Build Status](https://travis-ci.org/ziglang/zig.svg?branch=master)](https://travis-ci.org/ziglang/zig)
[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
### Stage 1: Build Zig from C++ Source Code
@ -161,7 +161,7 @@ bin/zig build --build-file ../build.zig test
##### Windows
See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
### Stage 2: Build Self-Hosted Zig from Zig Source Code
@ -182,6 +182,9 @@ binary.
This is the actual compiler binary that we will install to the system.
*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
not yet supported.*
#### Debug / Development Build
```

View File

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

View File

@ -95,7 +95,7 @@ const Tokenizer = struct {
};
fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer {
return Tokenizer {
return Tokenizer{
.buffer = buffer,
.index = 0,
.state = State.Start,
@ -105,7 +105,7 @@ const Tokenizer = struct {
}
fn next(self: &Tokenizer) Token {
var result = Token {
var result = Token{
.id = Token.Id.Eof,
.start = self.index,
.end = undefined,
@ -197,7 +197,7 @@ const Tokenizer = struct {
};
fn getTokenLocation(self: &Tokenizer, token: &const Token) Location {
var loc = Location {
var loc = Location{
.line = 0,
.column = 0,
.line_start = 0,
@ -346,7 +346,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
break;
},
Token.Id.Content => {
try nodes.append(Node {.Content = tokenizer.buffer[token.start..token.end] });
try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] });
},
Token.Id.BracketOpen => {
const tag_token = try eatToken(tokenizer, Token.Id.TagContent);
@ -365,11 +365,13 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
header_stack_size += 1;
const urlized = try urlize(allocator, content);
try nodes.append(Node{.HeaderOpen = HeaderOpen {
.name = content,
.url = urlized,
.n = header_stack_size,
}});
try nodes.append(Node{
.HeaderOpen = HeaderOpen{
.name = content,
.url = urlized,
.n = header_stack_size,
},
});
if (try urls.put(urlized, tag_token)) |other_tag_token| {
parseError(tokenizer, tag_token, "duplicate header url: #{}", urlized) catch {};
parseError(tokenizer, other_tag_token, "other tag here") catch {};
@ -407,14 +409,14 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
switch (see_also_tok.id) {
Token.Id.TagContent => {
const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end];
try list.append(SeeAlsoItem {
try list.append(SeeAlsoItem{
.name = content,
.token = see_also_tok,
});
},
Token.Id.Separator => {},
Token.Id.BracketClose => {
try nodes.append(Node {.SeeAlso = list.toOwnedSlice() } );
try nodes.append(Node{ .SeeAlso = list.toOwnedSlice() });
break;
},
else => return parseError(tokenizer, see_also_tok, "invalid see_also token"),
@ -438,8 +440,8 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
}
};
try nodes.append(Node {
.Link = Link {
try nodes.append(Node{
.Link = Link{
.url = try urlize(allocator, url_name),
.name = name,
.token = name_tok,
@ -463,24 +465,24 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
var code_kind_id: Code.Id = undefined;
var is_inline = false;
if (mem.eql(u8, code_kind_str, "exe")) {
code_kind_id = Code.Id { .Exe = ExpectedOutcome.Succeed };
code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed };
} else if (mem.eql(u8, code_kind_str, "exe_err")) {
code_kind_id = Code.Id { .Exe = ExpectedOutcome.Fail };
code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Fail };
} else if (mem.eql(u8, code_kind_str, "test")) {
code_kind_id = Code.Id.Test;
} else if (mem.eql(u8, code_kind_str, "test_err")) {
code_kind_id = Code.Id { .TestError = name};
code_kind_id = Code.Id{ .TestError = name };
name = "test";
} else if (mem.eql(u8, code_kind_str, "test_safety")) {
code_kind_id = Code.Id { .TestSafety = name};
code_kind_id = Code.Id{ .TestSafety = name };
name = "test";
} else if (mem.eql(u8, code_kind_str, "obj")) {
code_kind_id = Code.Id { .Obj = null };
code_kind_id = Code.Id{ .Obj = null };
} else if (mem.eql(u8, code_kind_str, "obj_err")) {
code_kind_id = Code.Id { .Obj = name };
code_kind_id = Code.Id{ .Obj = name };
name = "test";
} else if (mem.eql(u8, code_kind_str, "syntax")) {
code_kind_id = Code.Id { .Obj = null };
code_kind_id = Code.Id{ .Obj = null };
is_inline = true;
} else {
return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);
@ -514,17 +516,20 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
return parseError(tokenizer, end_code_tag, "invalid token inside code_begin: {}", end_tag_name);
}
_ = try eatToken(tokenizer, Token.Id.BracketClose);
} else unreachable; // TODO issue #707
try nodes.append(Node {.Code = Code {
.id = code_kind_id,
.name = name,
.source_token = source_token,
.is_inline = is_inline,
.mode = mode,
.link_objects = link_objects.toOwnedSlice(),
.target_windows = target_windows,
.link_libc = link_libc,
}});
} else
unreachable; // TODO issue #707
try nodes.append(Node{
.Code = Code{
.id = code_kind_id,
.name = name,
.source_token = source_token,
.is_inline = is_inline,
.mode = mode,
.link_objects = link_objects.toOwnedSlice(),
.target_windows = target_windows,
.link_libc = link_libc,
},
});
tokenizer.code_node_count += 1;
} else {
return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
@ -534,7 +539,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
}
}
return Toc {
return Toc{
.nodes = nodes.toOwnedSlice(),
.toc = toc_buf.toOwnedSlice(),
.urls = urls,
@ -727,16 +732,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
try io.writeFile(allocator, tmp_source_file_name, trimmed_raw_source);
switch (code.id) {
Code.Id.Exe => |expected_outcome| {
const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
var build_args = std.ArrayList([]const u8).init(allocator);
defer build_args.deinit();
try build_args.appendSlice([][]const u8 {zig_exe,
"build-exe", tmp_source_file_name,
"--output", tmp_bin_file_name,
try build_args.appendSlice([][]const u8{
zig_exe,
"build-exe",
tmp_source_file_name,
"--output",
tmp_bin_file_name,
});
try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", code.name);
switch (code.mode) {
@ -766,10 +774,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
try build_args.append("c");
try out.print(" --library c");
}
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(
tokenizer, code.source_token, "example failed to compile");
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
const run_args = [][]const u8 {tmp_bin_file_name};
const run_args = [][]const u8{tmp_bin_file_name};
const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
const result = try os.ChildProcess.exec(allocator, run_args, null, null, max_doc_file_size);
@ -777,7 +784,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
os.ChildProcess.Term.Exited => |exit_code| {
if (exit_code == 0) {
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
for (run_args) |arg| warn("{} ", arg) else warn("\n");
for (run_args) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example incorrectly compiled");
}
},
@ -785,11 +795,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
}
break :blk result;
} else blk: {
break :blk exec(allocator, run_args) catch return parseError(
tokenizer, code.source_token, "example crashed");
break :blk exec(allocator, run_args) catch return parseError(tokenizer, code.source_token, "example crashed");
};
const escaped_stderr = try escapeHtml(allocator, result.stderr);
const escaped_stdout = try escapeHtml(allocator, result.stdout);
@ -802,7 +810,11 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
var test_args = std.ArrayList([]const u8).init(allocator);
defer test_args.deinit();
try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
try test_args.appendSlice([][]const u8{
zig_exe,
"test",
tmp_source_file_name,
});
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
switch (code.mode) {
builtin.Mode.Debug => {},
@ -821,13 +833,15 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
}
if (code.target_windows) {
try test_args.appendSlice([][]const u8{
"--target-os", "windows",
"--target-arch", "x86_64",
"--target-environ", "msvc",
"--target-os",
"windows",
"--target-arch",
"x86_64",
"--target-environ",
"msvc",
});
}
const result = exec(allocator, test_args.toSliceConst()) catch return parseError(
tokenizer, code.source_token, "test failed");
const result = exec(allocator, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
const escaped_stderr = try escapeHtml(allocator, result.stderr);
const escaped_stdout = try escapeHtml(allocator, result.stdout);
try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);
@ -836,7 +850,13 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
var test_args = std.ArrayList([]const u8).init(allocator);
defer test_args.deinit();
try test_args.appendSlice([][]const u8 {zig_exe, "test", "--color", "on", tmp_source_file_name});
try test_args.appendSlice([][]const u8{
zig_exe,
"test",
"--color",
"on",
tmp_source_file_name,
});
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
switch (code.mode) {
builtin.Mode.Debug => {},
@ -858,13 +878,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
os.ChildProcess.Term.Exited => |exit_code| {
if (exit_code == 0) {
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (test_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example incorrectly compiled");
}
},
else => {
warn("{}\nThe following command crashed:\n", result.stderr);
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (test_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example compile crashed");
},
}
@ -881,7 +907,11 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
var test_args = std.ArrayList([]const u8).init(allocator);
defer test_args.deinit();
try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
try test_args.appendSlice([][]const u8{
zig_exe,
"test",
tmp_source_file_name,
});
switch (code.mode) {
builtin.Mode.Debug => {},
builtin.Mode.ReleaseSafe => try test_args.append("--release-safe"),
@ -894,13 +924,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
os.ChildProcess.Term.Exited => |exit_code| {
if (exit_code == 0) {
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (test_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example test incorrectly succeeded");
}
},
else => {
warn("{}\nThe following command crashed:\n", result.stderr);
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (test_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example compile crashed");
},
}
@ -918,9 +954,15 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
var build_args = std.ArrayList([]const u8).init(allocator);
defer build_args.deinit();
try build_args.appendSlice([][]const u8 {zig_exe, "build-obj", tmp_source_file_name,
"--color", "on",
"--output", tmp_obj_file_name});
try build_args.appendSlice([][]const u8{
zig_exe,
"build-obj",
tmp_source_file_name,
"--color",
"on",
"--output",
tmp_obj_file_name,
});
if (!code.is_inline) {
try out.print("<pre><code class=\"shell\">$ zig build-obj {}.zig", code.name);
@ -954,13 +996,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
os.ChildProcess.Term.Exited => |exit_code| {
if (exit_code == 0) {
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (build_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example build incorrectly succeeded");
}
},
else => {
warn("{}\nThe following command crashed:\n", result.stderr);
for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
for (build_args.toSliceConst()) |arg|
warn("{} ", arg)
else
warn("\n");
return parseError(tokenizer, code.source_token, "example compile crashed");
},
}
@ -975,8 +1023,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
try out.print("</code></pre>\n");
}
} else {
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(
tokenizer, code.source_token, "example failed to compile");
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
}
if (!code.is_inline) {
try out.print("</code></pre>\n");
@ -987,7 +1034,6 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
},
}
}
}
fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
@ -996,13 +1042,19 @@ fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex
os.ChildProcess.Term.Exited => |exit_code| {
if (exit_code != 0) {
warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
for (args) |arg| warn("{} ", arg) else warn("\n");
for (args) |arg|
warn("{} ", arg)
else
warn("\n");
return error.ChildExitError;
}
},
else => {
warn("{}\nThe following command crashed:\n", result.stderr);
for (args) |arg| warn("{} ", arg) else warn("\n");
for (args) |arg|
warn("{} ", arg)
else
warn("\n");
return error.ChildCrashed;
},
}

View File

@ -96,7 +96,7 @@
</p>
<p>
If you search for something specific in this documentation and do not find it,
please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
please <a href="https://github.com/ziglang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
</p>
<p>
The code samples in this document are compiled and tested as part of the main test suite of Zig.
@ -1232,7 +1232,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
</td>
</tr>
<tr>
<td><pre><code class="zig">*a<code></pre></td>
<td><pre><code class="zig">a.*<code></pre></td>
<td>
<ul>
<li>{#link|Pointers#}</li>
@ -1244,7 +1244,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
<td>
<pre><code class="zig">const x: u32 = 1234;
const ptr = &amp;x;
*x == 1234</code></pre>
x.* == 1234</code></pre>
</td>
</tr>
<tr>
@ -1258,7 +1258,7 @@ const ptr = &amp;x;
<td>
<pre><code class="zig">const x: u32 = 1234;
const ptr = &amp;x;
*x == 1234</code></pre>
x.* == 1234</code></pre>
</td>
</tr>
</table>
@ -1267,8 +1267,8 @@ const ptr = &amp;x;
{#header_open|Precedence#}
<pre><code>x() x[] x.y
a!b
!x -x -%x ~x *x &amp;x ?x ??x
x{}
!x -x -%x ~x &amp;x ?x ??x
x{} x.*
! * / % ** *%
+ - ++ +% -%
&lt;&lt; &gt;&gt;
@ -1316,7 +1316,7 @@ var some_integers: [100]i32 = undefined;
test "modify an array" {
for (some_integers) |*item, i| {
*item = i32(i);
item.* = i32(i);
}
assert(some_integers[10] == 10);
assert(some_integers[99] == 99);
@ -1357,7 +1357,7 @@ comptime {
var fancy_array = init: {
var initial_value: [10]Point = undefined;
for (initial_value) |*pt, i| {
*pt = Point {
pt.* = Point {
.x = i32(i),
.y = i32(i) * 2,
};
@ -1400,7 +1400,7 @@ test "address of syntax" {
const x_ptr = &x;
// Deference a pointer:
assert(*x_ptr == 1234);
assert(x_ptr.* == 1234);
// When you get the address of a const variable, you get a const pointer.
assert(@typeOf(x_ptr) == &const i32);
@ -1409,8 +1409,8 @@ test "address of syntax" {
var y: i32 = 5678;
const y_ptr = &y;
assert(@typeOf(y_ptr) == &i32);
*y_ptr += 1;
assert(*y_ptr == 5679);
y_ptr.* += 1;
assert(y_ptr.* == 5679);
}
test "pointer array access" {
@ -1448,9 +1448,9 @@ comptime {
// @ptrCast.
var x: i32 = 1;
const ptr = &x;
*ptr += 1;
ptr.* += 1;
x += 1;
assert(*ptr == 3);
assert(ptr.* == 3);
}
test "@ptrToInt and @intToPtr" {
@ -1492,7 +1492,7 @@ test "nullable pointers" {
var x: i32 = 1;
ptr = &x;
assert(*??ptr == 1);
assert((??ptr).* == 1);
// Nullable pointers are the same size as normal pointers, because pointer
// value 0 is used as the null value.
@ -1505,7 +1505,7 @@ test "pointer casting" {
// conversions are not possible.
const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
const u32_ptr = @ptrCast(&const u32, &bytes[0]);
assert(*u32_ptr == 0x12121212);
assert(u32_ptr.* == 0x12121212);
// Even this example is contrived - there are better ways to do the above than
// pointer casting. For example, using a slice narrowing cast:
@ -1610,7 +1610,7 @@ fn foo(bytes: []u8) u32 {
<code>u8</code> can alias any memory.
</p>
<p>As an example, this code produces undefined behavior:</p>
<pre><code class="zig">*@ptrCast(&amp;u32, f32(12.34))</code></pre>
<pre><code class="zig">@ptrCast(&amp;u32, f32(12.34)).*</code></pre>
<p>Instead, use {#link|@bitCast#}:
<pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
<p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>
@ -2040,7 +2040,7 @@ const Variant = union(enum) {
Bool: bool,
fn truthy(self: &const Variant) bool {
return switch (*self) {
return switch (self.*) {
Variant.Int => |x_int| x_int != 0,
Variant.Bool => |x_bool| x_bool,
};
@ -2151,7 +2151,7 @@ test "switch enum" {
// A reference to the matched value can be obtained using `*` syntax.
Item.C => |*item| blk: {
(*item).x += 1;
item.*.x += 1;
break :blk 6;
},
@ -2374,7 +2374,7 @@ test "for reference" {
// Iterate over the slice by reference by
// specifying that the capture value is a pointer.
for (items) |*value| {
*value += 1;
value.* += 1;
}
assert(items[0] == 4);
@ -2483,7 +2483,7 @@ test "if nullable" {
// Access the value by reference using a pointer capture.
var c: ?u32 = 3;
if (c) |*value| {
*value = 2;
value.* = 2;
}
if (c) |value| {
@ -2524,7 +2524,7 @@ test "if error union" {
// Access the value by reference using a pointer capture.
var c: error!u32 = 3;
if (c) |*value| {
*value = 9;
value.* = 9;
} else |err| {
unreachable;
}
@ -2827,7 +2827,7 @@ test "fn reflection" {
</p>
<p>
The number of unique error values across the entire compilation should determine the size of the error set type.
However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/zig-lang/zig/issues/786">#768</a>.
However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/ziglang/zig/issues/786">#768</a>.
</p>
<p>
You can implicitly cast an error from a subset to its superset:
@ -3111,7 +3111,48 @@ test "error union" {
{#code_end#}
<p>TODO the <code>||</code> operator for error sets</p>
{#header_open|Inferred Error Sets#}
<p>TODO</p>
<p>
Because many functions in Zig return a possible error, Zig supports inferring the error set.
To infer the error set for a function, use this syntax:
</p>
{#code_begin|test#}
// With an inferred error set
pub fn add_inferred(comptime T: type, a: T, b: T) !T {
var answer: T = undefined;
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
}
// With an explicit error set
pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
var answer: T = undefined;
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
}
const Error = error {
Overflow,
};
const std = @import("std");
test "inferred error set" {
if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
error.Overflow => {}, // ok
}
}
{#code_end#}
<p>
When a function has an inferred error set, that function becomes generic and thus it becomes
trickier to do certain things with it, such as obtain a function pointer, or have an error
set that is consistent across different build targets. Additionally, inferred error sets
are incompatible with recursion.
</p>
<p>
In these situations, it is recommended to use an explicit error set. You can generally start
with an empty error set and let compile errors guide you toward completing the set.
</p>
<p>
These limitations may be overcome in a future version of Zig.
</p>
{#header_close#}
{#header_close#}
{#header_open|Error Return Traces#}
@ -3872,13 +3913,22 @@ pub fn main() void {
{#header_open|@addWithOverflow#}
<pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a + b</code>. If overflow or underflow occurs,
Performs <code>result.* = a + b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
{#header_close#}
{#header_open|@ArgType#}
<p>TODO</p>
<pre><code class="zig">@ArgType(comptime T: type, comptime n: usize) -&gt; type</code></pre>
<p>
This builtin function takes a function type and returns the type of the parameter at index <code>n</code>.
</p>
<p>
<code>T</code> must be a function type.
</p>
<p>
Note: This function is deprecated. Use {#link|@typeInfo#} instead.
</p>
{#header_close#}
{#header_open|@atomicLoad#}
<pre><code class="zig">@atomicLoad(comptime T: type, ptr: &amp;const T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
@ -4073,9 +4123,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 +4150,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 +4497,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,22 +4530,63 @@ mem.set(u8, dest, c);</code></pre>
{#header_open|@mulWithOverflow#}
<pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a * b</code>. If overflow or underflow occurs,
Performs <code>result.* = a * b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
{#header_close#}
{#header_open|@newStackCall#}
<pre><code class="zig">@newStackCall(new_stack: []u8, function: var, args: ...) -&gt; var</code></pre>
<p>
This calls a function, in the same way that invoking an expression with parentheses does. However,
instead of using the same stack as the caller, the function uses the stack provided in the <code>new_stack</code>
parameter.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
var new_stack_bytes: [1024]u8 = undefined;
test "calling a function with a new stack" {
const arg = 1234;
const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
_ = targetFunction(arg);
assert(arg == 1234);
assert(a < b);
}
fn targetFunction(x: i32) usize {
assert(x == 1234);
var local_variable: i32 = 42;
const ptr = &local_variable;
ptr.* += 1;
assert(local_variable == 43);
return @ptrToInt(ptr);
}
{#code_end#}
{#header_close#}
{#header_open|@noInlineCall#}
<pre><code class="zig">@noInlineCall(function: var, args: ...) -&gt; var</code></pre>
<p>
This calls a function, in the same way that invoking an expression with parentheses does:
</p>
<pre><code class="zig">const assert = @import("std").debug.assert;
{#code_begin|test#}
const assert = @import("std").debug.assert;
test "noinline function call" {
assert(@noInlineCall(add, 3, 9) == 12);
}
fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
fn add(a: i32, b: i32) i32 {
return a + b;
}
{#code_end#}
<p>
Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call
will not be inlined. If the call must be inlined, a compile error is emitted.
@ -4705,7 +4796,7 @@ pub const FloatMode = enum {
{#header_open|@shlWithOverflow#}
<pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,
Performs <code>result.* = a &lt;&lt; b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -4749,7 +4840,7 @@ pub const FloatMode = enum {
{#header_open|@subWithOverflow#}
<pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
<p>
Performs <code>*result = a - b</code>. If overflow or underflow occurs,
Performs <code>result.* = a - b</code>. If overflow or underflow occurs,
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
If no overflow or underflow occurs, returns <code>false</code>.
</p>
@ -5867,7 +5958,7 @@ pub fn main() void {
{#code_begin|exe#}
{#link_libc#}
const c = @cImport({
// See https://github.com/zig-lang/zig/issues/515
// See https://github.com/ziglang/zig/issues/515
@cDefine("_NO_CRT_STDIO_INLINE", "1");
@cInclude("stdio.h");
});
@ -6210,7 +6301,7 @@ fn readU32Be() u32 {}
<li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
</ul>
<p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p>
{#header_close#}
{#header_open|Grammar#}
<pre><code class="nohighlight">Root = many(TopLevelItem) EOF
@ -6341,10 +6432,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
FieldAccessExpression = "." Symbol
PtrDerefExpression = ".*"
FnCallExpression = "(" list(Expression, ",") ")"
ArrayAccessExpression = "[" Expression "]"
@ -6357,7 +6450,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
StructLiteralField = "." Symbol "=" Expression
PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
@ -6451,7 +6544,7 @@ hljs.registerLanguage("zig", function(t) {
a = t.IR + "\\s*\\(",
c = {
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo newStackCall",
literal: "true false null undefined"
},
n = [e, t.CLCM, t.CBCM, s, r];

View File

@ -23,7 +23,7 @@ pub fn main() !void {
while (true) {
try stdout.print("\nGuess a number between 1 and 100: ");
var line_buf : [20]u8 = undefined;
var line_buf: [20]u8 = undefined;
const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
error.InputTooLong => {

View File

@ -1,5 +1,5 @@
const c = @cImport({
// See https://github.com/zig-lang/zig/issues/515
// See https://github.com/ziglang/zig/issues/515
@cDefine("_NO_CRT_STDIO_INLINE", "1");
@cInclude("stdio.h");
@cInclude("string.h");
@ -8,8 +8,7 @@ const c = @cImport({
const msg = c"Hello, world!\n";
export fn main(argc: c_int, argv: &&u8) c_int {
if (c.printf(msg) != c_int(c.strlen(msg)))
return -1;
if (c.printf(msg) != c_int(c.strlen(msg))) return -1;
return 0;
}

View File

@ -4,9 +4,7 @@ pub fn build(b: &Builder) void {
const obj = b.addObject("base64", "base64.zig");
const exe = b.addCExecutable("test");
exe.addCompileFlags([][]const u8 {
"-std=c99",
});
exe.addCompileFlags([][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.addObject(obj);

View File

@ -4,9 +4,7 @@ pub fn build(b: &Builder) void {
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
const exe = b.addCExecutable("test");
exe.addCompileFlags([][]const u8 {
"-std=c99",
});
exe.addCompileFlags([][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.linkLibrary(lib);

View File

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

View File

@ -48,9 +48,7 @@ pub fn resolveZigLibDir(allocator: &mem.Allocator) ![]u8 {
\\Unable to find zig lib directory: {}.
\\Reinstall Zig or use --zig-install-prefix.
\\
,
@errorName(err)
);
, @errorName(err));
return error.ZigLibDirNotFound;
};

View File

@ -108,5 +108,4 @@ pub const Instruction = struct {
ArgType,
Export,
};
};

View File

@ -37,7 +37,7 @@ const usage =
\\ zen Print zen of zig and exit
\\
\\
;
;
const Command = struct {
name: []const u8,
@ -63,22 +63,61 @@ pub fn main() !void {
os.exit(1);
}
const commands = []Command {
Command { .name = "build", .exec = cmdBuild },
Command { .name = "build-exe", .exec = cmdBuildExe },
Command { .name = "build-lib", .exec = cmdBuildLib },
Command { .name = "build-obj", .exec = cmdBuildObj },
Command { .name = "fmt", .exec = cmdFmt },
Command { .name = "run", .exec = cmdRun },
Command { .name = "targets", .exec = cmdTargets },
Command { .name = "test", .exec = cmdTest },
Command { .name = "translate-c", .exec = cmdTranslateC },
Command { .name = "version", .exec = cmdVersion },
Command { .name = "zen", .exec = cmdZen },
const commands = []Command{
Command{
.name = "build",
.exec = cmdBuild,
},
Command{
.name = "build-exe",
.exec = cmdBuildExe,
},
Command{
.name = "build-lib",
.exec = cmdBuildLib,
},
Command{
.name = "build-obj",
.exec = cmdBuildObj,
},
Command{
.name = "fmt",
.exec = cmdFmt,
},
Command{
.name = "run",
.exec = cmdRun,
},
Command{
.name = "targets",
.exec = cmdTargets,
},
Command{
.name = "test",
.exec = cmdTest,
},
Command{
.name = "translate-c",
.exec = cmdTranslateC,
},
Command{
.name = "version",
.exec = cmdVersion,
},
Command{
.name = "zen",
.exec = cmdZen,
},
// undocumented commands
Command { .name = "help", .exec = cmdHelp },
Command { .name = "internal", .exec = cmdInternal },
Command{
.name = "help",
.exec = cmdHelp,
},
Command{
.name = "internal",
.exec = cmdInternal,
},
};
for (commands) |command| {
@ -120,9 +159,9 @@ const usage_build =
\\ --verbose-cimport Enable compiler debug output for C imports
\\
\\
;
;
const args_build_spec = []Flag {
const args_build_spec = []Flag{
Flag.Bool("--help"),
Flag.Bool("--init"),
Flag.Arg1("--build-file"),
@ -148,7 +187,7 @@ const missing_build_file =
\\
\\See: `zig build --help` or `zig help` for more options.
\\
;
;
fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
var flags = try Args.parse(allocator, args_build_spec, args);
@ -317,15 +356,23 @@ const usage_build_generic =
\\ --ver-patch [ver] Dynamic library semver patch version
\\
\\
;
;
const args_build_generic = []Flag {
const args_build_generic = []Flag{
Flag.Bool("--help"),
Flag.Option("--color", []const []const u8 { "auto", "off", "on" }),
Flag.Option("--color", []const []const u8{
"auto",
"off",
"on",
}),
Flag.ArgMergeN("--assembly", 1),
Flag.Arg1("--cache-dir"),
Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }),
Flag.Option("--emit", []const []const u8{
"asm",
"bin",
"llvm-ir",
}),
Flag.Bool("--enable-timing-info"),
Flag.Arg1("--libc-include-dir"),
Flag.Arg1("--name"),
@ -471,7 +518,7 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
os.exit(1);
};
const asm_a= flags.many("assembly");
const asm_a = flags.many("assembly");
const obj_a = flags.many("object");
if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
@ -493,17 +540,16 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
defer allocator.free(zig_lib_dir);
var module =
try Module.create(
allocator,
root_name,
zig_root_source_file,
Target.Native,
out_type,
build_mode,
zig_lib_dir,
full_cache_dir
);
var module = try Module.create(
allocator,
root_name,
zig_root_source_file,
Target.Native,
out_type,
build_mode,
zig_lib_dir,
full_cache_dir,
);
defer module.destroy();
module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
@ -588,10 +634,10 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
}
if (flags.single("mmacosx-version-min")) |ver| {
module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
module.darwin_version_min = Module.DarwinVersionMin{ .MacOS = ver };
}
if (flags.single("mios-version-min")) |ver| {
module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
module.darwin_version_min = Module.DarwinVersionMin{ .Ios = ver };
}
module.emit_file_type = emit_type;
@ -637,15 +683,11 @@ const usage_fmt =
\\
\\Options:
\\ --help Print this help and exit
\\ --keep-backups Retain backup entries for every file
\\
\\
;
;
const args_fmt_spec = []Flag {
Flag.Bool("--help"),
Flag.Bool("--keep-backups"),
};
const args_fmt_spec = []Flag{Flag.Bool("--help")};
fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
var flags = try Args.parse(allocator, args_fmt_spec, args);
@ -677,7 +719,6 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
};
defer tree.deinit();
var error_it = tree.errors.iterator(0);
while (error_it.next()) |parse_error| {
const token = tree.tokens.at(parse_error.loc());
@ -723,8 +764,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
inline while (i < @memberCount(builtin.Arch)) : (i += 1) {
comptime const arch_tag = @memberName(builtin.Arch, i);
// NOTE: Cannot use empty string, see #918.
comptime const native_str =
if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
comptime const native_str = if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
try stdout.print(" {}{}", arch_tag, native_str);
}
@ -737,8 +777,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
inline while (i < @memberCount(builtin.Os)) : (i += 1) {
comptime const os_tag = @memberName(builtin.Os, i);
// NOTE: Cannot use empty string, see #918.
comptime const native_str =
if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
comptime const native_str = if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
try stdout.print(" {}{}", os_tag, native_str);
}
@ -751,8 +790,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
comptime const environ_tag = @memberName(builtin.Environ, i);
// NOTE: Cannot use empty string, see #918.
comptime const native_str =
if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
comptime const native_str = if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
try stdout.print(" {}{}", environ_tag, native_str);
}
@ -774,12 +812,9 @@ const usage_test =
\\ --help Print this help and exit
\\
\\
;
const args_test_spec = []Flag {
Flag.Bool("--help"),
};
;
const args_test_spec = []Flag{Flag.Bool("--help")};
fn cmdTest(allocator: &Allocator, args: []const []const u8) !void {
var flags = try Args.parse(allocator, args_build_spec, args);
@ -812,21 +847,18 @@ const usage_run =
\\ --help Print this help and exit
\\
\\
;
const args_run_spec = []Flag {
Flag.Bool("--help"),
};
;
const args_run_spec = []Flag{Flag.Bool("--help")};
fn cmdRun(allocator: &Allocator, args: []const []const u8) !void {
var compile_args = args;
var runtime_args: []const []const u8 = []const []const u8 {};
var runtime_args: []const []const u8 = []const []const u8{};
for (args) |argv, i| {
if (mem.eql(u8, argv, "--")) {
compile_args = args[0..i];
runtime_args = args[i+1..];
runtime_args = args[i + 1..];
break;
}
}
@ -860,9 +892,9 @@ const usage_translate_c =
\\ --output [path] Output file to write generated zig file (default: stdout)
\\
\\
;
;
const args_translate_c_spec = []Flag {
const args_translate_c_spec = []Flag{
Flag.Bool("--help"),
Flag.Bool("--enable-timing-info"),
Flag.Arg1("--libc-include-dir"),
@ -936,7 +968,7 @@ const info_zen =
\\ * Together we serve end users.
\\
\\
;
;
fn cmdZen(allocator: &Allocator, args: []const []const u8) !void {
try stdout.write(info_zen);
@ -951,7 +983,7 @@ const usage_internal =
\\ build-info Print static compiler build-info
\\
\\
;
;
fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
if (args.len == 0) {
@ -959,9 +991,10 @@ fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
os.exit(1);
}
const sub_commands = []Command {
Command { .name = "build-info", .exec = cmdInternalBuildInfo },
};
const sub_commands = []Command{Command{
.name = "build-info",
.exec = cmdInternalBuildInfo,
}};
for (sub_commands) |sub_command| {
if (mem.eql(u8, sub_command.name, args[0])) {
@ -985,7 +1018,7 @@ fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
\\ZIG_C_HEADER_FILES {}
\\ZIG_DIA_GUIDS_LIB {}
\\
,
,
std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),

View File

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

View File

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

View File

@ -379,6 +379,7 @@ enum NodeType {
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypePtrDeref,
NodeTypeUse,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
@ -603,13 +604,16 @@ struct AstNodeFieldAccessExpr {
Buf *field_name;
};
struct AstNodePtrDerefExpr {
AstNode *target;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
PrefixOpBinNot,
PrefixOpNegation,
PrefixOpNegationWrap,
PrefixOpDereference,
PrefixOpMaybe,
PrefixOpUnwrapMaybe,
};
@ -911,6 +915,7 @@ struct AstNode {
AstNodeCompTime comptime_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodePtrDerefExpr ptr_deref_expr;
AstNodeContainerDecl container_decl;
AstNodeStructField struct_field;
AstNodeStringLiteral string_literal;
@ -1340,6 +1345,7 @@ enum BuiltinFnId {
BuiltinFnIdOffsetOf,
BuiltinFnIdInlineCall,
BuiltinFnIdNoInlineCall,
BuiltinFnIdNewStackCall,
BuiltinFnIdTypeId,
BuiltinFnIdShlExact,
BuiltinFnIdShrExact,
@ -1656,8 +1662,13 @@ struct CodeGen {
LLVMValueRef coro_alloc_helper_fn_val;
LLVMValueRef merge_err_ret_traces_fn_val;
LLVMValueRef add_error_return_trace_addr_fn_val;
LLVMValueRef stacksave_fn_val;
LLVMValueRef stackrestore_fn_val;
LLVMValueRef write_register_fn_val;
bool error_during_imports;
LLVMValueRef sp_md_node;
const char **clang_argv;
size_t clang_argv_len;
ZigList<const char *> lib_dirs;
@ -2280,6 +2291,7 @@ struct IrInstructionCall {
bool is_async;
IrInstruction *async_allocator;
IrInstruction *new_stack;
};
struct IrInstructionConst {

View File

@ -25,6 +25,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type);
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type);
static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type);
static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type);
static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
if (node->owner->c_import_node != nullptr) {
@ -1007,7 +1008,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
if (fn_type_id->return_type != nullptr) {
ensure_complete_type(g, fn_type_id->return_type);
} else {
zig_panic("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447");
zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447");
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
@ -1556,7 +1557,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
return g->builtin_types.entry_invalid;
}
add_node_error(g, proto_node,
buf_sprintf("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447"));
buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
return g->builtin_types.entry_invalid;
//return get_generic_fn_type(g, &fn_type_id);
}
@ -3281,6 +3282,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:
@ -3879,7 +3881,7 @@ static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entr
}
}
static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
if (infer_fn != nullptr) {
if (infer_fn->anal_state == FnAnalStateInvalid) {
@ -3931,7 +3933,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
}
if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
fn_table_entry->anal_state = FnAnalStateInvalid;
return;
}
@ -3961,7 +3963,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
fn_table_entry->anal_state = FnAnalStateComplete;
}
void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
assert(fn_table_entry->anal_state != FnAnalStateProbing);
if (fn_table_entry->anal_state != FnAnalStateReady)
return;

View File

@ -191,7 +191,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node);
TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);

View File

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

View File

@ -582,7 +582,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
}
// Note: byval is disabled on windows due to an LLVM bug:
// https://github.com/zig-lang/zig/issues/536
// https://github.com/ziglang/zig/issues/536
if (is_byval && g->zig_target.os != OsWindows) {
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
}
@ -938,6 +938,53 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
return g->memcpy_fn_val;
}
static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
if (g->stacksave_fn_val)
return g->stacksave_fn_val;
// declare i8* @llvm.stacksave()
LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
return g->stacksave_fn_val;
}
static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
if (g->stackrestore_fn_val)
return g->stackrestore_fn_val;
// declare void @llvm.stackrestore(i8* %ptr)
LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), &param_type, 1, false);
g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
return g->stackrestore_fn_val;
}
static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
if (g->write_register_fn_val)
return g->write_register_fn_val;
// declare void @llvm.write_register.i64(metadata, i64 @value)
// !0 = !{!"sp\00"}
LLVMTypeRef param_types[] = {
LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
LLVMIntType(g->pointer_size_bytes * 8),
};
LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
assert(LLVMGetIntrinsicID(g->write_register_fn_val));
return g->write_register_fn_val;
}
static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
if (g->coro_destroy_fn_val)
return g->coro_destroy_fn_val;
@ -2901,6 +2948,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
return 1 + get_async_allocator_arg_index(g, fn_type_id);
}
static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
}
static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
if (g->sp_md_node == nullptr) {
Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
g->sp_md_node = LLVMMDNode(&str_node, 1);
}
LLVMValueRef params[] = {
g->sp_md_node,
aligned_end_addr,
};
LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
}
static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
LLVMValueRef fn_val;
TypeTableEntry *fn_type;
@ -2967,13 +3046,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
LLVMValueRef result;
if (instruction->new_stack == nullptr) {
result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
} else {
LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
gen_set_stack_pointer(g, new_stack_addr);
result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
}
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
// Note: byval is disabled on windows due to an LLVM bug:
// https://github.com/zig-lang/zig/issues/536
// https://github.com/ziglang/zig/issues/536
if (gen_info->is_byval && g->zig_target.os != OsWindows) {
addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
}
@ -6171,6 +6265,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
@ -6635,7 +6730,7 @@ static void init(CodeGen *g) {
const char *target_specific_features;
if (g->is_native_target) {
// LLVM creates invalid binaries on Windows sometimes.
// See https://github.com/zig-lang/zig/issues/508
// See https://github.com/ziglang/zig/issues/508
// As a workaround we do not use target native features on Windows.
if (g->zig_target.os == OsWindows) {
target_specific_cpu_args = "";

View File

@ -1102,7 +1102,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
IrInstruction *new_stack)
{
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
call_instruction->fn_entry = fn_entry;
@ -1113,6 +1114,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->arg_count = arg_count;
call_instruction->is_async = is_async;
call_instruction->async_allocator = async_allocator;
call_instruction->new_stack = new_stack;
if (fn_ref)
ir_ref_instruction(fn_ref, irb->current_basic_block);
@ -1120,16 +1122,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
ir_ref_instruction(args[i], irb->current_basic_block);
if (async_allocator)
ir_ref_instruction(async_allocator, irb->current_basic_block);
if (new_stack != nullptr)
ir_ref_instruction(new_stack, irb->current_basic_block);
return &call_instruction->base;
}
static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
IrInstruction *new_stack)
{
IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, new_stack);
ir_link_new_instruction(new_instruction, old_instruction);
return new_instruction;
}
@ -4303,7 +4308,37 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdNewStackCall:
{
if (node->data.fn_call_expr.params.length == 0) {
add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
return irb->codegen->invalid_instruction;
}
AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
if (new_stack == irb->codegen->invalid_instruction)
return new_stack;
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
size_t arg_count = node->data.fn_call_expr.params.length - 2;
IrInstruction **args = allocate<IrInstruction*>(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
args[i] = ir_gen_node(irb, arg_node, scope);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdTypeId:
@ -4513,7 +4548,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
}
}
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
return ir_lval_wrap(irb, scope, fn_call, lval);
}
@ -4574,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)
@ -4716,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:
@ -6553,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:
@ -6825,7 +6866,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction **args = allocate<IrInstruction *>(arg_count);
args[0] = implicit_allocator_ptr; // self
args[1] = mem_slice; // old_mem
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
@ -7592,38 +7633,16 @@ static bool slice_is_const(TypeTableEntry *type) {
return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
}
static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) {
assert(err_set_type->id == TypeTableEntryIdErrorSet);
FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
if (infer_fn != nullptr) {
if (infer_fn->anal_state == FnAnalStateInvalid) {
return false;
} else if (infer_fn->anal_state == FnAnalStateReady) {
analyze_fn_body(ira->codegen, infer_fn);
if (err_set_type->data.error_set.infer_fn != nullptr) {
assert(ira->codegen->errors.length != 0);
return false;
}
} else {
ir_add_error_node(ira, source_node,
buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
return false;
}
}
return true;
}
static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry *set1, TypeTableEntry *set2,
AstNode *source_node)
{
assert(set1->id == TypeTableEntryIdErrorSet);
assert(set2->id == TypeTableEntryIdErrorSet);
if (!resolve_inferred_error_set(ira, set1, source_node)) {
if (!resolve_inferred_error_set(ira->codegen, set1, source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (!resolve_inferred_error_set(ira, set2, source_node)) {
if (!resolve_inferred_error_set(ira->codegen, set2, source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (type_is_global_error_set(set1)) {
@ -7762,7 +7781,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
return result;
}
if (!resolve_inferred_error_set(ira, contained_set, source_node)) {
if (!resolve_inferred_error_set(ira->codegen, contained_set, source_node)) {
result.id = ConstCastResultIdUnresolvedInferredErrSet;
return result;
}
@ -8151,7 +8170,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
} else {
err_set_type = prev_inst->value.type;
if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
update_errors_helper(ira->codegen, &errors, &errors_count);
@ -8190,7 +8209,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (type_is_global_error_set(err_set_type)) {
continue;
}
if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (type_is_global_error_set(cur_type)) {
@ -8256,7 +8275,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
continue;
}
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (type_is_global_error_set(cur_err_set_type)) {
@ -8319,7 +8338,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
continue;
}
if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
@ -8376,11 +8395,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
TypeTableEntry *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
@ -8490,7 +8509,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
{
if (err_set_type != nullptr) {
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) {
@ -8686,6 +8705,10 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
*dest = *src;
if (!same_global_refs) {
dest->global_refs = global_refs;
if (dest->type->id == TypeTableEntryIdStruct) {
dest->data.x_struct.fields = allocate_nonzero<ConstExprValue>(dest->type->data.structure.src_field_count);
memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count);
}
}
}
@ -9168,7 +9191,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
if (!val)
return ira->codegen->invalid_instruction;
if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
}
if (!type_is_global_error_set(wanted_type)) {
@ -9609,7 +9632,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
}
@ -9707,7 +9730,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
zig_unreachable();
}
if (!type_is_global_error_set(err_set_type)) {
if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
}
if (err_set_type->data.error_set.err_count == 0) {
@ -10602,7 +10625,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
return ira->codegen->builtin_types.entry_invalid;
}
if (!resolve_inferred_error_set(ira, intersect_type, source_node)) {
if (!resolve_inferred_error_set(ira->codegen, intersect_type, source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
@ -11458,11 +11481,11 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction
return ira->codegen->builtin_types.entry_type;
}
if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, op1_type, instruction->op1->other->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, op2_type, instruction->op2->other->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
@ -11670,7 +11693,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
if (var->mem_slot_index != SIZE_MAX) {
assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
*mem_slot = casted_init_value->value;
copy_const_val(mem_slot, &casted_init_value->value,
!is_comptime_var || var->gen_is_const);
if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
ir_build_const_from(ira, &decl_var_instruction->base);
@ -11987,7 +12011,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);
fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
result->value.type = async_return_type;
return result;
}
@ -12084,7 +12108,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
{
ir_add_error(ira, casted_arg,
buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557"));
return false;
}
@ -12285,7 +12309,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
if (fn_proto_node->data.fn_proto.is_var_args) {
ir_add_error(ira, &call_instruction->base,
buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313"));
return ira->codegen->builtin_types.entry_invalid;
}
@ -12357,6 +12381,19 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
return ir_finish_anal(ira, return_type);
}
IrInstruction *casted_new_stack = nullptr;
if (call_instruction->new_stack != nullptr) {
TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
IrInstruction *new_stack = call_instruction->new_stack->other;
if (type_is_invalid(new_stack->value.type))
return ira->codegen->builtin_types.entry_invalid;
casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
if (type_is_invalid(casted_new_stack->value.type))
return ira->codegen->builtin_types.entry_invalid;
}
if (fn_type->data.fn.is_generic) {
if (!fn_entry) {
ir_add_error(ira, call_instruction->fn_ref,
@ -12365,7 +12402,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
}
if (call_instruction->is_async && fn_type_id->is_var_args) {
ir_add_error(ira, call_instruction->fn_ref,
buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/zig-lang/zig/issues/557"));
buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/ziglang/zig/issues/557"));
return ira->codegen->builtin_types.entry_invalid;
}
@ -12448,7 +12485,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
if (arg_var == nullptr) {
ir_add_error(ira, arg,
buf_sprintf("compiler bug: var args can't handle void. https://github.com/zig-lang/zig/issues/557"));
buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
return ira->codegen->builtin_types.entry_invalid;
}
IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
@ -12583,7 +12620,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
assert(async_allocator_inst == nullptr);
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
call_instruction->is_async, nullptr);
call_instruction->is_async, nullptr, casted_new_stack);
ir_add_alloca(ira, new_call_instruction, return_type);
@ -12674,7 +12711,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
ir_add_alloca(ira, new_call_instruction, return_type);
return ir_finish_anal(ira, return_type);
@ -13792,7 +13829,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
}
err_set_type = err_entry->set_with_only_this_in_it;
} else {
if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) {
if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
err_entry = find_err_table_entry(child_type, field_name);
@ -15923,10 +15960,6 @@ static void ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
assert(!fn_entry->is_test);
analyze_fn_body(ira->codegen, fn_entry);
if (fn_entry->anal_state == FnAnalStateInvalid)
return;
AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
ConstExprValue *fn_def_val = create_const_vals(1);
@ -16496,6 +16529,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
{
size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
inner_fields[1].data.x_maybe = create_const_vals(1);
inner_fields[1].data.x_maybe->special = ConstValSpecialStatic;
inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;
bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);
}
@ -17503,7 +17537,7 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
} else if (container_type->id == TypeTableEntryIdUnion) {
result = container_type->data.unionation.src_field_count;
} else if (container_type->id == TypeTableEntryIdErrorSet) {
if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
if (!resolve_inferred_error_set(ira->codegen, container_type, instruction->base.source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (type_is_global_error_set(container_type)) {
@ -17807,7 +17841,7 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
}
TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) {
if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}
if (!type_is_global_error_set(err_set_type) &&
@ -17880,6 +17914,15 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_invalid;
TypeTableEntry *ptr_type = value->value.type;
// Because we don't have Pointer Reform yet, we can't have a pointer to a 'type'.
// Therefor, we have to check for type 'type' here, so we can output a correct error
// without asserting the assert below.
if (ptr_type->id == TypeTableEntryIdMetaType) {
ir_add_error(ira, value,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&ptr_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
// This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
assert(ptr_type->id == TypeTableEntryIdPointer);
@ -18030,7 +18073,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
if (type_is_invalid(end_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
assert(start_value->value.type->id == TypeTableEntryIdEnum);
if (start_value->value.type->id != TypeTableEntryIdEnum) {
ir_add_error(ira, range->start, buf_sprintf("not an enum type"));
return ira->codegen->builtin_types.entry_invalid;
}
BigInt start_index;
bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
@ -18071,7 +18118,7 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
}
}
} else if (switch_type->id == TypeTableEntryIdErrorSet) {
if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->source_node)) {
return ira->codegen->builtin_types.entry_invalid;
}

View File

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

View File

@ -702,6 +702,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsLinux:
case OsMacOSX:
case OsZen:
case OsOpenBSD:
switch (id) {
case CIntTypeShort:
case CIntTypeUShort:
@ -742,7 +743,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsKFreeBSD:
case OsLv2:
case OsNetBSD:
case OsOpenBSD:
case OsSolaris:
case OsHaiku:
case OsMinix:
@ -896,3 +896,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
return false;
}
const char *arch_stack_pointer_register_name(const ArchType *arch) {
switch (arch->arch) {
case ZigLLVM_UnknownArch:
zig_unreachable();
case ZigLLVM_x86:
return "sp";
case ZigLLVM_x86_64:
return "rsp";
case ZigLLVM_aarch64:
case ZigLLVM_arm:
case ZigLLVM_thumb:
case ZigLLVM_aarch64_be:
case ZigLLVM_amdgcn:
case ZigLLVM_amdil:
case ZigLLVM_amdil64:
case ZigLLVM_armeb:
case ZigLLVM_arc:
case ZigLLVM_avr:
case ZigLLVM_bpfeb:
case ZigLLVM_bpfel:
case ZigLLVM_hexagon:
case ZigLLVM_lanai:
case ZigLLVM_hsail:
case ZigLLVM_hsail64:
case ZigLLVM_kalimba:
case ZigLLVM_le32:
case ZigLLVM_le64:
case ZigLLVM_mips:
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
case ZigLLVM_mipsel:
case ZigLLVM_msp430:
case ZigLLVM_nios2:
case ZigLLVM_nvptx:
case ZigLLVM_nvptx64:
case ZigLLVM_ppc64le:
case ZigLLVM_r600:
case ZigLLVM_renderscript32:
case ZigLLVM_renderscript64:
case ZigLLVM_riscv32:
case ZigLLVM_riscv64:
case ZigLLVM_shave:
case ZigLLVM_sparc:
case ZigLLVM_sparcel:
case ZigLLVM_sparcv9:
case ZigLLVM_spir:
case ZigLLVM_spir64:
case ZigLLVM_systemz:
case ZigLLVM_tce:
case ZigLLVM_tcele:
case ZigLLVM_thumbeb:
case ZigLLVM_wasm32:
case ZigLLVM_wasm64:
case ZigLLVM_xcore:
case ZigLLVM_ppc:
case ZigLLVM_ppc64:
zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
}
zig_unreachable();
}

View File

@ -77,6 +77,8 @@ size_t target_arch_count(void);
const ArchType *get_target_arch(size_t index);
void get_arch_name(char *out_str, const ArchType *arch);
const char *arch_stack_pointer_register_name(const ArchType *arch);
size_t target_vendor_count(void);
ZigLLVM_VendorType get_target_vendor(size_t index);

View File

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

View File

@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) type {
return AlignedArrayList(T, @alignOf(T));
}
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
return struct {
const Self = this;
@ -21,7 +21,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
/// Deinitialize with `deinit` or use `toOwnedSlice`.
pub fn init(allocator: &Allocator) Self {
return Self {
return Self{
.items = []align(A) T{},
.len = 0,
.allocator = allocator,
@ -52,7 +52,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
/// allocated with `allocator`.
/// Deinitialize with `deinit` or use `toOwnedSlice`.
pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {
return Self {
return Self{
.items = slice,
.len = slice.len,
.allocator = allocator,
@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
pub fn toOwnedSlice(self: &Self) []align(A) T {
const allocator = self.allocator;
const result = allocator.alignedShrink(T, A, self.items, self.len);
*self = init(allocator);
self.* = init(allocator);
return result;
}
@ -71,21 +71,21 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
try l.ensureCapacity(l.len + 1);
l.len += 1;
mem.copy(T, l.items[n+1..l.len], l.items[n..l.len-1]);
l.items[n] = *item;
mem.copy(T, l.items[n + 1..l.len], l.items[n..l.len - 1]);
l.items[n] = item.*;
}
pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
try l.ensureCapacity(l.len + items.len);
l.len += items.len;
mem.copy(T, l.items[n+items.len..l.len], l.items[n..l.len-items.len]);
mem.copy(T, l.items[n..n+items.len], items);
mem.copy(T, l.items[n + items.len..l.len], l.items[n..l.len - items.len]);
mem.copy(T, l.items[n..n + items.len], items);
}
pub fn append(l: &Self, item: &const T) !void {
const new_item_ptr = try l.addOne();
*new_item_ptr = *item;
new_item_ptr.* = item.*;
}
pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
@ -128,8 +128,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
}
pub fn popOrNull(self: &Self) ?T {
if (self.len == 0)
return null;
if (self.len == 0) return null;
return self.pop();
}
@ -151,7 +150,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
};
pub fn iterator(self: &const Self) Iterator {
return Iterator { .list = self, .count = 0 };
return Iterator{
.list = self,
.count = 0,
};
}
};
}
@ -160,13 +162,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 +187,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);
}
@ -198,7 +210,7 @@ test "iterator ArrayList test" {
try list.append(2);
try list.append(3);
var count : i32 = 0;
var count: i32 = 0;
var it = list.iterator();
while (it.next()) |next| {
assert(next == count + 1);
@ -216,7 +228,7 @@ test "iterator ArrayList test" {
}
it.reset();
assert(?? it.next() == 1);
assert(??it.next() == 1);
}
test "insert ArrayList test" {
@ -228,12 +240,15 @@ test "insert ArrayList test" {
assert(list.items[0] == 5);
assert(list.items[1] == 1);
try list.insertSlice(1, []const i32 { 9, 8 });
try list.insertSlice(1, []const i32{
9,
8,
});
assert(list.items[0] == 5);
assert(list.items[1] == 9);
assert(list.items[2] == 8);
const items = []const i32 { 1 };
const items = []const i32{1};
try list.insertSlice(0, items[0..0]);
assert(list.items[0] == 5);
}

View File

@ -16,7 +16,7 @@ pub fn Queue(comptime T: type) type {
data: T,
};
// TODO: well defined copy elision: https://github.com/zig-lang/zig/issues/287
// TODO: well defined copy elision: https://github.com/ziglang/zig/issues/287
pub fn init(self: &Self) void {
self.root.next = null;
self.head = &self.root;
@ -70,7 +70,7 @@ test "std.atomic.queue" {
var queue: Queue(i32) = undefined;
queue.init();
var context = Context {
var context = Context{
.allocator = a,
.queue = &queue,
.put_sum = 0,
@ -81,16 +81,18 @@ test "std.atomic.queue" {
var putters: [put_thread_count]&std.os.Thread = undefined;
for (putters) |*t| {
*t = try std.os.spawnThread(&context, startPuts);
t.* = try std.os.spawnThread(&context, startPuts);
}
var getters: [put_thread_count]&std.os.Thread = undefined;
for (getters) |*t| {
*t = try std.os.spawnThread(&context, startGets);
t.* = try std.os.spawnThread(&context, startGets);
}
for (putters) |t| t.wait();
for (putters) |t|
t.wait();
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
for (getters) |t| t.wait();
for (getters) |t|
t.wait();
std.debug.assert(context.put_sum == context.get_sum);
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);

View File

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

View File

@ -41,12 +41,10 @@ pub const Base64Encoder = struct {
dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
out_index += 1;
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
((source[i + 1] & 0xf0) >> 4)];
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
out_index += 1;
dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) |
((source[i + 2] & 0xc0) >> 6)];
dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) | ((source[i + 2] & 0xc0) >> 6)];
out_index += 1;
dest[out_index] = encoder.alphabet_chars[source[i + 2] & 0x3f];
@ -64,8 +62,7 @@ pub const Base64Encoder = struct {
dest[out_index] = encoder.pad_char;
out_index += 1;
} else {
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
((source[i + 1] & 0xf0) >> 4)];
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
out_index += 1;
dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2];
@ -84,6 +81,7 @@ pub const Base64Decoder = struct {
/// e.g. 'A' => 0.
/// undefined for any value not in the 64 alphabet chars.
char_to_index: [256]u8,
/// true only for the 64 chars in the alphabet, not the pad char.
char_in_alphabet: [256]bool,
pad_char: u8,
@ -131,26 +129,20 @@ pub const Base64Decoder = struct {
// common case
if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter;
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
decoder.char_to_index[source[src_cursor + 1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
decoder.char_to_index[source[src_cursor + 2]] >> 2;
dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 |
decoder.char_to_index[source[src_cursor + 3]];
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 | decoder.char_to_index[source[src_cursor + 3]];
dest_cursor += 3;
} else if (source[src_cursor + 2] != decoder.pad_char) {
// one pad char
if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
decoder.char_to_index[source[src_cursor + 1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
decoder.char_to_index[source[src_cursor + 2]] >> 2;
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding;
dest_cursor += 2;
} else {
// two pad chars
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
decoder.char_to_index[source[src_cursor + 1]] >> 4;
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding;
dest_cursor += 1;
}
@ -165,7 +157,7 @@ pub const Base64DecoderWithIgnore = struct {
decoder: Base64Decoder,
char_is_ignored: [256]bool,
pub fn init(alphabet_chars: []const u8, pad_char: u8, ignore_chars: []const u8) Base64DecoderWithIgnore {
var result = Base64DecoderWithIgnore {
var result = Base64DecoderWithIgnore{
.decoder = Base64Decoder.init(alphabet_chars, pad_char),
.char_is_ignored = []bool{false} ** 256,
};
@ -223,10 +215,12 @@ pub const Base64DecoderWithIgnore = struct {
} else if (decoder_with_ignore.char_is_ignored[c]) {
// we can even ignore chars during the padding
continue;
} else return error.InvalidCharacter;
} else
return error.InvalidCharacter;
}
break;
} else return error.InvalidCharacter;
} else
return error.InvalidCharacter;
}
switch (available_chars) {
@ -234,22 +228,17 @@ pub const Base64DecoderWithIgnore = struct {
// common case
if (dest_cursor + 3 > dest.len) return error.OutputTooSmall;
assert(pad_char_count == 0);
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
decoder.char_to_index[next_4_chars[1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
decoder.char_to_index[next_4_chars[2]] >> 2;
dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 |
decoder.char_to_index[next_4_chars[3]];
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 | decoder.char_to_index[next_4_chars[3]];
dest_cursor += 3;
continue;
},
3 => {
if (dest_cursor + 2 > dest.len) return error.OutputTooSmall;
if (pad_char_count != 1) return error.InvalidPadding;
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
decoder.char_to_index[next_4_chars[1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
decoder.char_to_index[next_4_chars[2]] >> 2;
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding;
dest_cursor += 2;
break;
@ -257,8 +246,7 @@ pub const Base64DecoderWithIgnore = struct {
2 => {
if (dest_cursor + 1 > dest.len) return error.OutputTooSmall;
if (pad_char_count != 2) return error.InvalidPadding;
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
decoder.char_to_index[next_4_chars[1]] >> 4;
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding;
dest_cursor += 1;
break;
@ -280,7 +268,6 @@ pub const Base64DecoderWithIgnore = struct {
}
};
pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char);
pub const Base64DecoderUnsafe = struct {
@ -291,7 +278,7 @@ pub const Base64DecoderUnsafe = struct {
pub fn init(alphabet_chars: []const u8, pad_char: u8) Base64DecoderUnsafe {
assert(alphabet_chars.len == 64);
var result = Base64DecoderUnsafe {
var result = Base64DecoderUnsafe{
.char_to_index = undefined,
.pad_char = pad_char,
};
@ -321,16 +308,13 @@ pub const Base64DecoderUnsafe = struct {
}
while (in_buf_len > 4) {
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
decoder.char_to_index[source[src_index + 1]] >> 4;
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
dest_index += 1;
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
decoder.char_to_index[source[src_index + 2]] >> 2;
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
dest_index += 1;
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
decoder.char_to_index[source[src_index + 3]];
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
dest_index += 1;
src_index += 4;
@ -338,18 +322,15 @@ pub const Base64DecoderUnsafe = struct {
}
if (in_buf_len > 1) {
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
decoder.char_to_index[source[src_index + 1]] >> 4;
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
dest_index += 1;
}
if (in_buf_len > 2) {
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
decoder.char_to_index[source[src_index + 2]] >> 2;
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
dest_index += 1;
}
if (in_buf_len > 3) {
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
decoder.char_to_index[source[src_index + 3]];
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
dest_index += 1;
}
}
@ -367,7 +348,6 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {
return result;
}
test "base64" {
@setEvalBranchQuota(8000);
testBase64() catch unreachable;
@ -375,26 +355,26 @@ test "base64" {
}
fn testBase64() !void {
try testAllApis("", "");
try testAllApis("f", "Zg==");
try testAllApis("fo", "Zm8=");
try testAllApis("foo", "Zm9v");
try testAllApis("foob", "Zm9vYg==");
try testAllApis("fooba", "Zm9vYmE=");
try testAllApis("", "");
try testAllApis("f", "Zg==");
try testAllApis("fo", "Zm8=");
try testAllApis("foo", "Zm9v");
try testAllApis("foob", "Zm9vYg==");
try testAllApis("fooba", "Zm9vYmE=");
try testAllApis("foobar", "Zm9vYmFy");
try testDecodeIgnoreSpace("", " ");
try testDecodeIgnoreSpace("f", "Z g= =");
try testDecodeIgnoreSpace("fo", " Zm8=");
try testDecodeIgnoreSpace("foo", "Zm9v ");
try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
try testDecodeIgnoreSpace("", " ");
try testDecodeIgnoreSpace("f", "Z g= =");
try testDecodeIgnoreSpace("fo", " Zm8=");
try testDecodeIgnoreSpace("foo", "Zm9v ");
try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
try testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y ");
// test getting some api errors
try testError("A", error.InvalidPadding);
try testError("AA", error.InvalidPadding);
try testError("AAA", error.InvalidPadding);
try testError("A", error.InvalidPadding);
try testError("AA", error.InvalidPadding);
try testError("AAA", error.InvalidPadding);
try testError("A..A", error.InvalidCharacter);
try testError("AA=A", error.InvalidCharacter);
try testError("AA/=", error.InvalidPadding);
@ -427,8 +407,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
// Base64DecoderWithIgnore
{
const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
standard_alphabet_chars, standard_pad_char, "");
const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, "");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
@ -446,8 +425,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
}
fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void {
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
standard_alphabet_chars, standard_pad_char, " ");
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
var written = try standard_decoder_ignore_space.decode(decoded, encoded);
@ -455,8 +433,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi
}
fn testError(encoded: []const u8, expected_err: error) !void {
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
standard_alphabet_chars, standard_pad_char, " ");
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
var buffer: [0x100]u8 = undefined;
if (standard_decoder.calcSize(encoded)) |decoded_size| {
var decoded = buffer[0..decoded_size];
@ -471,8 +448,7 @@ fn testError(encoded: []const u8, expected_err: error) !void {
}
fn testOutputTooSmallError(encoded: []const u8) !void {
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
standard_alphabet_chars, standard_pad_char, " ");
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| {

View File

@ -12,9 +12,7 @@ pub const BufMap = struct {
const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8);
pub fn init(allocator: &Allocator) BufMap {
var self = BufMap {
.hash_map = BufMapHashMap.init(allocator),
};
var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) };
return self;
}

View File

@ -10,9 +10,7 @@ pub const BufSet = struct {
const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
pub fn init(a: &Allocator) BufSet {
var self = BufSet {
.hash_map = BufSetHashMap.init(a),
};
var self = BufSet{ .hash_map = BufSetHashMap.init(a) };
return self;
}

View File

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

View File

@ -82,10 +82,8 @@ pub const Builder = struct {
description: []const u8,
};
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8,
cache_root: []const u8) Builder
{
var self = Builder {
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
var self = Builder{
.zig_exe = zig_exe,
.build_root = build_root,
.cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
@ -112,12 +110,12 @@ pub const Builder = struct {
.lib_dir = undefined,
.exe_dir = undefined,
.installed_files = ArrayList([]const u8).init(allocator),
.uninstall_tls = TopLevelStep {
.uninstall_tls = TopLevelStep{
.step = Step.init("uninstall", allocator, makeUninstall),
.description = "Remove build artifacts from prefix path",
},
.have_uninstall_step = false,
.install_tls = TopLevelStep {
.install_tls = TopLevelStep{
.step = Step.initNoOp("install", allocator),
.description = "Copy build artifacts to prefix path",
},
@ -151,9 +149,7 @@ pub const Builder = struct {
return LibExeObjStep.createObject(self, name, root_src);
}
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8,
ver: &const Version) &LibExeObjStep
{
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);
}
@ -163,7 +159,7 @@ pub const Builder = struct {
pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {
const test_step = self.allocator.create(TestStep) catch unreachable;
*test_step = TestStep.init(self, root_src);
test_step.* = TestStep.init(self, root_src);
return test_step;
}
@ -190,33 +186,31 @@ pub const Builder = struct {
}
/// ::argv is copied.
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
argv: []const []const u8) &CommandStep
{
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
return CommandStep.create(self, cwd, env_map, argv);
}
pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {
const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
*write_file_step = WriteFileStep.init(self, file_path, data);
write_file_step.* = WriteFileStep.init(self, file_path, data);
return write_file_step;
}
pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) &LogStep {
const data = self.fmt(format, args);
const log_step = self.allocator.create(LogStep) catch unreachable;
*log_step = LogStep.init(self, data);
log_step.* = LogStep.init(self, data);
return log_step;
}
pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) &RemoveDirStep {
const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
*remove_dir_step = RemoveDirStep.init(self, dir_path);
remove_dir_step.* = RemoveDirStep.init(self, dir_path);
return remove_dir_step;
}
pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {
return Version {
return Version{
.major = major,
.minor = minor,
.patch = patch,
@ -254,8 +248,7 @@ pub const Builder = struct {
}
pub fn getInstallStep(self: &Builder) &Step {
if (self.have_install_step)
return &self.install_tls.step;
if (self.have_install_step) return &self.install_tls.step;
self.top_level_steps.append(&self.install_tls) catch unreachable;
self.have_install_step = true;
@ -263,8 +256,7 @@ pub const Builder = struct {
}
pub fn getUninstallStep(self: &Builder) &Step {
if (self.have_uninstall_step)
return &self.uninstall_tls.step;
if (self.have_uninstall_step) return &self.uninstall_tls.step;
self.top_level_steps.append(&self.uninstall_tls) catch unreachable;
self.have_uninstall_step = true;
@ -360,7 +352,7 @@ pub const Builder = struct {
pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
const type_id = comptime typeToEnum(T);
const available_option = AvailableOption {
const available_option = AvailableOption{
.name = name,
.type_id = type_id,
.description = description,
@ -413,7 +405,7 @@ pub const Builder = struct {
pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {
const step_info = self.allocator.create(TopLevelStep) catch unreachable;
*step_info = TopLevelStep {
step_info.* = TopLevelStep{
.step = Step.initNoOp(name, self.allocator),
.description = description,
};
@ -428,15 +420,7 @@ pub const Builder = struct {
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
const release_small = self.option(bool, "release-small", "size optimizations on and safety off") ?? false;
const mode = if (release_safe and !release_fast and !release_small)
builtin.Mode.ReleaseSafe
else if (release_fast and !release_safe and !release_small)
builtin.Mode.ReleaseFast
else if (release_small and !release_fast and !release_safe)
builtin.Mode.ReleaseSmall
else if (!release_fast and !release_safe and !release_small)
builtin.Mode.Debug
else x: {
const mode = if (release_safe and !release_fast and !release_small) builtin.Mode.ReleaseSafe else if (release_fast and !release_safe and !release_small) builtin.Mode.ReleaseFast else if (release_small and !release_fast and !release_safe) builtin.Mode.ReleaseSmall else if (!release_fast and !release_safe and !release_small) builtin.Mode.Debug else x: {
warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
self.markInvalidUserInput();
break :x builtin.Mode.Debug;
@ -446,9 +430,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 +442,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 +467,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 +540,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 +599,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 +641,19 @@ pub const Builder = struct {
if (builtin.environ == builtin.Environ.msvc) {
return "cl.exe";
} else {
return os.getEnvVarOwned(self.allocator, "CC") catch |err|
if (err == error.EnvironmentVariableNotFound)
([]const u8)("cc")
else
debug.panic("Unable to get environment variable: {}", 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);
}
}
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 +737,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 +762,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,
};
@ -860,61 +836,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 +902,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 +925,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),
@ -1006,8 +978,7 @@ pub const LibExeObjStep = struct {
} 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);
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 +986,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,15 +996,13 @@ 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 {
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();
}
@ -1099,10 +1067,7 @@ pub const LibExeObjStep = struct {
}
pub fn getOutputPath(self: &LibExeObjStep) []const u8 {
return if (self.output_path) |output_path|
output_path
else
os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
}
pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) void {
@ -1115,10 +1080,7 @@ pub const LibExeObjStep = struct {
}
pub fn getOutputHPath(self: &LibExeObjStep) []const u8 {
return if (self.output_h_path) |output_h_path|
output_h_path
else
os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
}
pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) void {
@ -1159,7 +1121,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 +1305,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);
}
}
@ -1505,8 +1466,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 +1495,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 +1540,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 +1593,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 +1602,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,15 +1632,13 @@ 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 {
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,
}
},
};
}
@ -1789,11 +1745,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 +1782,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 +1791,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 +1811,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 +1823,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 +1844,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 +1873,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 +1892,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 +1917,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 +1931,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 +1944,7 @@ pub const Step = struct {
fn makeNoOp(self: &Step) error!void {}
};
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
filename_name_only: []const u8) !void
{
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
const out_dir = os.path.dirname(output_path);
const out_basename = os.path.basename(output_path);
// sym link for libfoo.so.1 to libfoo.so.1.2.3

View File

@ -60,7 +60,7 @@ pub const sigset_t = u32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
pub const Sigaction = extern struct {
handler: extern fn(c_int)void,
handler: extern fn(c_int) void,
sa_mask: sigset_t,
sa_flags: c_int,
};

View File

@ -1,7 +1,7 @@
const builtin = @import("builtin");
const Os = builtin.Os;
pub use switch(builtin.os) {
pub use switch (builtin.os) {
Os.linux => @import("linux.zig"),
Os.windows => @import("windows.zig"),
Os.macosx, Os.ios => @import("darwin.zig"),
@ -21,8 +21,7 @@ pub extern "c" fn raise(sig: c_int) c_int;
pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;
pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int;
pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) isize;
pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,
fd: c_int, offset: isize) ?&c_void;
pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?&c_void;
pub extern "c" fn munmap(addr: &c_void, len: usize) c_int;
pub extern "c" fn unlink(path: &const u8) c_int;
pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
@ -34,8 +33,7 @@ pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;
pub extern "c" fn rename(old: &const u8, new: &const u8) c_int;
pub extern "c" fn chdir(path: &const u8) c_int;
pub extern "c" fn execve(path: &const u8, argv: &const ?&const u8,
envp: &const ?&const u8) c_int;
pub extern "c" fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) c_int;
pub extern "c" fn dup(fd: c_int) c_int;
pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
pub extern "c" fn readlink(noalias path: &const u8, noalias buf: &u8, bufsize: usize) isize;
@ -54,9 +52,7 @@ pub extern "c" fn realloc(&c_void, usize) ?&c_void;
pub extern "c" fn free(&c_void) void;
pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) c_int;
pub extern "pthread" fn pthread_create(noalias newthread: &pthread_t,
noalias attr: ?&const pthread_attr_t, start_routine: extern fn(?&c_void) ?&c_void,
noalias arg: ?&c_void) c_int;
pub extern "pthread" fn pthread_create(noalias newthread: &pthread_t, noalias attr: ?&const pthread_attr_t, start_routine: extern fn(?&c_void) ?&c_void, noalias arg: ?&c_void) c_int;
pub extern "pthread" fn pthread_attr_init(attr: &pthread_attr_t) c_int;
pub extern "pthread" fn pthread_attr_setstack(attr: &pthread_attr_t, stackaddr: &c_void, stacksize: usize) c_int;
pub extern "pthread" fn pthread_attr_destroy(attr: &pthread_attr_t) c_int;

View File

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

View File

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

View File

@ -6,12 +6,25 @@ const debug = @import("../debug/index.zig");
const fmt = @import("../fmt/index.zig");
const RoundParam = struct {
a: usize, b: usize, c: usize, d: usize,
k: usize, s: u32, t: u32
a: usize,
b: usize,
c: usize,
d: usize,
k: usize,
s: u32,
t: u32,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundParam {
return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
return RoundParam{
.a = a,
.b = b,
.c = c,
.d = d,
.k = k,
.s = s,
.t = t,
};
}
pub const Md5 = struct {
@ -99,7 +112,7 @@ pub const Md5 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Little);
}
}
@ -112,30 +125,33 @@ pub const Md5 = struct {
while (i < 16) : (i += 1) {
// NOTE: Performing or's separately improves perf by ~10%
s[i] = 0;
s[i] |= u32(b[i*4+0]);
s[i] |= u32(b[i*4+1]) << 8;
s[i] |= u32(b[i*4+2]) << 16;
s[i] |= u32(b[i*4+3]) << 24;
s[i] |= u32(b[i * 4 + 0]);
s[i] |= u32(b[i * 4 + 1]) << 8;
s[i] |= u32(b[i * 4 + 2]) << 16;
s[i] |= u32(b[i * 4 + 3]) << 24;
}
var v: [4]u32 = []u32 {
d.s[0], d.s[1], d.s[2], d.s[3],
var v: [4]u32 = []u32{
d.s[0],
d.s[1],
d.s[2],
d.s[3],
};
const round0 = comptime []RoundParam {
Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
const round0 = comptime []RoundParam{
Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
@ -145,22 +161,22 @@ pub const Md5 = struct {
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
}
const round1 = comptime []RoundParam {
Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
const round1 = comptime []RoundParam{
Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
Rp(3, 0, 1, 2, 10, 9, 0x02441453),
Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
Rp(3, 0, 1, 2, 10, 9, 0x02441453),
Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
};
inline for (round1) |r| {
@ -168,46 +184,46 @@ pub const Md5 = struct {
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
}
const round2 = comptime []RoundParam {
Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
const round2 = comptime []RoundParam{
Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
};
inline for (round2) |r| {
v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
}
const round3 = comptime []RoundParam {
Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
const round3 = comptime []RoundParam{
Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
};
inline for (round3) |r| {
v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
@ -255,7 +271,7 @@ test "md5 streaming" {
}
test "md5 aligned final" {
var block = []u8 {0} ** Md5.block_size;
var block = []u8{0} ** Md5.block_size;
var out: [Md5.digest_size]u8 = undefined;
var h = Md5.init();

View File

@ -7,11 +7,23 @@ const builtin = @import("builtin");
pub const u160 = @IntType(false, 160);
const RoundParam = struct {
a: usize, b: usize, c: usize, d: usize, e: usize, i: u32,
a: usize,
b: usize,
c: usize,
d: usize,
e: usize,
i: u32,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
return RoundParam{
.a = a,
.b = b,
.c = c,
.d = d,
.e = e,
.i = i,
};
}
pub const Sha1 = struct {
@ -99,7 +111,7 @@ pub const Sha1 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Big);
}
}
@ -108,21 +120,25 @@ pub const Sha1 = struct {
var s: [16]u32 = undefined;
var v: [5]u32 = []u32 {
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
var v: [5]u32 = []u32{
d.s[0],
d.s[1],
d.s[2],
d.s[3],
d.s[4],
};
const round0a = comptime []RoundParam {
Rp(0, 1, 2, 3, 4, 0),
Rp(4, 0, 1, 2, 3, 1),
Rp(3, 4, 0, 1, 2, 2),
Rp(2, 3, 4, 0, 1, 3),
Rp(1, 2, 3, 4, 0, 4),
Rp(0, 1, 2, 3, 4, 5),
Rp(4, 0, 1, 2, 3, 6),
Rp(3, 4, 0, 1, 2, 7),
Rp(2, 3, 4, 0, 1, 8),
Rp(1, 2, 3, 4, 0, 9),
const round0a = comptime []RoundParam{
Rp(0, 1, 2, 3, 4, 0),
Rp(4, 0, 1, 2, 3, 1),
Rp(3, 4, 0, 1, 2, 2),
Rp(2, 3, 4, 0, 1, 3),
Rp(1, 2, 3, 4, 0, 4),
Rp(0, 1, 2, 3, 4, 5),
Rp(4, 0, 1, 2, 3, 6),
Rp(3, 4, 0, 1, 2, 7),
Rp(2, 3, 4, 0, 1, 8),
Rp(1, 2, 3, 4, 0, 9),
Rp(0, 1, 2, 3, 4, 10),
Rp(4, 0, 1, 2, 3, 11),
Rp(3, 4, 0, 1, 2, 12),
@ -131,32 +147,27 @@ pub const Sha1 = struct {
Rp(0, 1, 2, 3, 4, 15),
};
inline for (round0a) |r| {
s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
(u32(b[r.i * 4 + 1]) << 16) |
(u32(b[r.i * 4 + 2]) << 8) |
(u32(b[r.i * 4 + 3]) << 0);
s[r.i] = (u32(b[r.i * 4 + 0]) << 24) | (u32(b[r.i * 4 + 1]) << 16) | (u32(b[r.i * 4 + 2]) << 8) | (u32(b[r.i * 4 + 3]) << 0);
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
+% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
v[r.b] = math.rotl(u32, v[r.b], u32(30));
}
const round0b = comptime []RoundParam {
const round0b = comptime []RoundParam{
Rp(4, 0, 1, 2, 3, 16),
Rp(3, 4, 0, 1, 2, 17),
Rp(2, 3, 4, 0, 1, 18),
Rp(1, 2, 3, 4, 0, 19),
};
inline for (round0b) |r| {
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
+% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
v[r.b] = math.rotl(u32, v[r.b], u32(30));
}
const round1 = comptime []RoundParam {
const round1 = comptime []RoundParam{
Rp(0, 1, 2, 3, 4, 20),
Rp(4, 0, 1, 2, 3, 21),
Rp(3, 4, 0, 1, 2, 22),
@ -179,15 +190,14 @@ pub const Sha1 = struct {
Rp(1, 2, 3, 4, 0, 39),
};
inline for (round1) |r| {
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
+% (v[r.b] ^ v[r.c] ^ v[r.d]);
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
v[r.b] = math.rotl(u32, v[r.b], u32(30));
}
const round2 = comptime []RoundParam {
const round2 = comptime []RoundParam{
Rp(0, 1, 2, 3, 4, 40),
Rp(4, 0, 1, 2, 3, 41),
Rp(3, 4, 0, 1, 2, 42),
@ -210,15 +220,14 @@ pub const Sha1 = struct {
Rp(1, 2, 3, 4, 0, 59),
};
inline for (round2) |r| {
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
+% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
v[r.b] = math.rotl(u32, v[r.b], u32(30));
}
const round3 = comptime []RoundParam {
const round3 = comptime []RoundParam{
Rp(0, 1, 2, 3, 4, 60),
Rp(4, 0, 1, 2, 3, 61),
Rp(3, 4, 0, 1, 2, 62),
@ -241,11 +250,10 @@ pub const Sha1 = struct {
Rp(1, 2, 3, 4, 0, 79),
};
inline for (round3) |r| {
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
+% (v[r.b] ^ v[r.c] ^ v[r.d]);
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
v[r.b] = math.rotl(u32, v[r.b], u32(30));
}
@ -286,7 +294,7 @@ test "sha1 streaming" {
}
test "sha1 aligned final" {
var block = []u8 {0} ** Sha1.block_size;
var block = []u8{0} ** Sha1.block_size;
var out: [Sha1.digest_size]u8 = undefined;
var h = Sha1.init();

View File

@ -9,12 +9,31 @@ const htest = @import("test.zig");
// Sha224 + Sha256
const RoundParam256 = struct {
a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
i: usize, k: u32,
a: usize,
b: usize,
c: usize,
d: usize,
e: usize,
f: usize,
g: usize,
h: usize,
i: usize,
k: u32,
};
fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) RoundParam256 {
return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
return RoundParam256{
.a = a,
.b = b,
.c = c,
.d = d,
.e = e,
.f = f,
.g = g,
.h = h,
.i = i,
.k = k,
};
}
const Sha2Params32 = struct {
@ -29,7 +48,7 @@ const Sha2Params32 = struct {
out_len: usize,
};
const Sha224Params = Sha2Params32 {
const Sha224Params = Sha2Params32{
.iv0 = 0xC1059ED8,
.iv1 = 0x367CD507,
.iv2 = 0x3070DD17,
@ -41,7 +60,7 @@ const Sha224Params = Sha2Params32 {
.out_len = 224,
};
const Sha256Params = Sha2Params32 {
const Sha256Params = Sha2Params32{
.iv0 = 0x6A09E667,
.iv1 = 0xBB67AE85,
.iv2 = 0x3C6EF372,
@ -56,216 +75,215 @@ const Sha256Params = Sha2Params32 {
pub const Sha224 = Sha2_32(Sha224Params);
pub const Sha256 = Sha2_32(Sha256Params);
fn Sha2_32(comptime params: Sha2Params32) type { return struct {
const Self = this;
const block_size = 64;
const digest_size = params.out_len / 8;
fn Sha2_32(comptime params: Sha2Params32) type {
return struct {
const Self = this;
const block_size = 64;
const digest_size = params.out_len / 8;
s: [8]u32,
// Streaming Cache
buf: [64]u8,
buf_len: u8,
total_len: u64,
s: [8]u32,
// Streaming Cache
buf: [64]u8,
buf_len: u8,
total_len: u64,
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 {
d.s[0] = params.iv0;
d.s[1] = params.iv1;
d.s[2] = params.iv2;
d.s[3] = params.iv3;
d.s[4] = params.iv4;
d.s[5] = params.iv5;
d.s[6] = params.iv6;
d.s[7] = params.iv7;
d.buf_len = 0;
d.total_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.round(d.buf[0..]);
pub fn reset(d: &Self) void {
d.s[0] = params.iv0;
d.s[1] = params.iv1;
d.s[2] = params.iv2;
d.s[3] = params.iv3;
d.s[4] = params.iv4;
d.s[5] = params.iv5;
d.s[6] = params.iv6;
d.s[7] = params.iv7;
d.buf_len = 0;
d.total_len = 0;
}
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.round(b[off..off + 64]);
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;
d.total_len += b.len;
}
// 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]);
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
d.round(d.buf[0..]);
d.buf_len = 0;
}
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.round(b[off..off + 64]);
}
// Append padding bits.
d.buf[d.buf_len] = 0x80;
d.buf_len += 1;
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
d.total_len += b.len;
}
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
// Append padding bits.
d.buf[d.buf_len] = 0x80;
d.buf_len += 1;
// > 448 mod 512 so need to add an extra round to wrap around.
if (64 - d.buf_len < 8) {
d.round(d.buf[0..]);
mem.set(u8, d.buf[0..], 0);
}
// Append message length.
var i: usize = 1;
var len = d.total_len >> 5;
d.buf[63] = u8(d.total_len & 0x1f) << 3;
while (i < 8) : (i += 1) {
d.buf[63 - i] = u8(len & 0xff);
len >>= 8;
}
// > 448 mod 512 so need to add an extra round to wrap around.
if (64 - d.buf_len < 8) {
d.round(d.buf[0..]);
mem.set(u8, d.buf[0..], 0);
// May truncate for possible 224 output
const rr = d.s[0..params.out_len / 32];
for (rr) |s, j| {
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Big);
}
}
// Append message length.
var i: usize = 1;
var len = d.total_len >> 5;
d.buf[63] = u8(d.total_len & 0x1f) << 3;
while (i < 8) : (i += 1) {
d.buf[63 - i] = u8(len & 0xff);
len >>= 8;
fn round(d: &Self, b: []const u8) void {
debug.assert(b.len == 64);
var s: [64]u32 = undefined;
var i: usize = 0;
while (i < 16) : (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;
}
while (i < 64) : (i += 1) {
s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u32, s[i - 15], u32(7)) ^ math.rotr(u32, s[i - 15], u32(18)) ^ (s[i - 15] >> 3)) +% (math.rotr(u32, s[i - 2], u32(17)) ^ math.rotr(u32, s[i - 2], u32(19)) ^ (s[i - 2] >> 10));
}
var v: [8]u32 = []u32{
d.s[0],
d.s[1],
d.s[2],
d.s[3],
d.s[4],
d.s[5],
d.s[6],
d.s[7],
};
const round0 = comptime []RoundParam256{
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
};
inline for (round0) |r| {
v[r.h] = v[r.h] +% (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
v[r.d] = v[r.d] +% v[r.h];
v[r.h] = v[r.h] +% (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
}
d.s[0] +%= v[0];
d.s[1] +%= v[1];
d.s[2] +%= v[2];
d.s[3] +%= v[3];
d.s[4] +%= v[4];
d.s[5] +%= v[5];
d.s[6] +%= v[6];
d.s[7] +%= v[7];
}
d.round(d.buf[0..]);
// May truncate for possible 224 output
const rr = d.s[0 .. params.out_len / 32];
for (rr) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
}
}
fn round(d: &Self, b: []const u8) void {
debug.assert(b.len == 64);
var s: [64]u32 = undefined;
var i: usize = 0;
while (i < 16) : (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;
}
while (i < 64) : (i += 1) {
s[i] =
s[i-16] +% s[i-7] +%
(math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
(math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
}
var v: [8]u32 = []u32 {
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
};
const round0 = comptime []RoundParam256 {
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
};
inline for (round0) |r| {
v[r.h] =
v[r.h] +%
(math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
(v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
r.k +% s[r.i];
v[r.d] = v[r.d] +% v[r.h];
v[r.h] =
v[r.h] +%
(math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
}
d.s[0] +%= v[0];
d.s[1] +%= v[1];
d.s[2] +%= v[2];
d.s[3] +%= v[3];
d.s[4] +%= v[4];
d.s[5] +%= v[5];
d.s[6] +%= v[6];
d.s[7] +%= v[7];
}
};}
};
}
test "sha224 single" {
htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
@ -320,7 +338,7 @@ test "sha256 streaming" {
}
test "sha256 aligned final" {
var block = []u8 {0} ** Sha256.block_size;
var block = []u8{0} ** Sha256.block_size;
var out: [Sha256.digest_size]u8 = undefined;
var h = Sha256.init();
@ -328,17 +346,35 @@ test "sha256 aligned final" {
h.final(out[0..]);
}
/////////////////////
// Sha384 + Sha512
const RoundParam512 = struct {
a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
i: usize, k: u64,
a: usize,
b: usize,
c: usize,
d: usize,
e: usize,
f: usize,
g: usize,
h: usize,
i: usize,
k: u64,
};
fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
return RoundParam512{
.a = a,
.b = b,
.c = c,
.d = d,
.e = e,
.f = f,
.g = g,
.h = h,
.i = i,
.k = k,
};
}
const Sha2Params64 = struct {
@ -353,7 +389,7 @@ const Sha2Params64 = struct {
out_len: usize,
};
const Sha384Params = Sha2Params64 {
const Sha384Params = Sha2Params64{
.iv0 = 0xCBBB9D5DC1059ED8,
.iv1 = 0x629A292A367CD507,
.iv2 = 0x9159015A3070DD17,
@ -365,7 +401,7 @@ const Sha384Params = Sha2Params64 {
.out_len = 384,
};
const Sha512Params = Sha2Params64 {
const Sha512Params = Sha2Params64{
.iv0 = 0x6A09E667F3BCC908,
.iv1 = 0xBB67AE8584CAA73B,
.iv2 = 0x3C6EF372FE94F82B,
@ -374,242 +410,241 @@ const Sha512Params = Sha2Params64 {
.iv5 = 0x9B05688C2B3E6C1F,
.iv6 = 0x1F83D9ABFB41BD6B,
.iv7 = 0x5BE0CD19137E2179,
.out_len = 512
.out_len = 512,
};
pub const Sha384 = Sha2_64(Sha384Params);
pub const Sha512 = Sha2_64(Sha512Params);
fn Sha2_64(comptime params: Sha2Params64) type { return struct {
const Self = this;
const block_size = 128;
const digest_size = params.out_len / 8;
fn Sha2_64(comptime params: Sha2Params64) type {
return struct {
const Self = this;
const block_size = 128;
const digest_size = params.out_len / 8;
s: [8]u64,
// Streaming Cache
buf: [128]u8,
buf_len: u8,
total_len: u128,
s: [8]u64,
// Streaming Cache
buf: [128]u8,
buf_len: u8,
total_len: u128,
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 {
d.s[0] = params.iv0;
d.s[1] = params.iv1;
d.s[2] = params.iv2;
d.s[3] = params.iv3;
d.s[4] = params.iv4;
d.s[5] = params.iv5;
d.s[6] = params.iv6;
d.s[7] = params.iv7;
d.buf_len = 0;
d.total_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.round(d.buf[0..]);
pub fn reset(d: &Self) void {
d.s[0] = params.iv0;
d.s[1] = params.iv1;
d.s[2] = params.iv2;
d.s[3] = params.iv3;
d.s[4] = params.iv4;
d.s[5] = params.iv5;
d.s[6] = params.iv6;
d.s[7] = params.iv7;
d.buf_len = 0;
d.total_len = 0;
}
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
d.round(b[off..off + 128]);
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;
d.total_len += b.len;
}
// 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]);
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
d.round(d.buf[0..]);
d.buf_len = 0;
}
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
d.round(b[off..off + 128]);
}
// Append padding bits.
d.buf[d.buf_len] = 0x80;
d.buf_len += 1;
// Copy any remainder for next pass.
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
d.buf_len += u8(b[off..].len);
d.total_len += b.len;
}
pub fn final(d: &Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
// Append padding bits.
d.buf[d.buf_len] = 0x80;
d.buf_len += 1;
// > 896 mod 1024 so need to add an extra round to wrap around.
if (128 - d.buf_len < 16) {
d.round(d.buf[0..]);
mem.set(u8, d.buf[0..], 0);
}
// Append message length.
var i: usize = 1;
var len = d.total_len >> 5;
d.buf[127] = u8(d.total_len & 0x1f) << 3;
while (i < 16) : (i += 1) {
d.buf[127 - i] = u8(len & 0xff);
len >>= 8;
}
// > 896 mod 1024 so need to add an extra round to wrap around.
if (128 - d.buf_len < 16) {
d.round(d.buf[0..]);
mem.set(u8, d.buf[0..], 0);
// May truncate for possible 384 output
const rr = d.s[0..params.out_len / 64];
for (rr) |s, j| {
mem.writeInt(out[8 * j..8 * j + 8], s, builtin.Endian.Big);
}
}
// Append message length.
var i: usize = 1;
var len = d.total_len >> 5;
d.buf[127] = u8(d.total_len & 0x1f) << 3;
while (i < 16) : (i += 1) {
d.buf[127 - i] = u8(len & 0xff);
len >>= 8;
fn round(d: &Self, b: []const u8) void {
debug.assert(b.len == 128);
var s: [80]u64 = undefined;
var i: usize = 0;
while (i < 16) : (i += 1) {
s[i] = 0;
s[i] |= u64(b[i * 8 + 0]) << 56;
s[i] |= u64(b[i * 8 + 1]) << 48;
s[i] |= u64(b[i * 8 + 2]) << 40;
s[i] |= u64(b[i * 8 + 3]) << 32;
s[i] |= u64(b[i * 8 + 4]) << 24;
s[i] |= u64(b[i * 8 + 5]) << 16;
s[i] |= u64(b[i * 8 + 6]) << 8;
s[i] |= u64(b[i * 8 + 7]) << 0;
}
while (i < 80) : (i += 1) {
s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u64, s[i - 15], u64(1)) ^ math.rotr(u64, s[i - 15], u64(8)) ^ (s[i - 15] >> 7)) +% (math.rotr(u64, s[i - 2], u64(19)) ^ math.rotr(u64, s[i - 2], u64(61)) ^ (s[i - 2] >> 6));
}
var v: [8]u64 = []u64{
d.s[0],
d.s[1],
d.s[2],
d.s[3],
d.s[4],
d.s[5],
d.s[6],
d.s[7],
};
const round0 = comptime []RoundParam512{
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
};
inline for (round0) |r| {
v[r.h] = v[r.h] +% (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
v[r.d] = v[r.d] +% v[r.h];
v[r.h] = v[r.h] +% (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
}
d.s[0] +%= v[0];
d.s[1] +%= v[1];
d.s[2] +%= v[2];
d.s[3] +%= v[3];
d.s[4] +%= v[4];
d.s[5] +%= v[5];
d.s[6] +%= v[6];
d.s[7] +%= v[7];
}
d.round(d.buf[0..]);
// May truncate for possible 384 output
const rr = d.s[0 .. params.out_len / 64];
for (rr) |s, j| {
mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
}
}
fn round(d: &Self, b: []const u8) void {
debug.assert(b.len == 128);
var s: [80]u64 = undefined;
var i: usize = 0;
while (i < 16) : (i += 1) {
s[i] = 0;
s[i] |= u64(b[i*8+0]) << 56;
s[i] |= u64(b[i*8+1]) << 48;
s[i] |= u64(b[i*8+2]) << 40;
s[i] |= u64(b[i*8+3]) << 32;
s[i] |= u64(b[i*8+4]) << 24;
s[i] |= u64(b[i*8+5]) << 16;
s[i] |= u64(b[i*8+6]) << 8;
s[i] |= u64(b[i*8+7]) << 0;
}
while (i < 80) : (i += 1) {
s[i] =
s[i-16] +% s[i-7] +%
(math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
(math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
}
var v: [8]u64 = []u64 {
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
};
const round0 = comptime []RoundParam512 {
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
};
inline for (round0) |r| {
v[r.h] =
v[r.h] +%
(math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
(v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
r.k +% s[r.i];
v[r.d] = v[r.d] +% v[r.h];
v[r.h] =
v[r.h] +%
(math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
}
d.s[0] +%= v[0];
d.s[1] +%= v[1];
d.s[2] +%= v[2];
d.s[3] +%= v[3];
d.s[4] +%= v[4];
d.s[5] +%= v[5];
d.s[6] +%= v[6];
d.s[7] +%= v[7];
}
};}
};
}
test "sha384 single" {
const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
@ -680,7 +715,7 @@ test "sha512 streaming" {
}
test "sha512 aligned final" {
var block = []u8 {0} ** Sha512.block_size;
var block = []u8{0} ** Sha512.block_size;
var out: [Sha512.digest_size]u8 = undefined;
var h = Sha512.init();

View File

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

View File

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

View File

@ -11,7 +11,7 @@ const Timer = time.Timer;
const HashFunction = @import("md5.zig").Md5;
const MiB = 1024 * 1024;
const BytesToHash = 1024 * MiB;
const BytesToHash = 1024 * MiB;
pub fn main() !void {
var stdout_file = try std.io.getStdOut();

View File

@ -9,7 +9,6 @@ pub const line_sep = switch (builtin.os) {
else => "\n",
};
pub fn len(ptr: &const u8) usize {
var count: usize = 0;
while (ptr[count] != 0) : (count += 1) {}
@ -95,7 +94,7 @@ pub const NullTerminated2DArray = struct {
}
index_buf[i] = null;
return NullTerminated2DArray {
return NullTerminated2DArray{
.allocator = allocator,
.byte_count = byte_count,
.ptr = @ptrCast(?&?&u8, buf.ptr),
@ -107,4 +106,3 @@ pub const NullTerminated2DArray = struct {
self.allocator.free(buf[0..self.byte_count]);
}
};

View File

@ -13,14 +13,14 @@ pub const FailingAllocator = struct {
deallocations: usize,
pub fn init(allocator: &mem.Allocator, fail_index: usize) FailingAllocator {
return FailingAllocator {
return FailingAllocator{
.internal_allocator = allocator,
.fail_index = fail_index,
.index = 0,
.allocated_bytes = 0,
.freed_bytes = 0,
.deallocations = 0,
.allocator = mem.Allocator {
.allocator = mem.Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,

View File

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

View File

@ -337,7 +337,6 @@ pub const AT_PGI_lbase = 0x3a00;
pub const AT_PGI_soffset = 0x3a01;
pub const AT_PGI_lstride = 0x3a02;
pub const OP_addr = 0x03;
pub const OP_deref = 0x06;
pub const OP_const1u = 0x08;
@ -577,7 +576,6 @@ pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
pub const CFA_advance_loc = 0x40;
pub const CFA_offset = 0x80;
pub const CFA_restore = 0xc0;

View File

@ -123,13 +123,11 @@ pub const DT_SYMINFO = 0x6ffffeff;
pub const DT_ADDRRNGHI = 0x6ffffeff;
pub const DT_ADDRNUM = 11;
pub const DT_VERSYM = 0x6ffffff0;
pub const DT_RELACOUNT = 0x6ffffff9;
pub const DT_RELCOUNT = 0x6ffffffa;
pub const DT_FLAGS_1 = 0x6ffffffb;
pub const DT_VERDEF = 0x6ffffffc;
@ -139,13 +137,10 @@ pub const DT_VERNEED = 0x6ffffffe;
pub const DT_VERNEEDNUM = 0x6fffffff;
pub const DT_VERSIONTAGNUM = 16;
pub const DT_AUXILIARY = 0x7ffffffd;
pub const DT_FILTER = 0x7fffffff;
pub const DT_EXTRANUM = 3;
pub const DT_SPARC_REGISTER = 0x70000001;
pub const DT_SPARC_NUM = 2;
@ -434,9 +429,7 @@ pub const Elf = struct {
try elf.in_file.seekForward(4);
const header_size = try in.readInt(elf.endian, u16);
if ((elf.is_64 and header_size != 64) or
(!elf.is_64 and header_size != 52))
{
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
return error.InvalidFormat;
}
@ -467,16 +460,16 @@ pub const Elf = struct {
if (sh_entry_size != 64) return error.InvalidFormat;
for (elf.section_headers) |*elf_section| {
elf_section.name = try in.readInt(elf.endian, u32);
elf_section.sh_type = try in.readInt(elf.endian, u32);
elf_section.flags = try in.readInt(elf.endian, u64);
elf_section.addr = try in.readInt(elf.endian, u64);
elf_section.offset = try in.readInt(elf.endian, u64);
elf_section.size = try in.readInt(elf.endian, u64);
elf_section.link = try in.readInt(elf.endian, u32);
elf_section.info = try in.readInt(elf.endian, u32);
elf_section.addr_align = try in.readInt(elf.endian, u64);
elf_section.ent_size = try in.readInt(elf.endian, u64);
elf_section.name = try in.readInt(elf.endian, u32);
elf_section.sh_type = try in.readInt(elf.endian, u32);
elf_section.flags = try in.readInt(elf.endian, u64);
elf_section.addr = try in.readInt(elf.endian, u64);
elf_section.offset = try in.readInt(elf.endian, u64);
elf_section.size = try in.readInt(elf.endian, u64);
elf_section.link = try in.readInt(elf.endian, u32);
elf_section.info = try in.readInt(elf.endian, u32);
elf_section.addr_align = try in.readInt(elf.endian, u64);
elf_section.ent_size = try in.readInt(elf.endian, u64);
}
} else {
if (sh_entry_size != 40) return error.InvalidFormat;
@ -513,8 +506,7 @@ pub const Elf = struct {
pub fn close(elf: &Elf) void {
elf.allocator.free(elf.section_headers);
if (elf.auto_close_stream)
elf.in_file.close();
if (elf.auto_close_stream) elf.in_file.close();
}
pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader {
@ -852,27 +844,27 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
flags2: Elf32_Word,
};
pub const Ehdr = switch(@sizeOf(usize)) {
pub const Ehdr = switch (@sizeOf(usize)) {
4 => Elf32_Ehdr,
8 => Elf64_Ehdr,
else => @compileError("expected pointer size of 32 or 64"),
};
pub const Phdr = switch(@sizeOf(usize)) {
pub const Phdr = switch (@sizeOf(usize)) {
4 => Elf32_Phdr,
8 => Elf64_Phdr,
else => @compileError("expected pointer size of 32 or 64"),
};
pub const Sym = switch(@sizeOf(usize)) {
pub const Sym = switch (@sizeOf(usize)) {
4 => Elf32_Sym,
8 => Elf64_Sym,
else => @compileError("expected pointer size of 32 or 64"),
};
pub const Verdef = switch(@sizeOf(usize)) {
pub const Verdef = switch (@sizeOf(usize)) {
4 => Elf32_Verdef,
8 => Elf64_Verdef,
else => @compileError("expected pointer size of 32 or 64"),
};
pub const Verdaux = switch(@sizeOf(usize)) {
pub const Verdaux = switch (@sizeOf(usize)) {
4 => Elf32_Verdaux,
8 => Elf64_Verdaux,
else => @compileError("expected pointer size of 32 or 64"),

View File

@ -6,7 +6,7 @@ const mem = std.mem;
const posix = std.os.posix;
pub const TcpServer = struct {
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void,
loop: &Loop,
sockfd: i32,
@ -18,13 +18,11 @@ pub const TcpServer = struct {
const PromiseNode = std.LinkedList(promise).Node;
pub fn init(loop: &Loop) !TcpServer {
const sockfd = try std.os.posixSocket(posix.AF_INET,
posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
posix.PROTO_tcp);
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
errdefer std.os.close(sockfd);
// TODO can't initialize handler coroutine here because we need well defined copy elision
return TcpServer {
return TcpServer{
.loop = loop,
.sockfd = sockfd,
.accept_coro = null,
@ -34,9 +32,7 @@ pub const TcpServer = struct {
};
}
pub fn listen(self: &TcpServer, address: &const std.net.Address,
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
{
pub fn listen(self: &TcpServer, address: &const std.net.Address, handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void) !void {
self.handleRequestFn = handleRequestFn;
try std.os.posixBind(self.sockfd, &address.os_addr);
@ -48,7 +44,6 @@ pub const TcpServer = struct {
try self.loop.addFd(self.sockfd, ??self.accept_coro);
errdefer self.loop.removeFd(self.sockfd);
}
pub fn deinit(self: &TcpServer) void {
@ -60,9 +55,7 @@ pub const TcpServer = struct {
pub async fn handler(self: &TcpServer) void {
while (true) {
var accepted_addr: std.net.Address = undefined;
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
{
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
var socket = std.os.File.openHandle(accepted_fd);
_ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
error.OutOfMemory => {
@ -83,19 +76,14 @@ pub const TcpServer = struct {
}
continue;
},
error.ConnectionAborted,
error.FileDescriptorClosed => continue,
error.ConnectionAborted, error.FileDescriptorClosed => continue,
error.PageFault => unreachable,
error.InvalidSyscall => unreachable,
error.FileDescriptorNotASocket => unreachable,
error.OperationNotSupported => unreachable,
error.SystemFdQuotaExceeded,
error.SystemResources,
error.ProtocolFailure,
error.BlockedByFirewall,
error.Unexpected => {
error.SystemFdQuotaExceeded, error.SystemResources, error.ProtocolFailure, error.BlockedByFirewall, error.Unexpected => {
@panic("TODO handle this error");
},
}
@ -110,7 +98,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 +106,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);
}
@ -130,7 +116,6 @@ pub const Loop = struct {
pub fn removeFd(self: &Loop, fd: i32) void {
std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
}
async fn waitFd(self: &Loop, fd: i32) !void {
defer self.removeFd(fd);
suspend |p| {
@ -157,9 +142,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/ziglang/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);
@ -178,12 +163,9 @@ test "listen on a port, send bytes, receive bytes" {
tcp_server: TcpServer,
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/ziglang/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 +173,13 @@ 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/ziglang/zig/issues/733
var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
var adapter = std.io.FileOutStream.init(&socket);
var stream = &adapter.stream;
@ -210,9 +191,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);
@ -220,7 +199,6 @@ test "listen on a port, send bytes, receive bytes" {
defer cancel p;
loop.run();
}
async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
errdefer @panic("test failure");

View File

@ -1,4 +1,4 @@
pub const enum3 = []u64 {
pub const enum3 = []u64{
0x4e2e2785c3a2a20b,
0x240a28877a09a4e1,
0x728fca36c06cf106,
@ -439,13 +439,13 @@ const Slab = struct {
};
fn slab(str: []const u8, exp: i32) Slab {
return Slab {
return Slab{
.str = str,
.exp = exp,
};
}
pub const enum3_data = []Slab {
pub const enum3_data = []Slab{
slab("40648030339495312", 69),
slab("4498645355592131", -134),
slab("678321594594593", 244),
@ -879,4 +879,3 @@ pub const enum3_data = []Slab {
slab("32216657306260762", 218),
slab("30423431424080128", 219),
};

View File

@ -86,7 +86,7 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
const data = enum3_data[i];
const digits = buffer[1..data.str.len + 1];
mem.copy(u8, digits, data.str);
return FloatDecimal {
return FloatDecimal{
.digits = digits,
.exp = data.exp,
};
@ -98,14 +98,12 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
/// Uncorrected Errol3 double to ASCII conversion.
fn errol3u(val: f64, buffer: []u8) FloatDecimal {
// check if in integer or fixed range
if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
return errolInt(val, buffer);
} else if (val >= 16.0 and val < 9.007199254740992e15) {
return errolFixed(val, buffer);
}
// normalize the midpoint
const e = math.frexp(val).exponent;
@ -137,11 +135,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 +169,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 +186,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 +229,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 +240,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 +295,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 +336,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 +346,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 +388,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,
};
@ -428,7 +419,7 @@ fn fpprev(val: f64) f64 {
return @bitCast(f64, @bitCast(u64, val) -% 1);
}
pub const c_digits_lut = []u8 {
pub const c_digits_lut = []u8{
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
'0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
'1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
@ -587,7 +578,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 +677,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 +703,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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,7 @@ const max_int_digits = 65;
/// Renders fmt string with args, calling output with slices of bytes.
/// If `output` returns an error, the error is returned from `format` and
/// `output` is not called again.
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
comptime fmt: []const u8, args: ...) Errors!void
{
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
const State = enum {
Start,
OpenBrace,
@ -27,6 +25,9 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
Character,
Buf,
BufWidth,
Bytes,
BytesBase,
BytesWidth,
};
comptime var start_index = 0;
@ -95,13 +96,18 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
'.' => {
state = State.Float;
},
'B' => {
width = 0;
radix = 1000;
state = State.Bytes;
},
else => @compileError("Unknown format character: " ++ []u8{c}),
},
State.Buf => switch (c) {
'}' => {
return output(context, args[next_arg]);
},
'0' ... '9' => {
'0'...'9' => {
width_start = i;
state = State.BufWidth;
},
@ -121,7 +127,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {
'0'...'9' => {
width_start = i;
state = State.IntegerWidth;
},
@ -135,7 +141,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.FloatScientific => switch (c) {
@ -145,7 +151,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {
'0'...'9' => {
width_start = i;
state = State.FloatScientificWidth;
},
@ -159,7 +165,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Float => switch (c) {
@ -169,7 +175,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {
'0'...'9' => {
width_start = i;
state = State.FloatWidth;
},
@ -183,7 +189,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BufWidth => switch (c) {
@ -194,7 +200,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
state = State.Start;
start_index = i + 1;
},
'0' ... '9' => {},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Character => switch (c) {
@ -206,6 +212,47 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Bytes => switch (c) {
'}' => {
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'i' => {
radix = 1024;
state = State.BytesBase;
},
'0'...'9' => {
width_start = i;
state = State.BytesWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BytesBase => switch (c) {
'}' => {
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {
width_start = i;
state = State.BytesWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BytesWidth => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatBytes(args[next_arg], width, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
}
}
comptime {
@ -221,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 => {
@ -256,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));
}
@ -270,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;
@ -289,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.
@ -338,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;
}
@ -350,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");
}
@ -381,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.
@ -431,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 '.'
@ -470,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) {
@ -489,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
@ -516,14 +558,54 @@ 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..]);
}
}
pub fn formatBytes(
value: var,
width: ?usize,
comptime radix: usize,
context: var,
comptime Errors: type,
output: fn(@typeOf(context), []const u8) Errors!void,
) Errors!void {
if (value == 0) {
return output(context, "0B");
}
pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
{
const mags = " KMGTPEZY";
const magnitude = switch (radix) {
1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
1024 => math.min(math.log2(value) / 10, mags.len - 1),
else => unreachable,
};
const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
const suffix = mags[magnitude];
try formatFloatDecimal(new_value, width, context, Errors, output);
if (suffix == ' ') {
return output(context, "B");
}
const buf = switch (radix) {
1000 => []u8{ suffix, 'B' },
1024 => []u8{ suffix, 'i', 'B' },
else => unreachable,
};
return output(context, buf);
}
pub fn formatInt(
value: var,
base: u8,
uppercase: bool,
width: usize,
context: var,
comptime Errors: type,
output: fn(@typeOf(context), []const u8) Errors!void,
) Errors!void {
if (@typeOf(value).is_signed) {
return formatIntSigned(value, base, uppercase, width, context, Errors, output);
} else {
@ -531,9 +613,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 = '-';
@ -552,9 +632,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;
@ -566,8 +644,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..];
@ -579,8 +656,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);
@ -592,7 +668,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,
};
@ -609,10 +685,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] == '+') {
@ -632,9 +706,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,
};
@ -653,22 +728,21 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
const value = switch (c) {
'0' ... '9' => c - '0',
'A' ... 'Z' => c - 'A' + 10,
'a' ... 'z' => c - 'a' + 10,
'0'...'9' => c - '0',
'A'...'Z' => c - 'A' + 10,
'a'...'z' => c - 'a' + 10,
else => return error.InvalidCharacter,
};
if (value >= radix)
return error.InvalidCharacter;
if (value >= radix) return error.InvalidCharacter;
return value;
}
fn digitToChar(digit: u8, uppercase: bool) u8 {
return switch (digit) {
0 ... 9 => digit + '0',
10 ... 35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
0...9 => digit + '0',
10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
else => unreachable,
};
}
@ -684,7 +758,7 @@ 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];
}
@ -697,7 +771,7 @@ pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...
}
fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
*size += bytes.len;
size.* += bytes.len;
}
test "buf print int" {
@ -738,44 +812,34 @@ test "parse unsigned comptime" {
test "fmt.format" {
{
var buf1: [32]u8 = undefined;
const value: ?i32 = 1234;
const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
assert(mem.eql(u8, result, "nullable: 1234\n"));
try testFmt("nullable: 1234\n", "nullable: {}\n", value);
}
{
var buf1: [32]u8 = undefined;
const value: ?i32 = null;
const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
assert(mem.eql(u8, result, "nullable: null\n"));
try testFmt("nullable: null\n", "nullable: {}\n", value);
}
{
var buf1: [32]u8 = undefined;
const value: error!i32 = 1234;
const result = try bufPrint(buf1[0..], "error union: {}\n", value);
assert(mem.eql(u8, result, "error union: 1234\n"));
try testFmt("error union: 1234\n", "error union: {}\n", value);
}
{
var buf1: [32]u8 = undefined;
const value: error!i32 = error.InvalidChar;
const result = try bufPrint(buf1[0..], "error union: {}\n", value);
assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
}
{
var buf1: [32]u8 = undefined;
const value: u3 = 0b101;
const result = try bufPrint(buf1[0..], "u3: {}\n", value);
assert(mem.eql(u8, result, "u3: 5\n"));
try testFmt("u3: 5\n", "u3: {}\n", value);
}
try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
{
// Dummy field because of https://github.com/zig-lang/zig/issues/557.
// Dummy field because of https://github.com/ziglang/zig/issues/557.
const Struct = struct {
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@"));
}
@ -986,9 +1050,22 @@ test "fmt.format" {
}
}
fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
var buf: [100]u8 = undefined;
const result = try bufPrint(buf[0..], template, args);
if (mem.eql(u8, result, expected)) return;
std.debug.warn("\n====== expected this output: =========\n");
std.debug.warn("{}", expected);
std.debug.warn("\n======== instead found this: =========\n");
std.debug.warn("{}", result);
std.debug.warn("\n======================================\n");
return error.TestFailed;
}
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) {
@ -1000,7 +1077,6 @@ pub fn trim(buf: []const u8) []const u8 {
}
}
break;
}
return buf[start..end];
}

View File

@ -13,9 +13,7 @@ pub const Adler32 = struct {
adler: u32,
pub fn init() Adler32 {
return Adler32 {
.adler = 1,
};
return Adler32{ .adler = 1 };
}
// This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
@ -33,8 +31,7 @@ pub const Adler32 = struct {
if (s2 >= base) {
s2 -= base;
}
}
else if (input.len < 16) {
} else if (input.len < 16) {
for (input) |b| {
s1 +%= b;
s2 +%= s1;
@ -44,8 +41,7 @@ pub const Adler32 = struct {
}
s2 %= base;
}
else {
} else {
var i: usize = 0;
while (i + nmax <= input.len) : (i += nmax) {
const n = nmax / 16; // note: 16 | nmax
@ -98,15 +94,14 @@ test "adler32 sanity" {
}
test "adler32 long" {
const long1 = []u8 {1} ** 1024;
const long1 = []u8{1} ** 1024;
debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
const long2 = []u8 {1} ** 1025;
const long2 = []u8{1} ** 1025;
debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
}
test "adler32 very long" {
const long = []u8 {1} ** 5553;
const long = []u8{1} ** 5553;
debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
}

View File

@ -9,9 +9,9 @@ const std = @import("../index.zig");
const debug = std.debug;
pub const Polynomial = struct {
const IEEE = 0xedb88320;
const IEEE = 0xedb88320;
const Castagnoli = 0x82f63b78;
const Koopman = 0xeb31d82e;
const Koopman = 0xeb31d82e;
};
// IEEE is by far the most common CRC and so is aliased by default.
@ -27,20 +27,22 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
for (tables[0]) |*e, i| {
var crc = u32(i);
var j: usize = 0; while (j < 8) : (j += 1) {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
crc = (crc >> 1) ^ poly;
} else {
crc = (crc >> 1);
}
}
*e = crc;
e.* = crc;
}
var i: usize = 0;
while (i < 256) : (i += 1) {
var crc = tables[0][i];
var j: usize = 1; while (j < 8) : (j += 1) {
var j: usize = 1;
while (j < 8) : (j += 1) {
const index = @truncate(u8, crc);
crc = tables[0][index] ^ (crc >> 8);
tables[j][i] = crc;
@ -53,19 +55,17 @@ 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);
@ -76,8 +76,8 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
lookup_tables[3][p[4]] ^
lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
lookup_tables[7][@truncate(u8, self.crc >> 0)];
lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
lookup_tables[7][@truncate(u8, self.crc >> 0)];
}
while (i < input.len) : (i += 1) {
@ -123,14 +123,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 +140,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
crc: u32,
pub fn init() Self {
return Self {
.crc = 0xffffffff,
};
return Self{ .crc = 0xffffffff };
}
pub fn update(self: &Self, input: []const u8) void {

View File

@ -7,7 +7,7 @@
const std = @import("../index.zig");
const debug = std.debug;
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
@ -18,9 +18,7 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
value: T,
pub fn init() Self {
return Self {
.value = offset,
};
return Self{ .value = offset };
}
pub fn update(self: &Self, input: []const u8) void {

View File

@ -45,7 +45,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
const k0 = mem.readInt(key[0..8], u64, Endian.Little);
const k1 = mem.readInt(key[8..16], u64, Endian.Little);
var d = Self {
var d = Self{
.v0 = k0 ^ 0x736f6d6570736575,
.v1 = k1 ^ 0x646f72616e646f6d,
.v2 = k0 ^ 0x6c7967656e657261,
@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
test "siphash64-2-4 sanity" {
const vectors = [][]const u8 {
const vectors = [][]const u8{
"\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
"\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
"\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
@ -241,7 +241,7 @@ test "siphash64-2-4 sanity" {
}
test "siphash128-2-4 sanity" {
const vectors = [][]const u8 {
const vectors = [][]const u8{
"\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
"\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
"\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",

View File

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

View File

@ -10,7 +10,7 @@ const c = std.c;
const Allocator = mem.Allocator;
pub const c_allocator = &c_allocator_state;
var c_allocator_state = Allocator {
var c_allocator_state = Allocator{
.allocFn = cAlloc,
.reallocFn = cRealloc,
.freeFn = cFree,
@ -18,10 +18,7 @@ var c_allocator_state = Allocator {
fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
assert(alignment <= @alignOf(c_longdouble));
return if (c.malloc(n)) |buf|
@ptrCast(&u8, buf)[0..n]
else
error.OutOfMemory;
return if (c.malloc(n)) |buf| @ptrCast(&u8, buf)[0..n] else error.OutOfMemory;
}
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
@ -48,8 +45,8 @@ pub const DirectAllocator = struct {
const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
pub fn init() DirectAllocator {
return DirectAllocator {
.allocator = Allocator {
return DirectAllocator{
.allocator = Allocator{
.allocFn = alloc,
.reallocFn = realloc,
.freeFn = free,
@ -73,37 +70,35 @@ pub const DirectAllocator = struct {
switch (builtin.os) {
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 +108,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"),
@ -144,13 +139,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 +153,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"),
@ -174,7 +169,7 @@ pub const DirectAllocator = struct {
},
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 +190,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 +223,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 +248,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 +264,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 +273,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 +294,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 +310,7 @@ pub const FixedBufferAllocator = struct {
}
}
fn free(allocator: &Allocator, bytes: []u8) void { }
fn free(allocator: &Allocator, bytes: []u8) void {}
};
/// lock free
@ -325,8 +320,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 +343,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 +357,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 +407,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| {
@ -432,28 +424,28 @@ 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
//Maybe a platform's page_size is actually the same as or
// very near usize?
if(os.page_size << 2 > @maxValue(usize)) return;
if (os.page_size << 2 > @maxValue(usize)) return;
const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
const large_align = u29(os.page_size << 2);
var align_mask: usize = undefined;
_ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
var slice = try allocator.allocFn(allocator, 500, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 100, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 10, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));

View File

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

View File

@ -42,7 +42,7 @@ test "write a file, read it, then delete it" {
assert(mem.eql(u8, contents[0.."begin".len], "begin"));
assert(mem.eql(u8, contents["begin".len..contents.len - "end".len], data));
assert(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
assert(mem.eql(u8, contents[contents.len - "end".len..], "end"));
}
try os.deleteFile(allocator, tmp_file_name);
}

View File

@ -35,7 +35,7 @@ pub const Token = struct {
};
pub fn init(id: Id, count: usize, offset: u1) Token {
return Token {
return Token{
.id = id,
.offset = offset,
.string_has_escape = false,
@ -45,7 +45,7 @@ pub const Token = struct {
}
pub fn initString(count: usize, has_unicode_escape: bool) Token {
return Token {
return Token{
.id = Id.String,
.offset = 0,
.string_has_escape = has_unicode_escape,
@ -55,7 +55,7 @@ pub const Token = struct {
}
pub fn initNumber(count: usize, number_is_integer: bool) Token {
return Token {
return Token{
.id = Id.Number,
.offset = 0,
.string_has_escape = false,
@ -66,7 +66,7 @@ pub const Token = struct {
// A marker token is a zero-length
pub fn initMarker(id: Id) Token {
return Token {
return Token{
.id = id,
.offset = 0,
.string_has_escape = false,
@ -77,7 +77,7 @@ pub const Token = struct {
// Slice into the underlying input string.
pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
return input[i + self.offset - self.count .. i + self.offset];
return input[i + self.offset - self.count..i + self.offset];
}
};
@ -86,7 +86,7 @@ pub const Token = struct {
// parsing state requires ~40-50 bytes of stack space.
//
// Conforms strictly to RFC8529.
const StreamingJsonParser = struct {
pub const StreamingJsonParser = struct {
// Current state
state: State,
// How many bytes we have counted for the current token
@ -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;
@ -252,7 +252,7 @@ const StreamingJsonParser = struct {
p.after_value_state = State.TopLevelEnd;
p.count = 0;
},
'1' ... '9' => {
'1'...'9' => {
p.number_is_integer = true;
p.state = State.NumberMaybeDigitOrDotOrExponent;
p.after_value_state = State.TopLevelEnd;
@ -324,7 +324,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 +348,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 +362,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 +376,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;
@ -386,7 +386,7 @@ const StreamingJsonParser = struct {
p.state = State.NumberMaybeDotOrExponent;
p.count = 0;
},
'1' ... '9' => {
'1'...'9' => {
p.state = State.NumberMaybeDigitOrDotOrExponent;
p.count = 0;
},
@ -428,7 +428,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 +442,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;
@ -452,7 +452,7 @@ const StreamingJsonParser = struct {
p.state = State.NumberMaybeDotOrExponent;
p.count = 0;
},
'1' ... '9' => {
'1'...'9' => {
p.state = State.NumberMaybeDigitOrDotOrExponent;
p.count = 0;
},
@ -501,7 +501,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,7 +519,7 @@ const StreamingJsonParser = struct {
p.state = State.TopLevelEnd;
}
*token = Token.initMarker(Token.Id.ObjectEnd);
token.* = Token.initMarker(Token.Id.ObjectEnd);
},
0x09, 0x0A, 0x0D, 0x20 => {
// whitespace
@ -543,7 +543,7 @@ const StreamingJsonParser = struct {
},
State.String => switch (c) {
0x00 ... 0x1F => {
0x00...0x1F => {
return error.InvalidControlCharacter;
},
'"' => {
@ -553,21 +553,21 @@ 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 => {
0xC0...0xDF => {
p.state = State.StringUtf8Byte1;
},
0xE0 ... 0xEF => {
0xE0...0xEF => {
p.state = State.StringUtf8Byte2;
},
0xF0 ... 0xFF => {
0xF0...0xFF => {
p.state = State.StringUtf8Byte3;
},
else => {
@ -613,28 +613,28 @@ 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,
@ -646,7 +646,7 @@ const StreamingJsonParser = struct {
'0' => {
p.state = State.NumberMaybeDotOrExponent;
},
'1' ... '9' => {
'1'...'9' => {
p.state = State.NumberMaybeDigitOrDotOrExponent;
},
else => {
@ -668,7 +668,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;
},
}
@ -685,12 +685,12 @@ const StreamingJsonParser = struct {
p.number_is_integer = false;
p.state = State.NumberExponent;
},
'0' ... '9' => {
'0'...'9' => {
// another digit
},
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;
},
}
@ -699,7 +699,7 @@ const StreamingJsonParser = struct {
State.NumberFractionalRequired => {
p.complete = p.after_value_state == State.TopLevelEnd;
switch (c) {
'0' ... '9' => {
'0'...'9' => {
p.state = State.NumberFractional;
},
else => {
@ -711,7 +711,7 @@ const StreamingJsonParser = struct {
State.NumberFractional => {
p.complete = p.after_value_state == State.TopLevelEnd;
switch (c) {
'0' ... '9' => {
'0'...'9' => {
// another digit
},
'e', 'E' => {
@ -720,7 +720,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;
},
}
@ -735,18 +735,18 @@ 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;
},
}
},
State.NumberExponent => switch (c) {
'-', '+', => {
'-', '+' => {
p.complete = false;
p.state = State.NumberExponentDigitsRequired;
},
'0' ... '9' => {
'0'...'9' => {
p.complete = p.after_value_state == State.TopLevelEnd;
p.state = State.NumberExponentDigits;
},
@ -756,7 +756,7 @@ const StreamingJsonParser = struct {
},
State.NumberExponentDigitsRequired => switch (c) {
'0' ... '9' => {
'0'...'9' => {
p.complete = p.after_value_state == State.TopLevelEnd;
p.state = State.NumberExponentDigits;
},
@ -768,12 +768,12 @@ const StreamingJsonParser = struct {
State.NumberExponentDigits => {
p.complete = p.after_value_state == State.TopLevelEnd;
switch (c) {
'0' ... '9' => {
'0'...'9' => {
// another digit
},
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 +793,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 +819,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 +840,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 +895,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 +950,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");
},
@ -1012,7 +1012,7 @@ pub const Value = union(enum) {
};
// A non-stream JSON parser which constructs a tree of Value's.
const JsonParser = struct {
pub const JsonParser = struct {
allocator: &Allocator,
state: State,
copy_strings: bool,
@ -1027,7 +1027,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 +1082,7 @@ const JsonParser = struct {
std.debug.assert(p.stack.len == 1);
return ValueTree {
return ValueTree{
.arena = arena,
.root = p.stack.at(0),
};
@ -1115,11 +1115,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 +1133,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 +1165,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 +1179,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 +1194,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,10 +1208,10 @@ 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);
@ -1248,15 +1248,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 +1266,21 @@ test "json parser dynamic" {
defer p.deinit();
const s =
\\{
\\ "Image": {
\\ "Width": 800,
\\ "Height": 600,
\\ "Title": "View from 15th Floor",
\\ "Thumbnail": {
\\ "Url": "http://www.example.com/image/481989943",
\\ "Height": 125,
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ }
\\}
;
\\{
\\ "Image": {
\\ "Width": 800,
\\ "Height": 600,
\\ "Title": "View from 15th Floor",
\\ "Thumbnail": {
\\ "Url": "http://www.example.com/image/481989943",
\\ "Height": 125,
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ }
\\}
;
var tree = try p.parse(s);
defer tree.deinit();

View File

@ -81,9 +81,7 @@ test "y_array_with_several_null" {
}
test "y_array_with_trailing_space" {
ok(
"[2] "
);
ok("[2] ");
}
test "y_number_0e+1" {
@ -431,15 +429,11 @@ test "y_string_two-byte-utf-8" {
}
test "y_string_u+2028_line_sep" {
ok(
\\[""]
);
ok("[\"\xe2\x80\xa8\"]");
}
test "y_string_u+2029_par_sep" {
ok(
\\[""]
);
ok("[\"\xe2\x80\xa9\"]");
}
test "y_string_uescaped_newline" {
@ -455,9 +449,7 @@ test "y_string_uEscape" {
}
test "y_string_unescaped_char_delete" {
ok(
\\[""]
);
ok("[\"\x7f\"]");
}
test "y_string_unicode_2" {
@ -527,9 +519,7 @@ test "y_string_utf8" {
}
test "y_string_with_del_character" {
ok(
\\["aa"]
);
ok("[\"a\x7fa\"]");
}
test "y_structure_lonely_false" {
@ -587,9 +577,7 @@ test "y_structure_true_in_array" {
}
test "y_structure_whitespace_array" {
ok(
" [] "
);
ok(" [] ");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -704,7 +692,6 @@ test "n_array_newlines_unclosed" {
);
}
test "n_array_number_and_comma" {
err(
\\[1,]
@ -718,9 +705,7 @@ test "n_array_number_and_several_commas" {
}
test "n_array_spaces_vertical_tab_formfeed" {
err(
\\[" a"\f]
);
err("[\"\x0aa\"\\f]");
}
test "n_array_star_inside" {
@ -774,9 +759,7 @@ test "n_incomplete_true" {
}
test "n_multidigit_number_then_00" {
err(
\\123
);
err("123\x00");
}
test "n_number_0.1.2" {
@ -983,7 +966,6 @@ test "n_number_invalid-utf-8-in-int" {
);
}
test "n_number_++" {
err(
\\[++1234]
@ -1240,7 +1222,7 @@ test "n_object_unterminated-value" {
err(
\\{"a":"a
);
}
}
test "n_object_with_single_string" {
err(
@ -1255,9 +1237,7 @@ test "n_object_with_trailing_garbage" {
}
test "n_single_space" {
err(
" "
);
err(" ");
}
test "n_string_1_surrogate_then_escape" {
@ -1291,9 +1271,7 @@ test "n_string_accentuated_char_no_quotes" {
}
test "n_string_backslash_00" {
err(
\\["\"]
);
err("[\"\x00\"]");
}
test "n_string_escaped_backslash_bad" {
@ -1303,15 +1281,11 @@ test "n_string_escaped_backslash_bad" {
}
test "n_string_escaped_ctrl_char_tab" {
err(
\\["\ "]
);
err("\x5b\x22\x5c\x09\x22\x5d");
}
test "n_string_escaped_emoji" {
err(
\\["\🌀"]
);
err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]");
}
test "n_string_escape_x" {
@ -1357,9 +1331,7 @@ test "n_string_invalid_unicode_escape" {
}
test "n_string_invalid_utf8_after_escape" {
err(
\\["\å"]
);
err("[\"\\\x75\xc3\xa5\"]");
}
test "n_string_invalid-utf-8-in-escape" {
@ -1405,9 +1377,7 @@ test "n_string_start_escape_unclosed" {
}
test "n_string_unescaped_crtl_char" {
err(
\\["aa"]
);
err("[\"a\x00a\"]");
}
test "n_string_unescaped_newline" {
@ -1418,9 +1388,7 @@ test "n_string_unescaped_newline" {
}
test "n_string_unescaped_tab" {
err(
\\[" "]
);
err("[\"\t\"]");
}
test "n_string_unicode_CapitalU" {
@ -1436,9 +1404,7 @@ test "n_string_with_trailing_garbage" {
}
test "n_structure_100000_opening_arrays" {
err(
"[" ** 100000
);
err("[" ** 100000);
}
test "n_structure_angle_bracket_." {
@ -1532,9 +1498,7 @@ test "n_structure_no_data" {
}
test "n_structure_null-byte-outside-string" {
err(
\\[]
);
err("[\x00]");
}
test "n_structure_number_with_trailing_garbage" {
@ -1580,9 +1544,7 @@ test "n_structure_open_array_comma" {
}
test "n_structure_open_array_object" {
err(
"[{\"\":" ** 50000
);
err("[{\"\":" ** 50000);
}
test "n_structure_open_array_open_object" {
@ -1718,9 +1680,7 @@ test "n_structure_UTF8_BOM_no_data" {
}
test "n_structure_whitespace_formfeed" {
err(
\\[ ]
);
err("[\x0c]");
}
test "n_structure_whitespace_U+2060_word_joiner" {
@ -1900,21 +1860,15 @@ test "i_string_truncated-utf-8" {
}
test "i_string_utf16BE_no_BOM" {
any(
\\["é"]
);
any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d");
}
test "i_string_utf16LE_no_BOM" {
any(
\\["é"]
);
any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
}
test "i_string_UTF-16LE_with_BOM" {
any(
\\ÿþ["é"]
);
any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
}
test "i_string_UTF-8_invalid_sequence" {
@ -1930,9 +1884,7 @@ test "i_string_UTF8_surrogate_U+D800" {
}
test "i_structure_500_nested_arrays" {
any(
("[" ** 500) ++ ("]" ** 500)
);
any(("[" ** 500) ++ ("]" ** 500));
}
test "i_structure_UTF-8_BOM_empty_object" {

View File

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

View File

@ -58,15 +58,15 @@ pub const SymbolTable = struct {
// code, its displacement is different.
pub fn deinit(self: &SymbolTable) void {
self.allocator.free(self.symbols);
self.symbols = []const Symbol {};
self.symbols = []const Symbol{};
self.allocator.free(self.strings);
self.strings = []const u8 {};
self.strings = []const u8{};
}
pub fn search(self: &const SymbolTable, address: usize) ?&const Symbol {
var min: usize = 0;
var max: usize = self.symbols.len - 1; // Exclude sentinel.
var max: usize = self.symbols.len - 1; // Exclude sentinel.
while (min < max) {
const mid = min + (max - min) / 2;
const curr = &self.symbols[mid];
@ -118,10 +118,11 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
try in.stream.readNoEof(strings);
var nsyms: usize = 0;
for (syms) |sym| if (isSymbol(sym)) nsyms += 1;
for (syms) |sym|
if (isSymbol(sym)) nsyms += 1;
if (nsyms == 0) return error.MissingDebugInfo;
var symbols = try allocator.alloc(Symbol, nsyms + 1); // Room for sentinel.
var symbols = try allocator.alloc(Symbol, nsyms + 1); // Room for sentinel.
errdefer allocator.free(symbols);
var pie_slide: usize = 0;
@ -132,7 +133,7 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
const end = ??mem.indexOfScalarPos(u8, strings, start, 0);
const name = strings[start..end];
const address = sym.n_value;
symbols[nsym] = Symbol { .name = name, .address = address };
symbols[nsym] = Symbol{ .name = name, .address = address };
nsym += 1;
if (is_pie and mem.eql(u8, name, "_SymbolTable_deinit")) {
pie_slide = @ptrToInt(SymbolTable.deinit) - address;
@ -145,13 +146,14 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
// Insert the sentinel. Since we don't know where the last function ends,
// we arbitrarily limit it to the start address + 4 KB.
const top = symbols[nsyms - 1].address + 4096;
symbols[nsyms] = Symbol { .name = "", .address = top };
symbols[nsyms] = Symbol{ .name = "", .address = top };
if (pie_slide != 0) {
for (symbols) |*symbol| symbol.address += pie_slide;
for (symbols) |*symbol|
symbol.address += pie_slide;
}
return SymbolTable {
return SymbolTable{
.allocator = allocator,
.symbols = symbols,
.strings = strings,

View File

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

View File

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

View File

@ -17,25 +17,25 @@ pub fn atan(x: var) @typeOf(x) {
}
fn atan32(x_: f32) f32 {
const atanhi = []const f32 {
const atanhi = []const f32{
4.6364760399e-01, // atan(0.5)hi
7.8539812565e-01, // atan(1.0)hi
9.8279368877e-01, // atan(1.5)hi
1.5707962513e+00, // atan(inf)hi
};
const atanlo = []const f32 {
const atanlo = []const f32{
5.0121582440e-09, // atan(0.5)lo
3.7748947079e-08, // atan(1.0)lo
3.4473217170e-08, // atan(1.5)lo
7.5497894159e-08, // atan(inf)lo
};
const aT = []const f32 {
const aT = []const f32{
3.3333328366e-01,
-1.9999158382e-01,
-1.9999158382e-01,
1.4253635705e-01,
-1.0648017377e-01,
-1.0648017377e-01,
6.1687607318e-02,
};
@ -80,8 +80,7 @@ fn atan32(x_: f32) f32 {
id = 1;
x = (x - 1.0) / (x + 1.0);
}
}
else {
} else {
// |x| < 2.4375
if (ix < 0x401C0000) {
id = 2;
@ -109,31 +108,31 @@ fn atan32(x_: f32) f32 {
}
fn atan64(x_: f64) f64 {
const atanhi = []const f64 {
const atanhi = []const f64{
4.63647609000806093515e-01, // atan(0.5)hi
7.85398163397448278999e-01, // atan(1.0)hi
9.82793723247329054082e-01, // atan(1.5)hi
1.57079632679489655800e+00, // atan(inf)hi
};
const atanlo = []const f64 {
const atanlo = []const f64{
2.26987774529616870924e-17, // atan(0.5)lo
3.06161699786838301793e-17, // atan(1.0)lo
1.39033110312309984516e-17, // atan(1.5)lo
6.12323399573676603587e-17, // atan(inf)lo
};
const aT = []const f64 {
const aT = []const f64{
3.33333333333329318027e-01,
-1.99999999998764832476e-01,
-1.99999999998764832476e-01,
1.42857142725034663711e-01,
-1.11111104054623557880e-01,
-1.11111104054623557880e-01,
9.09088713343650656196e-02,
-7.69187620504482999495e-02,
-7.69187620504482999495e-02,
6.66107313738753120669e-02,
-5.83357013379057348645e-02,
-5.83357013379057348645e-02,
4.97687799461593236017e-02,
-3.65315727442169155270e-02,
-3.65315727442169155270e-02,
1.62858201153657823623e-02,
};
@ -179,8 +178,7 @@ fn atan64(x_: f64) f64 {
id = 1;
x = (x - 1.0) / (x + 1.0);
}
}
else {
} else {
// |x| < 2.4375
if (ix < 0x40038000) {
id = 2;

View File

@ -31,7 +31,7 @@ pub fn atan2(comptime T: type, x: T, y: T) T {
}
fn atan2_32(y: f32, x: f32) f32 {
const pi: f32 = 3.1415927410e+00;
const pi: f32 = 3.1415927410e+00;
const pi_lo: f32 = -8.7422776573e-08;
if (math.isNan(x) or math.isNan(y)) {
@ -53,9 +53,9 @@ 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 +71,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 +107,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 +143,9 @@ 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 +161,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 +197,10 @@ fn atan2_64(y: f64, x: f64) f64 {
};
switch (m) {
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
0 => return z, // atan(+, +)
1 => return -z, // atan(-, +)
2 => return pi - (z - pi_lo), // atan(+, -)
3 => return (z - pi_lo) - pi, // atan(-, -)
else => unreachable,
}
}

View File

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

View File

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

View File

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

View File

@ -31,28 +31,28 @@ pub fn Complex(comptime T: type) type {
im: T,
pub fn new(re: T, im: T) Self {
return Self {
return Self{
.re = re,
.im = im,
};
}
pub fn add(self: &const Self, other: &const Self) Self {
return Self {
return Self{
.re = self.re + other.re,
.im = self.im + other.im,
};
}
pub fn sub(self: &const Self, other: &const Self) Self {
return Self {
return Self{
.re = self.re - other.re,
.im = self.im - other.im,
};
}
pub fn mul(self: &const Self, other: &const Self) Self {
return Self {
return Self{
.re = self.re * other.re - self.im * other.im,
.im = self.im * other.re + self.re * other.im,
};
@ -63,14 +63,14 @@ pub fn Complex(comptime T: type) type {
const im_num = self.im * other.re - self.re * other.im;
const den = other.re * other.re + other.im * other.im;
return Self {
return Self{
.re = re_num / den,
.im = im_num / den,
};
}
pub fn conjugate(self: &const Self) Self {
return Self {
return Self{
.re = self.re,
.im = -self.im,
};
@ -78,7 +78,7 @@ pub fn Complex(comptime T: type) type {
pub fn reciprocal(self: &const Self) Self {
const m = self.re * self.re + self.im * self.im;
return Self {
return Self{
.re = self.re / m,
.im = -self.im / m,
};
@ -121,8 +121,8 @@ test "complex.div" {
const b = Complex(f32).new(2, 7);
const c = a.div(b);
debug.assert(math.approxEq(f32, c.re, f32(31)/53, epsilon) and
math.approxEq(f32, c.im, f32(-29)/53, epsilon));
debug.assert(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
}
test "complex.conjugate" {
@ -136,8 +136,8 @@ test "complex.reciprocal" {
const a = Complex(f32).new(5, 3);
const c = a.reciprocal();
debug.assert(math.approxEq(f32, c.re, f32(5)/34, epsilon) and
math.approxEq(f32, c.im, f32(-3)/34, epsilon));
debug.assert(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
}
test "complex.magnitude" {

View File

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

View File

@ -98,7 +98,7 @@ test "complex.ctanh32" {
const a = Complex(f32).new(5, 3);
const c = tanh(a);
debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon));
debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon));
debug.assert(math.approxEq(f32, c.im, -0.000025, epsilon));
}
@ -106,6 +106,6 @@ test "complex.ctanh64" {
const a = Complex(f64).new(5, 3);
const c = tanh(a);
debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon));
debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon));
debug.assert(math.approxEq(f64, c.im, -0.000025, epsilon));
}

View File

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

View File

@ -20,10 +20,10 @@ pub fn exp(x: var) @typeOf(x) {
fn exp32(x_: f32) f32 {
@setFloatMode(this, builtin.FloatMode.Strict);
const half = []f32 { 0.5, -0.5 };
const half = []f32{ 0.5, -0.5 };
const ln2hi = 6.9314575195e-1;
const ln2lo = 1.4286067653e-6;
const invln2 = 1.4426950216e+0;
const invln2 = 1.4426950216e+0;
const P1 = 1.6666625440e-1;
const P2 = -2.7667332906e-3;
@ -47,7 +47,7 @@ fn exp32(x_: f32) f32 {
return x * 0x1.0p127;
}
if (sign != 0) {
math.forceEval(-0x1.0p-149 / x); // overflow
math.forceEval(-0x1.0p-149 / x); // overflow
// x <= -103.972084
if (hx >= 0x42CFF1B5) {
return 0;
@ -64,8 +64,7 @@ fn exp32(x_: f32) f32 {
// |x| > 1.5 * ln2
if (hx > 0x3F851592) {
k = i32(invln2 * x + half[usize(sign)]);
}
else {
} else {
k = 1 - sign - sign;
}
@ -79,8 +78,7 @@ fn exp32(x_: f32) f32 {
k = 0;
hi = x;
lo = 0;
}
else {
} else {
math.forceEval(0x1.0p127 + x); // inexact
return 1 + x;
}
@ -99,15 +97,15 @@ fn exp32(x_: f32) f32 {
fn exp64(x_: f64) f64 {
@setFloatMode(this, builtin.FloatMode.Strict);
const half = []const f64 { 0.5, -0.5 };
const half = []const f64{ 0.5, -0.5 };
const ln2hi: f64 = 6.93147180369123816490e-01;
const ln2lo: f64 = 1.90821492927058770002e-10;
const invln2: f64 = 1.44269504088896338700e+00;
const P1: f64 = 1.66666666666666019037e-01;
const P2: f64 = -2.77777777770155933842e-03;
const P3: f64 = 6.61375632143793436117e-05;
const P4: f64 = -1.65339022054652515390e-06;
const P5: f64 = 4.13813679705723846039e-08;
const P1: f64 = 1.66666666666666019037e-01;
const P2: f64 = -2.77777777770155933842e-03;
const P3: f64 = 6.61375632143793436117e-05;
const P4: f64 = -1.65339022054652515390e-06;
const P5: f64 = 4.13813679705723846039e-08;
var x = x_;
var ux = @bitCast(u64, x);
@ -151,8 +149,7 @@ fn exp64(x_: f64) f64 {
// |x| >= 1.5 * ln2
if (hx > 0x3FF0A2B2) {
k = i32(invln2 * x + half[usize(sign)]);
}
else {
} else {
k = 1 - sign - sign;
}
@ -166,8 +163,7 @@ fn exp64(x_: f64) f64 {
k = 0;
hi = x;
lo = 0;
}
else {
} else {
// inexact if x != 0
// math.forceEval(0x1.0p1023 + x);
return 1 + x;

View File

@ -16,7 +16,7 @@ pub fn exp2(x: var) @typeOf(x) {
};
}
const exp2ft = []const f64 {
const exp2ft = []const f64{
0x1.6a09e667f3bcdp-1,
0x1.7a11473eb0187p-1,
0x1.8ace5422aa0dbp-1,
@ -92,195 +92,195 @@ fn exp2_32(x: f32) f32 {
return f32(r * uk);
}
const exp2dt = []f64 {
const exp2dt = []f64{
// exp2(z + eps) eps
0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
0x1.6b052fa751744p-1, 0x1.8000p-50,
0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
0x1.6b052fa751744p-1, 0x1.8000p-50,
0x1.6c012750bd9fep-1, -0x1.8780p-45,
0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
0x1.6dfb23c651a29p-1, -0x1.8000p-50,
0x1.6ef9298593ae3p-1, -0x1.c000p-52,
0x1.6ff7df9519386p-1, -0x1.fd80p-45,
0x1.70f7466f42da3p-1, -0x1.c880p-45,
0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
0x1.72f8286eacf05p-1, -0x1.8300p-44,
0x1.73f9a48a58152p-1, -0x1.0c00p-47,
0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
0x1.75feb564267f1p-1, 0x1.3e00p-47,
0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
0x1.75feb564267f1p-1, 0x1.3e00p-47,
0x1.77024b1ab6d48p-1, -0x1.7d00p-45,
0x1.780694fde5d38p-1, -0x1.d000p-50,
0x1.790b938ac1d00p-1, 0x1.3000p-49,
0x1.790b938ac1d00p-1, 0x1.3000p-49,
0x1.7a11473eb0178p-1, -0x1.d000p-49,
0x1.7b17b0976d060p-1, 0x1.0400p-45,
0x1.7c1ed0130c133p-1, 0x1.0000p-53,
0x1.7b17b0976d060p-1, 0x1.0400p-45,
0x1.7c1ed0130c133p-1, 0x1.0000p-53,
0x1.7d26a62ff8636p-1, -0x1.6900p-45,
0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47,
0x1.7f3878491c3e8p-1, -0x1.4580p-45,
0x1.80427543e1b4ep-1, 0x1.3000p-44,
0x1.814d2add1071ap-1, 0x1.f000p-47,
0x1.80427543e1b4ep-1, 0x1.3000p-44,
0x1.814d2add1071ap-1, 0x1.f000p-47,
0x1.82589994ccd7ep-1, -0x1.1c00p-45,
0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
0x1.8471a4623cab5p-1, 0x1.7100p-43,
0x1.857f4179f5bbcp-1, 0x1.2600p-45,
0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
0x1.8471a4623cab5p-1, 0x1.7100p-43,
0x1.857f4179f5bbcp-1, 0x1.2600p-45,
0x1.868d99b4491afp-1, -0x1.2c40p-44,
0x1.879cad931a395p-1, -0x1.3000p-45,
0x1.88ac7d98a65b8p-1, -0x1.a800p-45,
0x1.89bd0a4785800p-1, -0x1.d000p-49,
0x1.8ace5422aa223p-1, 0x1.3280p-44,
0x1.8be05bad619fap-1, 0x1.2b40p-43,
0x1.8ace5422aa223p-1, 0x1.3280p-44,
0x1.8be05bad619fap-1, 0x1.2b40p-43,
0x1.8cf3216b54383p-1, -0x1.ed00p-45,
0x1.8e06a5e08664cp-1, -0x1.0500p-45,
0x1.8f1ae99157807p-1, 0x1.8280p-45,
0x1.8f1ae99157807p-1, 0x1.8280p-45,
0x1.902fed0282c0ep-1, -0x1.cb00p-46,
0x1.9145b0b91ff96p-1, -0x1.5e00p-47,
0x1.925c353aa2ff9p-1, 0x1.5400p-48,
0x1.93737b0cdc64ap-1, 0x1.7200p-46,
0x1.925c353aa2ff9p-1, 0x1.5400p-48,
0x1.93737b0cdc64ap-1, 0x1.7200p-46,
0x1.948b82b5f98aep-1, -0x1.9000p-47,
0x1.95a44cbc852cbp-1, 0x1.5680p-45,
0x1.95a44cbc852cbp-1, 0x1.5680p-45,
0x1.96bdd9a766f21p-1, -0x1.6d00p-44,
0x1.97d829fde4e2ap-1, -0x1.1000p-47,
0x1.98f33e47a23a3p-1, 0x1.d000p-45,
0x1.98f33e47a23a3p-1, 0x1.d000p-45,
0x1.9a0f170ca0604p-1, -0x1.8a40p-44,
0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
0x1.9d674194bb8c5p-1, -0x1.c000p-49,
0x1.9e86319e3238ep-1, 0x1.7d00p-46,
0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
0x1.9e86319e3238ep-1, 0x1.7d00p-46,
0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
0x1.a0c667b5de54dp-1, -0x1.5000p-48,
0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
0x1.a42c980460a5dp-1, -0x1.af00p-46,
0x1.a5503b23e259bp-1, 0x1.b600p-47,
0x1.a674a8af46213p-1, 0x1.8880p-44,
0x1.a799e1330b3a7p-1, 0x1.1200p-46,
0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
0x1.a5503b23e259bp-1, 0x1.b600p-47,
0x1.a674a8af46213p-1, 0x1.8880p-44,
0x1.a799e1330b3a7p-1, 0x1.1200p-46,
0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45,
0x1.ab0e521356fb8p-1, 0x1.b700p-45,
0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
0x1.ab0e521356fb8p-1, 0x1.b700p-45,
0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
0x1.ae89f995ad2a3p-1, -0x1.c900p-45,
0x1.afb4ce622f367p-1, 0x1.6500p-46,
0x1.b0e07298db790p-1, 0x1.fd40p-45,
0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
0x1.afb4ce622f367p-1, 0x1.6500p-46,
0x1.b0e07298db790p-1, 0x1.fd40p-45,
0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
0x1.b468415b747e7p-1, -0x1.8380p-44,
0x1.b59728de5593ap-1, 0x1.8000p-54,
0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
0x1.b59728de5593ap-1, 0x1.8000p-54,
0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
0x1.b928cf22749b2p-1, -0x1.4c00p-47,
0x1.ba5b030a10603p-1, -0x1.d700p-47,
0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
0x1.bdf69c3f3a16fp-1, -0x1.f780p-46,
0x1.bf2c25bd71db8p-1, -0x1.0a00p-46,
0x1.c06286141b2e9p-1, -0x1.1400p-46,
0x1.c199bdd8552e0p-1, 0x1.be00p-47,
0x1.c199bdd8552e0p-1, 0x1.be00p-47,
0x1.c2d1cd9fa64eep-1, -0x1.9400p-47,
0x1.c40ab5fffd02fp-1, -0x1.ed00p-47,
0x1.c544778fafd15p-1, 0x1.9660p-44,
0x1.c544778fafd15p-1, 0x1.9660p-44,
0x1.c67f12e57d0cbp-1, -0x1.a100p-46,
0x1.c7ba88988c1b6p-1, -0x1.8458p-42,
0x1.c8f6d9406e733p-1, -0x1.a480p-46,
0x1.ca3405751c4dfp-1, 0x1.b000p-51,
0x1.cb720dcef9094p-1, 0x1.1400p-47,
0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
0x1.cdf0b555dc412p-1, 0x1.3600p-48,
0x1.ca3405751c4dfp-1, 0x1.b000p-51,
0x1.cb720dcef9094p-1, 0x1.1400p-47,
0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
0x1.cdf0b555dc412p-1, 0x1.3600p-48,
0x1.cf3155b5bab3bp-1, -0x1.6900p-47,
0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
0x1.d1b532b08c8fap-1, -0x1.5e00p-46,
0x1.d2f87080d8a85p-1, 0x1.d280p-46,
0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
0x1.d5818dcfba491p-1, 0x1.f000p-50,
0x1.d2f87080d8a85p-1, 0x1.d280p-46,
0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
0x1.d5818dcfba491p-1, 0x1.f000p-50,
0x1.d6c76e862e6a1p-1, -0x1.3a00p-47,
0x1.d80e316c9834ep-1, -0x1.cd80p-47,
0x1.d955d71ff6090p-1, 0x1.4c00p-48,
0x1.da9e603db32aep-1, 0x1.f900p-48,
0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
0x1.d955d71ff6090p-1, 0x1.4c00p-48,
0x1.da9e603db32aep-1, 0x1.f900p-48,
0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
0x1.dd321f301b445p-1, -0x1.5200p-48,
0x1.de7d5641c05bfp-1, -0x1.d700p-46,
0x1.dfc97337b9aecp-1, -0x1.6140p-46,
0x1.e11676b197d5ep-1, 0x1.b480p-47,
0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
0x1.e11676b197d5ep-1, 0x1.b480p-47,
0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
0x1.e502ee78b3fb4p-1, -0x1.9300p-47,
0x1.e653924676d68p-1, -0x1.5000p-49,
0x1.e7a51fbc74c44p-1, -0x1.7f80p-47,
0x1.e8f7977cdb726p-1, -0x1.3700p-48,
0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
0x1.ecf482d8e680dp-1, 0x1.5500p-48,
0x1.ee4aaa2188514p-1, 0x1.6400p-51,
0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
0x1.ecf482d8e680dp-1, 0x1.5500p-48,
0x1.ee4aaa2188514p-1, 0x1.6400p-51,
0x1.efa1bee615a13p-1, -0x1.e800p-49,
0x1.f0f9c1cb64106p-1, -0x1.a880p-48,
0x1.f252b376bb963p-1, -0x1.c900p-45,
0x1.f3ac948dd7275p-1, 0x1.a000p-53,
0x1.f3ac948dd7275p-1, 0x1.a000p-53,
0x1.f50765b6e4524p-1, -0x1.4f00p-48,
0x1.f6632798844fdp-1, 0x1.a800p-51,
0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
0x1.f6632798844fdp-1, 0x1.a800p-51,
0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
0x1.f91d802243c82p-1, -0x1.4600p-50,
0x1.fa7c1819e908ep-1, -0x1.b0c0p-47,
0x1.fbdba3692d511p-1, -0x1.0e00p-51,
0x1.fd3c22b8f7194p-1, -0x1.0de8p-46,
0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
0x1.0000000000000p+0, 0x0.0000p+0,
0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
0x1.0000000000000p+0, 0x0.0000p+0,
0x1.00b1afa5abcbep+0, -0x1.3400p-52,
0x1.0163da9fb3303p+0, -0x1.2170p-46,
0x1.02168143b0282p+0, 0x1.a400p-52,
0x1.02c9a3e77806cp+0, 0x1.f980p-49,
0x1.02168143b0282p+0, 0x1.a400p-52,
0x1.02c9a3e77806cp+0, 0x1.f980p-49,
0x1.037d42e11bbcap+0, -0x1.7400p-51,
0x1.04315e86e7f89p+0, 0x1.8300p-50,
0x1.04315e86e7f89p+0, 0x1.8300p-50,
0x1.04e5f72f65467p+0, -0x1.a3f0p-46,
0x1.059b0d315855ap+0, -0x1.2840p-47,
0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
0x1.0706b29ddf71ap+0, 0x1.5240p-46,
0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
0x1.0706b29ddf71ap+0, 0x1.5240p-46,
0x1.07bd42b72a82dp+0, -0x1.9a00p-49,
0x1.0874518759bd0p+0, 0x1.6400p-49,
0x1.0874518759bd0p+0, 0x1.6400p-49,
0x1.092bdf66607c8p+0, -0x1.0780p-47,
0x1.09e3ecac6f383p+0, -0x1.8000p-54,
0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
0x1.0b5586cf988fcp+0, -0x1.ac80p-48,
0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
0x1.0cc922b724816p+0, 0x1.5200p-47,
0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
0x1.0cc922b724816p+0, 0x1.5200p-47,
0x1.0d83b23395dd8p+0, -0x1.ad00p-48,
0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47,
0x1.0fb66affed2f0p+0, -0x1.d300p-47,
0x1.1073028d7234bp+0, 0x1.1500p-48,
0x1.11301d0125b5bp+0, 0x1.c000p-49,
0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
0x1.12abdc06c31d5p+0, 0x1.8400p-49,
0x1.1073028d7234bp+0, 0x1.1500p-48,
0x1.11301d0125b5bp+0, 0x1.c000p-49,
0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
0x1.12abdc06c31d5p+0, 0x1.8400p-49,
0x1.136a814f2047dp+0, -0x1.ed00p-47,
0x1.1429aaea92de9p+0, 0x1.8e00p-49,
0x1.14e95934f3138p+0, 0x1.b400p-49,
0x1.15a98c8a58e71p+0, 0x1.5300p-47,
0x1.166a45471c3dfp+0, 0x1.3380p-47,
0x1.172b83c7d5211p+0, 0x1.8d40p-45,
0x1.1429aaea92de9p+0, 0x1.8e00p-49,
0x1.14e95934f3138p+0, 0x1.b400p-49,
0x1.15a98c8a58e71p+0, 0x1.5300p-47,
0x1.166a45471c3dfp+0, 0x1.3380p-47,
0x1.172b83c7d5211p+0, 0x1.8d40p-45,
0x1.17ed48695bb9fp+0, -0x1.5d00p-47,
0x1.18af9388c8d93p+0, -0x1.c880p-46,
0x1.1972658375d66p+0, 0x1.1f00p-46,
0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
0x1.1972658375d66p+0, 0x1.1f00p-46,
0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
0x1.1af99f81387e3p+0, -0x1.7390p-43,
0x1.1bbe084045d54p+0, 0x1.4e40p-45,
0x1.1bbe084045d54p+0, 0x1.4e40p-45,
0x1.1c82f95281c43p+0, -0x1.a200p-47,
0x1.1d4873168b9b2p+0, 0x1.3800p-49,
0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
0x1.1ed5022fcd938p+0, 0x1.1900p-47,
0x1.1d4873168b9b2p+0, 0x1.3800p-49,
0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
0x1.1ed5022fcd938p+0, 0x1.1900p-47,
0x1.1f9c18438cdf7p+0, -0x1.b780p-46,
0x1.2063b88628d8fp+0, 0x1.d940p-45,
0x1.212be3578a81ep+0, 0x1.8000p-50,
0x1.21f49917ddd41p+0, 0x1.b340p-45,
0x1.22bdda2791323p+0, 0x1.9f80p-46,
0x1.2063b88628d8fp+0, 0x1.d940p-45,
0x1.212be3578a81ep+0, 0x1.8000p-50,
0x1.21f49917ddd41p+0, 0x1.b340p-45,
0x1.22bdda2791323p+0, 0x1.9f80p-46,
0x1.2387a6e7561e7p+0, -0x1.9c80p-46,
0x1.2451ffb821427p+0, 0x1.2300p-47,
0x1.2451ffb821427p+0, 0x1.2300p-47,
0x1.251ce4fb2a602p+0, -0x1.3480p-46,
0x1.25e85711eceb0p+0, 0x1.2700p-46,
0x1.26b4565e27d16p+0, 0x1.1d00p-46,
0x1.2780e341de00fp+0, 0x1.1ee0p-44,
0x1.25e85711eceb0p+0, 0x1.2700p-46,
0x1.26b4565e27d16p+0, 0x1.1d00p-46,
0x1.2780e341de00fp+0, 0x1.1ee0p-44,
0x1.284dfe1f5633ep+0, -0x1.4c00p-46,
0x1.291ba7591bb30p+0, -0x1.3d80p-46,
0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45,
0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
0x1.2c57e39771af9p+0, -0x1.0800p-46,
0x1.2d285a6e402d9p+0, -0x1.ed00p-47,
0x1.2df961f641579p+0, -0x1.4200p-48,
@ -290,78 +290,78 @@ const exp2dt = []f64 {
0x1.31432edeea50bp+0, -0x1.0df8p-40,
0x1.32170fc4cd7b8p+0, -0x1.2480p-45,
0x1.32eb83ba8e9a2p+0, -0x1.5980p-45,
0x1.33c08b2641766p+0, 0x1.ed00p-46,
0x1.33c08b2641766p+0, 0x1.ed00p-46,
0x1.3496266e3fa27p+0, -0x1.c000p-50,
0x1.356c55f929f0fp+0, -0x1.0d80p-44,
0x1.36431a2de88b9p+0, 0x1.2c80p-45,
0x1.371a7373aaa39p+0, 0x1.0600p-45,
0x1.36431a2de88b9p+0, 0x1.2c80p-45,
0x1.371a7373aaa39p+0, 0x1.0600p-45,
0x1.37f26231e74fep+0, -0x1.6600p-46,
0x1.38cae6d05d838p+0, -0x1.ae00p-47,
0x1.39a401b713ec3p+0, -0x1.4720p-43,
0x1.3a7db34e5a020p+0, 0x1.8200p-47,
0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
0x1.3a7db34e5a020p+0, 0x1.8200p-47,
0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
0x1.3d0e544ede122p+0, -0x1.7a00p-46,
0x1.3dea64c1234bbp+0, 0x1.6300p-45,
0x1.3dea64c1234bbp+0, 0x1.6300p-45,
0x1.3ec70df1c4eccp+0, -0x1.8a60p-43,
0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44,
0x1.40822c367a0bbp+0, 0x1.5b80p-45,
0x1.4160a21f72e95p+0, 0x1.ec00p-46,
0x1.40822c367a0bbp+0, 0x1.5b80p-45,
0x1.4160a21f72e95p+0, 0x1.ec00p-46,
0x1.423fb27094646p+0, -0x1.3600p-46,
0x1.431f5d950a920p+0, 0x1.3980p-45,
0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
0x1.431f5d950a920p+0, 0x1.3980p-45,
0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
0x1.44e0860618919p+0, -0x1.6c00p-48,
0x1.45c2042a7d201p+0, -0x1.bc00p-47,
0x1.46a41ed1d0016p+0, -0x1.2800p-46,
0x1.4786d668b3326p+0, 0x1.0e00p-44,
0x1.4786d668b3326p+0, 0x1.0e00p-44,
0x1.486a2b5c13c00p+0, -0x1.d400p-45,
0x1.494e1e192af04p+0, 0x1.c200p-47,
0x1.494e1e192af04p+0, 0x1.c200p-47,
0x1.4a32af0d7d372p+0, -0x1.e500p-46,
0x1.4b17dea6db801p+0, 0x1.7800p-47,
0x1.4b17dea6db801p+0, 0x1.7800p-47,
0x1.4bfdad53629e1p+0, -0x1.3800p-46,
0x1.4ce41b817c132p+0, 0x1.0800p-47,
0x1.4dcb299fddddbp+0, 0x1.c700p-45,
0x1.4ce41b817c132p+0, 0x1.0800p-47,
0x1.4dcb299fddddbp+0, 0x1.c700p-45,
0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46,
0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
0x1.508417f4531c1p+0, -0x1.8c00p-47,
0x1.516daa2cf662ap+0, -0x1.a000p-48,
0x1.5257de83f51eap+0, 0x1.a080p-43,
0x1.5257de83f51eap+0, 0x1.a080p-43,
0x1.5342b569d4edap+0, -0x1.6d80p-45,
0x1.542e2f4f6ac1ap+0, -0x1.2440p-44,
0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
0x1.56070dde9116bp+0, 0x1.4b00p-45,
0x1.56f4736b529dep+0, 0x1.15a0p-43,
0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
0x1.56070dde9116bp+0, 0x1.4b00p-45,
0x1.56f4736b529dep+0, 0x1.15a0p-43,
0x1.57e27dbe2c40ep+0, -0x1.9e00p-45,
0x1.58d12d497c76fp+0, -0x1.3080p-45,
0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
0x1.5ab07dd485427p+0, -0x1.4000p-51,
0x1.5ba11fba87af4p+0, 0x1.0080p-44,
0x1.5ba11fba87af4p+0, 0x1.0080p-44,
0x1.5c9268a59460bp+0, -0x1.6c80p-45,
0x1.5d84590998e3fp+0, 0x1.69a0p-43,
0x1.5d84590998e3fp+0, 0x1.69a0p-43,
0x1.5e76f15ad20e1p+0, -0x1.b400p-46,
0x1.5f6a320dcebcap+0, 0x1.7700p-46,
0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
0x1.6152ae6cdf715p+0, 0x1.1000p-47,
0x1.5f6a320dcebcap+0, 0x1.7700p-46,
0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
0x1.6152ae6cdf715p+0, 0x1.1000p-47,
0x1.6247eb03a5531p+0, -0x1.5d00p-46,
0x1.633dd1d1929b5p+0, -0x1.2d00p-46,
0x1.6434634ccc313p+0, -0x1.a800p-49,
0x1.652b9febc8efap+0, -0x1.8600p-45,
0x1.6623882553397p+0, 0x1.1fe0p-40,
0x1.6623882553397p+0, 0x1.1fe0p-40,
0x1.671c1c708328ep+0, -0x1.7200p-44,
0x1.68155d44ca97ep+0, 0x1.6800p-49,
0x1.68155d44ca97ep+0, 0x1.6800p-49,
0x1.690f4b19e9471p+0, -0x1.9780p-45,
};
fn exp2_64(x: f64) f64 {
@setFloatMode(this, @import("builtin").FloatMode.Strict);
const tblsiz = u32(exp2dt.len / 2);
const tblsiz = u32(exp2dt.len / 2);
const redux: f64 = 0x1.8p52 / f64(tblsiz);
const P1: f64 = 0x1.62e42fefa39efp-1;
const P2: f64 = 0x1.ebfbdff82c575p-3;
const P3: f64 = 0x1.c6b08d704a0a6p-5;
const P4: f64 = 0x1.3b2ab88f70400p-7;
const P5: f64 = 0x1.5d88003875c74p-10;
const P1: f64 = 0x1.62e42fefa39efp-1;
const P2: f64 = 0x1.ebfbdff82c575p-3;
const P3: f64 = 0x1.c6b08d704a0a6p-5;
const P4: f64 = 0x1.3b2ab88f70400p-7;
const P5: f64 = 0x1.5d88003875c74p-10;
const ux = @bitCast(u64, x);
const ix = u32(ux >> 32) & 0x7FFFFFFF;

View File

@ -21,11 +21,11 @@ pub fn expm1(x: var) @typeOf(x) {
fn expm1_32(x_: f32) f32 {
@setFloatMode(this, builtin.FloatMode.Strict);
const o_threshold: f32 = 8.8721679688e+01;
const ln2_hi: f32 = 6.9313812256e-01;
const ln2_lo: f32 = 9.0580006145e-06;
const invln2: f32 = 1.4426950216e+00;
const ln2_hi: f32 = 6.9313812256e-01;
const ln2_lo: f32 = 9.0580006145e-06;
const invln2: f32 = 1.4426950216e+00;
const Q1: f32 = -3.3333212137e-2;
const Q2: f32 = 1.5807170421e-3;
const Q2: f32 = 1.5807170421e-3;
var x = x_;
const ux = @bitCast(u32, x);
@ -93,8 +93,7 @@ fn expm1_32(x_: f32) f32 {
math.forceEval(x * x);
}
return x;
}
else {
} else {
k = 0;
}
@ -148,13 +147,13 @@ fn expm1_32(x_: f32) f32 {
fn expm1_64(x_: f64) f64 {
@setFloatMode(this, builtin.FloatMode.Strict);
const o_threshold: f64 = 7.09782712893383973096e+02;
const ln2_hi: f64 = 6.93147180369123816490e-01;
const ln2_lo: f64 = 1.90821492927058770002e-10;
const invln2: f64 = 1.44269504088896338700e+00;
const ln2_hi: f64 = 6.93147180369123816490e-01;
const ln2_lo: f64 = 1.90821492927058770002e-10;
const invln2: f64 = 1.44269504088896338700e+00;
const Q1: f64 = -3.33333333333331316428e-02;
const Q2: f64 = 1.58730158725481460165e-03;
const Q2: f64 = 1.58730158725481460165e-03;
const Q3: f64 = -7.93650757867487942473e-05;
const Q4: f64 = 4.00821782732936239552e-06;
const Q4: f64 = 4.00821782732936239552e-06;
const Q5: f64 = -2.01099218183624371326e-07;
var x = x_;
@ -223,8 +222,7 @@ fn expm1_64(x_: f64) f64 {
math.forceEval(f32(x));
}
return x;
}
else {
} else {
k = 0;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -138,8 +138,7 @@ fn log1p_64(x: f64) f64 {
c = 0;
f = x;
}
}
else if (hx >= 0x7FF00000) {
} else if (hx >= 0x7FF00000) {
return x;
}

View File

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

View File

@ -28,7 +28,6 @@ const assert = std.debug.assert;
// This implementation is taken from the go stlib, musl is a bit more complex.
pub fn pow(comptime T: type, x: T, y: T) T {
@setFloatMode(this, @import("builtin").FloatMode.Strict);
if (T != f32 and T != f64) {

View File

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

View File

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

View File

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

View File

@ -6,14 +6,14 @@ const builtin = @import("builtin");
const mem = this;
pub const Allocator = struct {
const Error = error {OutOfMemory};
const Error = error{OutOfMemory};
/// Allocate byte_count bytes and return them in a slice, with the
/// slice's pointer aligned at least to alignment bytes.
/// The returned newly allocated memory is undefined.
/// `alignment` is guaranteed to be >= 1
/// `alignment` is guaranteed to be a power of 2
allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
allocFn: fn(self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
/// If `new_byte_count > old_mem.len`:
/// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
@ -26,10 +26,10 @@ pub const Allocator = struct {
/// The returned newly allocated memory is undefined.
/// `alignment` is guaranteed to be >= 1
/// `alignment` is guaranteed to be a power of 2
reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
reallocFn: fn(self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
freeFn: fn (self: &Allocator, old_mem: []u8) void,
freeFn: fn(self: &Allocator, old_mem: []u8) void,
fn create(self: &Allocator, comptime T: type) !&T {
if (@sizeOf(T) == 0) return &{};
@ -47,7 +47,7 @@ pub const Allocator = struct {
if (@sizeOf(T) == 0) return &{};
const slice = try self.alloc(T, 1);
const ptr = &slice[0];
*ptr = *init;
ptr.* = init.*;
return ptr;
}
@ -59,9 +59,7 @@ pub const Allocator = struct {
return self.alignedAlloc(T, @alignOf(T), n);
}
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
n: usize) ![]align(alignment) T
{
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
if (n == 0) {
return (&align(alignment) T)(undefined)[0..0];
}
@ -70,7 +68,7 @@ pub const Allocator = struct {
assert(byte_slice.len == byte_count);
// This loop gets optimized out in ReleaseFast mode
for (byte_slice) |*byte| {
*byte = undefined;
byte.* = undefined;
}
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
}
@ -79,9 +77,7 @@ pub const Allocator = struct {
return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
}
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
{
fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
if (old_mem.len == 0) {
return self.alloc(T, n);
}
@ -97,7 +93,7 @@ pub const Allocator = struct {
if (n > old_mem.len) {
// This loop gets optimized out in ReleaseFast mode
for (byte_slice[old_byte_slice.len..]) |*byte| {
*byte = undefined;
byte.* = undefined;
}
}
return ([]T)(@alignCast(alignment, byte_slice));
@ -110,9 +106,7 @@ pub const Allocator = struct {
return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
}
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,
old_mem: []align(alignment) T, n: usize) []align(alignment) T
{
fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
if (n == 0) {
self.free(old_mem);
return old_mem[0..0];
@ -131,8 +125,7 @@ pub const Allocator = struct {
fn free(self: &Allocator, memory: var) void {
const bytes = ([]const u8)(memory);
if (bytes.len == 0)
return;
if (bytes.len == 0) return;
const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
self.freeFn(self, non_const_ptr[0..bytes.len]);
}
@ -146,11 +139,13 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {
// this and automatically omit safety checks for loops
@setRuntimeSafety(false);
assert(dest.len >= source.len);
for (source) |s, i| dest[i] = s;
for (source) |s, i|
dest[i] = s;
}
pub fn set(comptime T: type, dest: []T, value: T) void {
for (dest) |*d| *d = value;
for (dest) |*d|
d.* = value;
}
/// Returns true if lhs < rhs, false otherwise
@ -182,6 +177,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
/// Returns true if all elements in a slice are equal to the scalar value provided
pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
for (slice) |item| {
if (item != scalar) return false;
}
return true;
}
/// Copies ::m to newly allocated memory. Caller is responsible to free it.
pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
const new_buf = try allocator.alloc(T, m.len);
@ -229,8 +232,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 +240,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 +254,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 +264,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 +278,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 +349,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 +366,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 +393,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 +401,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 +419,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 +435,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 +444,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 +540,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 +593,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 +650,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 +665,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,13 +692,25 @@ 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
// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by
// endian-casting the pointer and then dereferencing
pub fn endianSwapIfLe(comptime T: type, x: T) T {

View File

@ -19,9 +19,9 @@ 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 {
return Address{
.os_addr = posix.sockaddr{
.in = posix.sockaddr_in{
.family = posix.AF_INET,
.port = std.mem.endianSwapIfLe(u16, port),
.addr = ip4,
@ -32,10 +32,10 @@ pub const Address = struct {
}
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 {
.os_addr = posix.sockaddr{
.in6 = posix.sockaddr_in6{
.family = posix.AF_INET6,
.port = std.mem.endianSwapIfLe(u16, port),
.flowinfo = 0,
@ -47,9 +47,7 @@ pub const Address = struct {
}
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 +96,7 @@ pub fn parseIp4(buf: []const u8) !u32 {
}
} else {
return error.InvalidCharacter;
}
}
}
if (index == 3 and saw_any_digits) {
out_ptr[index] = x;

View File

@ -49,7 +49,7 @@ pub const ChildProcess = struct {
err_pipe: if (is_windows) void else [2]i32,
llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
pub const SpawnError = error {
pub const SpawnError = error{
ProcessFdQuotaExceeded,
Unexpected,
NotDir,
@ -88,7 +88,7 @@ pub const ChildProcess = struct {
const child = try allocator.create(ChildProcess);
errdefer allocator.destroy(child);
*child = ChildProcess {
child.* = ChildProcess{
.allocator = allocator,
.argv = argv,
.pid = undefined,
@ -99,8 +99,10 @@ pub const ChildProcess = struct {
.term = null,
.env_map = null,
.cwd = null,
.uid = if (is_windows) {} else null,
.gid = if (is_windows) {} else null,
.uid = if (is_windows) {} else
null,
.gid = if (is_windows) {} else
null,
.stdin = null,
.stdout = null,
.stderr = null,
@ -193,9 +195,7 @@ pub const ChildProcess = struct {
/// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
/// If it succeeds, the caller owns result.stdout and result.stderr memory.
pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
env_map: ?&const BufMap, max_output_size: usize) !ExecResult
{
pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?&const BufMap, max_output_size: usize) !ExecResult {
const child = try ChildProcess.init(argv, allocator);
defer child.deinit();
@ -218,7 +218,7 @@ pub const ChildProcess = struct {
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
return ExecResult {
return ExecResult{
.term = try child.wait(),
.stdout = stdout.toOwnedSlice(),
.stderr = stderr.toOwnedSlice(),
@ -255,9 +255,9 @@ pub const ChildProcess = struct {
self.term = (SpawnError!Term)(x: {
var exit_code: windows.DWORD = undefined;
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
break :x Term { .Unknown = 0 };
break :x Term{ .Unknown = 0 };
} else {
break :x Term { .Exited = @bitCast(i32, exit_code)};
break :x Term{ .Exited = @bitCast(i32, exit_code) };
}
});
@ -288,9 +288,18 @@ pub const ChildProcess = struct {
}
fn cleanupStreams(self: &ChildProcess) void {
if (self.stdin) |*stdin| { stdin.close(); self.stdin = null; }
if (self.stdout) |*stdout| { stdout.close(); self.stdout = null; }
if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
if (self.stdin) |*stdin| {
stdin.close();
self.stdin = null;
}
if (self.stdout) |*stdout| {
stdout.close();
self.stdout = null;
}
if (self.stderr) |*stderr| {
stderr.close();
self.stderr = null;
}
}
fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
@ -317,25 +326,30 @@ pub const ChildProcess = struct {
fn statusToTerm(status: i32) Term {
return if (posix.WIFEXITED(status))
Term { .Exited = posix.WEXITSTATUS(status) }
Term{ .Exited = posix.WEXITSTATUS(status) }
else if (posix.WIFSIGNALED(status))
Term { .Signal = posix.WTERMSIG(status) }
Term{ .Signal = posix.WTERMSIG(status) }
else if (posix.WIFSTOPPED(status))
Term { .Stopped = posix.WSTOPSIG(status) }
Term{ .Stopped = posix.WSTOPSIG(status) }
else
Term { .Unknown = status }
;
Term{ .Unknown = status };
}
fn spawnPosix(self: &ChildProcess) !void {
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
errdefer if (self.stdin_behavior == StdIo.Pipe) {
destroyPipe(stdin_pipe);
};
const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
errdefer if (self.stdout_behavior == StdIo.Pipe) {
destroyPipe(stdout_pipe);
};
const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
errdefer if (self.stderr_behavior == StdIo.Pipe) {
destroyPipe(stderr_pipe);
};
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const dev_null_fd = if (any_ignore) blk: {
@ -346,7 +360,9 @@ pub const ChildProcess = struct {
} else blk: {
break :blk undefined;
};
defer { if (any_ignore) os.close(dev_null_fd); }
defer {
if (any_ignore) os.close(dev_null_fd);
}
var env_map_owned: BufMap = undefined;
var we_own_env_map: bool = undefined;
@ -358,7 +374,9 @@ pub const ChildProcess = struct {
env_map_owned = try os.getEnvMap(self.allocator);
break :x &env_map_owned;
};
defer { if (we_own_env_map) env_map_owned.deinit(); }
defer {
if (we_own_env_map) env_map_owned.deinit();
}
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
@ -375,17 +393,12 @@ pub const ChildProcess = struct {
}
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 +409,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 +435,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 +486,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 +506,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 +526,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 +556,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 +577,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 +588,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 +618,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,15 +637,10 @@ 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,
@ -641,18 +651,16 @@ 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 {
var buf = try Buffer.initSize(allocator, 0);
defer buf.deinit();
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;
@ -663,18 +671,18 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
switch (byte) {
'\\' => backslash_count += 1,
'"' => {
try buf.appendByteNTimes('\\', backslash_count * 2 + 1);
try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
try buf.appendByte('"');
backslash_count = 0;
},
else => {
try buf.appendByteNTimes('\\', backslash_count);
try buf_stream.writeByteNTimes('\\', backslash_count);
try buf.appendByte(byte);
backslash_count = 0;
},
}
}
try buf.appendByteNTimes('\\', backslash_count * 2);
try buf_stream.writeByteNTimes('\\', backslash_count * 2);
try buf.appendByte('"');
}
@ -686,7 +694,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;
@ -715,8 +722,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 {
@ -725,8 +732,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 {
@ -742,8 +749,8 @@ fn makePipe() ![2]i32 {
}
fn destroyPipe(pipe: &const [2]i32) void {
os.close((*pipe)[0]);
os.close((*pipe)[1]);
os.close((pipe.*)[0]);
os.close((pipe.*)[1]);
}
// Child of fork calls this to report an error to the fork parent.

View File

@ -10,33 +10,75 @@ 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;
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
/// [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;
/// 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;
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
/// [XSI] notify on stop, untraced child
pub const WUNTRACED = 0x00000002;
/// 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 +88,47 @@ 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 +156,136 @@ 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;
pub const SIGHUP = 1; /// hangup
pub const SIGINT = 2; /// interrupt
pub const SIGQUIT = 3; /// quit
pub const SIGILL = 4; /// illegal instruction (not reset when caught)
pub const SIGTRAP = 5; /// trace trap (not reset when caught)
pub const SIGABRT = 6; /// abort()
pub const SIGPOLL = 7; /// pollable event ([XSR] generated, not supported)
pub const SIGIOT = SIGABRT; /// compatibility
pub const SIGEMT = 7; /// EMT instruction
pub const SIGFPE = 8; /// floating point exception
pub const SIGKILL = 9; /// kill (cannot be caught or ignored)
pub const SIGBUS = 10; /// bus error
pub const SIGSEGV = 11; /// segmentation violation
pub const SIGSYS = 12; /// bad argument to system call
pub const SIGPIPE = 13; /// write on a pipe with no one to read it
pub const SIGALRM = 14; /// alarm clock
pub const SIGTERM = 15; /// software termination signal from kill
pub const SIGURG = 16; /// urgent condition on IO channel
pub const SIGSTOP = 17; /// sendable stop signal not from tty
pub const SIGTSTP = 18; /// stop signal from tty
pub const SIGCONT = 19; /// continue a stopped process
pub const SIGCHLD = 20; /// to parent on child stop or exit
pub const SIGTTIN = 21; /// to readers pgrp upon background tty read
pub const SIGTTOU = 22; /// like TTIN for output if (tp->t_local&LTOSTOP)
pub const SIGIO = 23; /// input/output possible signal
pub const SIGXCPU = 24; /// exceeded CPU time limit
pub const SIGXFSZ = 25; /// exceeded file size limit
pub const SIGVTALRM = 26; /// virtual time alarm
pub const SIGPROF = 27; /// profiling time alarm
pub const SIGWINCH = 28; /// window size changes
pub const SIGINFO = 29; /// information request
pub const SIGUSR1 = 30; /// user defined signal 1
pub const SIGUSR2 = 31; /// user defined signal 2
/// unblock specified signal set
pub const SIG_UNBLOCK = 2;
fn wstatus(x: i32) i32 { return x & 0o177; }
/// set specified signal set
pub const SIG_SETMASK = 3;
/// hangup
pub const SIGHUP = 1;
/// interrupt
pub const SIGINT = 2;
/// quit
pub const SIGQUIT = 3;
/// illegal instruction (not reset when caught)
pub const SIGILL = 4;
/// trace trap (not reset when caught)
pub const SIGTRAP = 5;
/// abort()
pub const SIGABRT = 6;
/// pollable event ([XSR] generated, not supported)
pub const SIGPOLL = 7;
/// compatibility
pub const SIGIOT = SIGABRT;
/// EMT instruction
pub const SIGEMT = 7;
/// floating point exception
pub const SIGFPE = 8;
/// kill (cannot be caught or ignored)
pub const SIGKILL = 9;
/// bus error
pub const SIGBUS = 10;
/// segmentation violation
pub const SIGSEGV = 11;
/// bad argument to system call
pub const SIGSYS = 12;
/// write on a pipe with no one to read it
pub const SIGPIPE = 13;
/// alarm clock
pub const SIGALRM = 14;
/// software termination signal from kill
pub const SIGTERM = 15;
/// urgent condition on IO channel
pub const SIGURG = 16;
/// sendable stop signal not from tty
pub const SIGSTOP = 17;
/// stop signal from tty
pub const SIGTSTP = 18;
/// continue a stopped process
pub const SIGCONT = 19;
/// to parent on child stop or exit
pub const SIGCHLD = 20;
/// to readers pgrp upon background tty read
pub const SIGTTIN = 21;
/// like TTIN for output if (tp->t_local&LTOSTOP)
pub const SIGTTOU = 22;
/// input/output possible signal
pub const SIGIO = 23;
/// exceeded CPU time limit
pub const SIGXCPU = 24;
/// exceeded file size limit
pub const SIGXFSZ = 25;
/// virtual time alarm
pub const SIGVTALRM = 26;
/// profiling time alarm
pub const SIGPROF = 27;
/// window size changes
pub const SIGWINCH = 28;
/// information request
pub const SIGINFO = 29;
/// user defined signal 1
pub const SIGUSR1 = 30;
/// user defined signal 2
pub const SIGUSR2 = 31;
fn wstatus(x: i32) i32 {
return x & 0o177;
}
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 +337,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 +352,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 +373,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 +418,7 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
}
pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) usize {
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
}
pub fn setreuid(ruid: u32, euid: u32) usize {
@ -287,8 +436,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 +447,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 +468,22 @@ pub const sockaddr = c.sockaddr;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = struct {
handler: extern fn(i32)void,
handler: extern fn(i32) void,
mask: sigset_t,
flags: u32,
};
pub fn sigaddset(set: &sigset_t, signo: u5) void {
*set |= u32(1) << (signo - 1);
set.* |= u32(1) << (signo - 1);
}
/// Takes the return value from a syscall and formats it back in the way
/// that the kernel represents it to libc. Errno was a mistake, let's make
/// it go away forever.
fn errnoWrap(value: isize) usize {
return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
}
pub const timezone = c.timezone;
pub const timeval = c.timeval;
pub const mach_timebase_info_data = c.mach_timebase_info_data;

View File

@ -1,142 +1,328 @@
/// Operation not permitted
pub const EPERM = 1;
pub const EPERM = 1; /// Operation not permitted
pub const ENOENT = 2; /// No such file or directory
pub const ESRCH = 3; /// No such process
pub const EINTR = 4; /// Interrupted system call
pub const EIO = 5; /// Input/output error
pub const ENXIO = 6; /// Device not configured
pub const E2BIG = 7; /// Argument list too long
pub const ENOEXEC = 8; /// Exec format error
pub const EBADF = 9; /// Bad file descriptor
pub const ECHILD = 10; /// No child processes
pub const EDEADLK = 11; /// Resource deadlock avoided
/// No such file or directory
pub const ENOENT = 2;
pub const ENOMEM = 12; /// Cannot allocate memory
pub const EACCES = 13; /// Permission denied
pub const EFAULT = 14; /// Bad address
pub const ENOTBLK = 15; /// Block device required
pub const EBUSY = 16; /// Device / Resource busy
pub const EEXIST = 17; /// File exists
pub const EXDEV = 18; /// Cross-device link
pub const ENODEV = 19; /// Operation not supported by device
pub const ENOTDIR = 20; /// Not a directory
pub const EISDIR = 21; /// Is a directory
pub const EINVAL = 22; /// Invalid argument
pub const ENFILE = 23; /// Too many open files in system
pub const EMFILE = 24; /// Too many open files
pub const ENOTTY = 25; /// Inappropriate ioctl for device
pub const ETXTBSY = 26; /// Text file busy
pub const EFBIG = 27; /// File too large
pub const ENOSPC = 28; /// No space left on device
pub const ESPIPE = 29; /// Illegal seek
pub const EROFS = 30; /// Read-only file system
pub const EMLINK = 31; /// Too many links
pub const EPIPE = 32; /// Broken pipe
/// No such process
pub const ESRCH = 3;
/// Interrupted system call
pub const EINTR = 4;
/// Input/output error
pub const EIO = 5;
/// Device not configured
pub const ENXIO = 6;
/// Argument list too long
pub const E2BIG = 7;
/// Exec format error
pub const ENOEXEC = 8;
/// Bad file descriptor
pub const EBADF = 9;
/// No child processes
pub const ECHILD = 10;
/// Resource deadlock avoided
pub const EDEADLK = 11;
/// Cannot allocate memory
pub const ENOMEM = 12;
/// Permission denied
pub const EACCES = 13;
/// Bad address
pub const EFAULT = 14;
/// Block device required
pub const ENOTBLK = 15;
/// Device / Resource busy
pub const EBUSY = 16;
/// File exists
pub const EEXIST = 17;
/// Cross-device link
pub const EXDEV = 18;
/// Operation not supported by device
pub const ENODEV = 19;
/// Not a directory
pub const ENOTDIR = 20;
/// Is a directory
pub const EISDIR = 21;
/// Invalid argument
pub const EINVAL = 22;
/// Too many open files in system
pub const ENFILE = 23;
/// Too many open files
pub const EMFILE = 24;
/// Inappropriate ioctl for device
pub const ENOTTY = 25;
/// Text file busy
pub const ETXTBSY = 26;
/// File too large
pub const EFBIG = 27;
/// No space left on device
pub const ENOSPC = 28;
/// Illegal seek
pub const ESPIPE = 29;
/// Read-only file system
pub const EROFS = 30;
/// Too many links
pub const EMLINK = 31;
/// Broken pipe
// math software
pub const EDOM = 33; /// Numerical argument out of domain
pub const ERANGE = 34; /// Result too large
pub const EPIPE = 32;
/// Numerical argument out of domain
pub const EDOM = 33;
/// Result too large
// non-blocking and interrupt i/o
pub const EAGAIN = 35; /// Resource temporarily unavailable
pub const EWOULDBLOCK = EAGAIN; /// Operation would block
pub const EINPROGRESS = 36; /// Operation now in progress
pub const EALREADY = 37; /// Operation already in progress
pub const ERANGE = 34;
/// Resource temporarily unavailable
pub const EAGAIN = 35;
/// Operation would block
pub const EWOULDBLOCK = EAGAIN;
/// Operation now in progress
pub const EINPROGRESS = 36;
/// Operation already in progress
// ipc/network software -- argument errors
pub const ENOTSOCK = 38; /// Socket operation on non-socket
pub const EDESTADDRREQ = 39; /// Destination address required
pub const EMSGSIZE = 40; /// Message too long
pub const EPROTOTYPE = 41; /// Protocol wrong type for socket
pub const ENOPROTOOPT = 42; /// Protocol not available
pub const EPROTONOSUPPORT = 43; /// Protocol not supported
pub const EALREADY = 37;
pub const ESOCKTNOSUPPORT = 44; /// Socket type not supported
/// Socket operation on non-socket
pub const ENOTSOCK = 38;
pub const ENOTSUP = 45; /// Operation not supported
/// Destination address required
pub const EDESTADDRREQ = 39;
pub const EPFNOSUPPORT = 46; /// Protocol family not supported
pub const EAFNOSUPPORT = 47; /// Address family not supported by protocol family
pub const EADDRINUSE = 48; /// Address already in use
pub const EADDRNOTAVAIL = 49; /// Can't assign requested address
/// Message too long
pub const EMSGSIZE = 40;
/// Protocol wrong type for socket
pub const EPROTOTYPE = 41;
/// Protocol not available
pub const ENOPROTOOPT = 42;
/// Protocol not supported
pub const EPROTONOSUPPORT = 43;
/// Socket type not supported
pub const ESOCKTNOSUPPORT = 44;
/// Operation not supported
pub const ENOTSUP = 45;
/// Protocol family not supported
pub const EPFNOSUPPORT = 46;
/// Address family not supported by protocol family
pub const EAFNOSUPPORT = 47;
/// Address already in use
pub const EADDRINUSE = 48;
/// Can't assign requested address
// ipc/network software -- operational errors
pub const ENETDOWN = 50; /// Network is down
pub const ENETUNREACH = 51; /// Network is unreachable
pub const ENETRESET = 52; /// Network dropped connection on reset
pub const ECONNABORTED = 53; /// Software caused connection abort
pub const ECONNRESET = 54; /// Connection reset by peer
pub const ENOBUFS = 55; /// No buffer space available
pub const EISCONN = 56; /// Socket is already connected
pub const ENOTCONN = 57; /// Socket is not connected
pub const EADDRNOTAVAIL = 49;
pub const ESHUTDOWN = 58; /// Can't send after socket shutdown
pub const ETOOMANYREFS = 59; /// Too many references: can't splice
/// Network is down
pub const ENETDOWN = 50;
pub const ETIMEDOUT = 60; /// Operation timed out
pub const ECONNREFUSED = 61; /// Connection refused
/// Network is unreachable
pub const ENETUNREACH = 51;
pub const ELOOP = 62; /// Too many levels of symbolic links
pub const ENAMETOOLONG = 63; /// File name too long
/// Network dropped connection on reset
pub const ENETRESET = 52;
pub const EHOSTDOWN = 64; /// Host is down
pub const EHOSTUNREACH = 65; /// No route to host
pub const ENOTEMPTY = 66; /// Directory not empty
/// Software caused connection abort
pub const ECONNABORTED = 53;
/// Connection reset by peer
pub const ECONNRESET = 54;
/// No buffer space available
pub const ENOBUFS = 55;
/// Socket is already connected
pub const EISCONN = 56;
/// Socket is not connected
pub const ENOTCONN = 57;
/// Can't send after socket shutdown
pub const ESHUTDOWN = 58;
/// Too many references: can't splice
pub const ETOOMANYREFS = 59;
/// Operation timed out
pub const ETIMEDOUT = 60;
/// Connection refused
pub const ECONNREFUSED = 61;
/// Too many levels of symbolic links
pub const ELOOP = 62;
/// File name too long
pub const ENAMETOOLONG = 63;
/// Host is down
pub const EHOSTDOWN = 64;
/// No route to host
pub const EHOSTUNREACH = 65;
/// Directory not empty
// quotas & mush
pub const EPROCLIM = 67; /// Too many processes
pub const EUSERS = 68; /// Too many users
pub const EDQUOT = 69; /// Disc quota exceeded
pub const ENOTEMPTY = 66;
/// Too many processes
pub const EPROCLIM = 67;
/// Too many users
pub const EUSERS = 68;
/// Disc quota exceeded
// Network File System
pub const ESTALE = 70; /// Stale NFS file handle
pub const EREMOTE = 71; /// Too many levels of remote in path
pub const EBADRPC = 72; /// RPC struct is bad
pub const ERPCMISMATCH = 73; /// RPC version wrong
pub const EPROGUNAVAIL = 74; /// RPC prog. not avail
pub const EPROGMISMATCH = 75; /// Program version wrong
pub const EPROCUNAVAIL = 76; /// Bad procedure for program
pub const EDQUOT = 69;
pub const ENOLCK = 77; /// No locks available
pub const ENOSYS = 78; /// Function not implemented
/// Stale NFS file handle
pub const ESTALE = 70;
pub const EFTYPE = 79; /// Inappropriate file type or format
pub const EAUTH = 80; /// Authentication error
pub const ENEEDAUTH = 81; /// Need authenticator
/// Too many levels of remote in path
pub const EREMOTE = 71;
/// RPC struct is bad
pub const EBADRPC = 72;
/// RPC version wrong
pub const ERPCMISMATCH = 73;
/// RPC prog. not avail
pub const EPROGUNAVAIL = 74;
/// Program version wrong
pub const EPROGMISMATCH = 75;
/// Bad procedure for program
pub const EPROCUNAVAIL = 76;
/// No locks available
pub const ENOLCK = 77;
/// Function not implemented
pub const ENOSYS = 78;
/// Inappropriate file type or format
pub const EFTYPE = 79;
/// Authentication error
pub const EAUTH = 80;
/// Need authenticator
// Intelligent device errors
pub const EPWROFF = 82; /// Device power is off
pub const EDEVERR = 83; /// Device error, e.g. paper out
pub const ENEEDAUTH = 81;
pub const EOVERFLOW = 84; /// Value too large to be stored in data type
/// Device power is off
pub const EPWROFF = 82;
/// Device error, e.g. paper out
pub const EDEVERR = 83;
/// Value too large to be stored in data type
// Program loading errors
pub const EBADEXEC = 85; /// Bad executable
pub const EBADARCH = 86; /// Bad CPU type in executable
pub const ESHLIBVERS = 87; /// Shared library version mismatch
pub const EBADMACHO = 88; /// Malformed Macho file
pub const EOVERFLOW = 84;
pub const ECANCELED = 89; /// Operation canceled
/// Bad executable
pub const EBADEXEC = 85;
pub const EIDRM = 90; /// Identifier removed
pub const ENOMSG = 91; /// No message of desired type
pub const EILSEQ = 92; /// Illegal byte sequence
pub const ENOATTR = 93; /// Attribute not found
/// Bad CPU type in executable
pub const EBADARCH = 86;
pub const EBADMSG = 94; /// Bad message
pub const EMULTIHOP = 95; /// Reserved
pub const ENODATA = 96; /// No message available on STREAM
pub const ENOLINK = 97; /// Reserved
pub const ENOSR = 98; /// No STREAM resources
pub const ENOSTR = 99; /// Not a STREAM
pub const EPROTO = 100; /// Protocol error
pub const ETIME = 101; /// STREAM ioctl timeout
/// Shared library version mismatch
pub const ESHLIBVERS = 87;
pub const ENOPOLICY = 103; /// No such policy registered
/// Malformed Macho file
pub const EBADMACHO = 88;
pub const ENOTRECOVERABLE = 104; /// State not recoverable
pub const EOWNERDEAD = 105; /// Previous owner died
/// Operation canceled
pub const ECANCELED = 89;
pub const EQFULL = 106; /// Interface output queue is full
pub const ELAST = 106; /// Must be equal largest errno
/// Identifier removed
pub const EIDRM = 90;
/// No message of desired type
pub const ENOMSG = 91;
/// Illegal byte sequence
pub const EILSEQ = 92;
/// Attribute not found
pub const ENOATTR = 93;
/// Bad message
pub const EBADMSG = 94;
/// Reserved
pub const EMULTIHOP = 95;
/// No message available on STREAM
pub const ENODATA = 96;
/// Reserved
pub const ENOLINK = 97;
/// No STREAM resources
pub const ENOSR = 98;
/// Not a STREAM
pub const ENOSTR = 99;
/// Protocol error
pub const EPROTO = 100;
/// STREAM ioctl timeout
pub const ETIME = 101;
/// No such policy registered
pub const ENOPOLICY = 103;
/// State not recoverable
pub const ENOTRECOVERABLE = 104;
/// Previous owner died
pub const EOWNERDEAD = 105;
/// Interface output queue is full
pub const EQFULL = 106;
/// Must be equal largest errno
pub const ELAST = 106;

View File

@ -1,26 +1,26 @@
/// Epoch reference times in terms of their difference from
/// posix epoch in seconds.
pub const posix = 0; //Jan 01, 1970 AD
pub const dos = 315532800; //Jan 01, 1980 AD
pub const ios = 978307200; //Jan 01, 2001 AD
pub const openvms = -3506716800; //Nov 17, 1858 AD
pub const zos = -2208988800; //Jan 01, 1900 AD
pub const windows = -11644473600; //Jan 01, 1601 AD
pub const amiga = 252460800; //Jan 01, 1978 AD
pub const pickos = -63244800; //Dec 31, 1967 AD
pub const gps = 315964800; //Jan 06, 1980 AD
pub const clr = -62135769600; //Jan 01, 0001 AD
pub const posix = 0; //Jan 01, 1970 AD
pub const dos = 315532800; //Jan 01, 1980 AD
pub const ios = 978307200; //Jan 01, 2001 AD
pub const openvms = -3506716800; //Nov 17, 1858 AD
pub const zos = -2208988800; //Jan 01, 1900 AD
pub const windows = -11644473600; //Jan 01, 1601 AD
pub const amiga = 252460800; //Jan 01, 1978 AD
pub const pickos = -63244800; //Dec 31, 1967 AD
pub const gps = 315964800; //Jan 06, 1980 AD
pub const clr = -62135769600; //Jan 01, 0001 AD
pub const unix = posix;
pub const android = posix;
pub const os2 = dos;
pub const bios = dos;
pub const vfat = dos;
pub const ntfs = windows;
pub const ntp = zos;
pub const jbase = pickos;
pub const aros = amiga;
pub const morphos = amiga;
pub const brew = gps;
pub const atsc = gps;
pub const go = clr;
pub const unix = posix;
pub const android = posix;
pub const os2 = dos;
pub const bios = dos;
pub const vfat = dos;
pub const ntfs = windows;
pub const ntp = zos;
pub const jbase = pickos;
pub const aros = amiga;
pub const morphos = amiga;
pub const brew = gps;
pub const atsc = gps;
pub const go = clr;

View File

@ -21,12 +21,18 @@ pub const File = struct {
/// Call close to clean up.
pub fn openRead(allocator: &mem.Allocator, path: []const u8) OpenError!File {
if (is_posix) {
const flags = posix.O_LARGEFILE|posix.O_RDONLY;
const flags = posix.O_LARGEFILE | posix.O_RDONLY;
const fd = try os.posixOpen(allocator, path, flags, 0);
return openHandle(fd);
} else if (is_windows) {
const handle = try os.windowsOpen(allocator, path, windows.GENERIC_READ, windows.FILE_SHARE_READ,
windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
const handle = try os.windowsOpen(
allocator,
path,
windows.GENERIC_READ,
windows.FILE_SHARE_READ,
windows.OPEN_EXISTING,
windows.FILE_ATTRIBUTE_NORMAL,
);
return openHandle(handle);
} else {
@compileError("TODO implement openRead for this OS");
@ -36,7 +42,6 @@ pub const File = struct {
/// Calls `openWriteMode` with os.default_file_mode for the mode.
pub fn openWrite(allocator: &mem.Allocator, path: []const u8) OpenError!File {
return openWriteMode(allocator, path, os.default_file_mode);
}
/// If the path does not exist it will be created.
@ -45,18 +50,22 @@ pub const File = struct {
/// Call close to clean up.
pub fn openWriteMode(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
if (is_posix) {
const flags = posix.O_LARGEFILE|posix.O_WRONLY|posix.O_CREAT|posix.O_CLOEXEC|posix.O_TRUNC;
const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
const fd = try os.posixOpen(allocator, path, flags, file_mode);
return openHandle(fd);
} else if (is_windows) {
const handle = try os.windowsOpen(allocator, path, windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE|windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE,
windows.CREATE_ALWAYS, windows.FILE_ATTRIBUTE_NORMAL);
const handle = try os.windowsOpen(
allocator,
path,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
windows.CREATE_ALWAYS,
windows.FILE_ATTRIBUTE_NORMAL,
);
return openHandle(handle);
} else {
@compileError("TODO implement openWriteMode for this OS");
}
}
/// If the path does not exist it will be created.
@ -65,24 +74,26 @@ pub const File = struct {
/// Call close to clean up.
pub fn openWriteNoClobber(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
if (is_posix) {
const flags = posix.O_LARGEFILE|posix.O_WRONLY|posix.O_CREAT|posix.O_CLOEXEC|posix.O_EXCL;
const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_EXCL;
const fd = try os.posixOpen(allocator, path, flags, file_mode);
return openHandle(fd);
} else if (is_windows) {
const handle = try os.windowsOpen(allocator, path, windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE|windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE,
windows.CREATE_NEW, windows.FILE_ATTRIBUTE_NORMAL);
const handle = try os.windowsOpen(
allocator,
path,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
windows.CREATE_NEW,
windows.FILE_ATTRIBUTE_NORMAL,
);
return openHandle(handle);
} else {
@compileError("TODO implement openWriteMode for this OS");
}
}
pub fn openHandle(handle: os.FileHandle) File {
return File {
.handle = handle,
};
return File{ .handle = handle };
}
pub fn access(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
@ -217,7 +228,7 @@ pub const File = struct {
return result;
},
Os.windows => {
var pos : windows.LARGE_INTEGER = undefined;
var pos: windows.LARGE_INTEGER = undefined;
if (windows.SetFilePointerEx(self.handle, 0, &pos, windows.FILE_CURRENT) == 0) {
const err = windows.GetLastError();
return switch (err) {
@ -268,7 +279,7 @@ pub const File = struct {
}
}
pub const ModeError = error {
pub const ModeError = error{
BadFd,
SystemResources,
Unexpected,
@ -296,7 +307,7 @@ pub const File = struct {
}
}
pub const ReadError = error {};
pub const ReadError = error{};
pub fn read(self: &File, buffer: []u8) !usize {
if (is_posix) {
@ -306,12 +317,12 @@ pub const File = struct {
const read_err = posix.getErrno(amt_read);
if (read_err > 0) {
switch (read_err) {
posix.EINTR => continue,
posix.EINTR => continue,
posix.EINVAL => unreachable,
posix.EFAULT => unreachable,
posix.EBADF => return error.BadFd,
posix.EIO => return error.Io,
else => return os.unexpectedErrorPosix(read_err),
posix.EBADF => return error.BadFd,
posix.EIO => return error.Io,
else => return os.unexpectedErrorPosix(read_err),
}
}
if (amt_read == 0) return index;

View File

@ -74,7 +74,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
'\n' => return error.CorruptPasswordFile,
else => {
const digit = switch (byte) {
'0' ... '9' => byte - '0',
'0'...'9' => byte - '0',
else => return error.CorruptPasswordFile,
};
if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
@ -83,14 +83,14 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
},
State.ReadGroupId => switch (byte) {
'\n', ':' => {
return UserInfo {
return UserInfo{
.uid = uid,
.gid = gid,
};
},
else => {
const digit = switch (byte) {
'0' ... '9' => byte - '0',
'0'...'9' => byte - '0',
else => return error.CorruptPasswordFile,
};
if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;

View File

@ -3,8 +3,7 @@ const builtin = @import("builtin");
const Os = builtin.Os;
const is_windows = builtin.os == Os.windows;
const is_posix = switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx => true,
builtin.Os.linux, builtin.Os.macosx => true,
else => false,
};
const os = this;
@ -27,8 +26,7 @@ pub const linux = @import("linux/index.zig");
pub const zen = @import("zen.zig");
pub const posix = switch (builtin.os) {
Os.linux => linux,
Os.macosx,
Os.ios => darwin,
Os.macosx, Os.ios => darwin,
Os.zen => zen,
else => @compileError("Unsupported OS"),
};
@ -112,8 +110,7 @@ pub fn getRandomBytes(buf: []u8) !void {
}
return;
},
Os.macosx,
Os.ios => {
Os.macosx, Os.ios => {
const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
defer close(fd);
@ -137,7 +134,7 @@ pub fn getRandomBytes(buf: []u8) !void {
}
},
Os.zen => {
const randomness = []u8 {
const randomness = []u8{
42,
1,
7,
@ -175,9 +172,7 @@ pub fn abort() noreturn {
c.abort();
}
switch (builtin.os) {
Os.linux,
Os.macosx,
Os.ios => {
Os.linux, Os.macosx, Os.ios => {
_ = posix.raise(posix.SIGABRT);
_ = posix.raise(posix.SIGKILL);
while (true) {}
@ -199,9 +194,7 @@ pub fn exit(status: u8) noreturn {
c.exit(status);
}
switch (builtin.os) {
Os.linux,
Os.macosx,
Os.ios => {
Os.linux, Os.macosx, Os.ios => {
posix.exit(status);
},
Os.windows => {
@ -239,7 +232,7 @@ pub fn close(handle: FileHandle) void {
/// Calls POSIX read, and keeps trying if it gets interrupted.
pub fn posixRead(fd: i32, buf: []u8) !void {
// Linux can return EINVAL when read amount is > 0x7ffff000
// See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274
// See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
const max_buf_len = 0x7ffff000;
var index: usize = 0;
@ -250,14 +243,12 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
if (err > 0) {
return switch (err) {
posix.EINTR => continue,
posix.EINVAL,
posix.EFAULT => unreachable,
posix.EINVAL, posix.EFAULT => unreachable,
posix.EAGAIN => error.WouldBlock,
posix.EBADF => error.FileClosed,
posix.EIO => error.InputOutput,
posix.EISDIR => error.IsDir,
posix.ENOBUFS,
posix.ENOMEM => error.SystemResources,
posix.ENOBUFS, posix.ENOMEM => error.SystemResources,
else => unexpectedErrorPosix(err),
};
}
@ -265,7 +256,7 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
}
}
pub const PosixWriteError = error {
pub const PosixWriteError = error{
WouldBlock,
FileClosed,
DestinationAddressRequired,
@ -281,7 +272,7 @@ pub const PosixWriteError = error {
/// Calls POSIX write, and keeps trying if it gets interrupted.
pub fn posixWrite(fd: i32, bytes: []const u8) !void {
// Linux can return EINVAL when write amount is > 0x7ffff000
// See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856
// See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
const max_bytes_len = 0x7ffff000;
var index: usize = 0;
@ -292,8 +283,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
if (write_err > 0) {
return switch (write_err) {
posix.EINTR => continue,
posix.EINVAL,
posix.EFAULT => unreachable,
posix.EINVAL, posix.EFAULT => unreachable,
posix.EAGAIN => PosixWriteError.WouldBlock,
posix.EBADF => PosixWriteError.FileClosed,
posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
@ -310,7 +300,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
}
}
pub const PosixOpenError = error {
pub const PosixOpenError = error{
OutOfMemory,
AccessDenied,
FileTooBig,
@ -349,8 +339,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {
posix.EFAULT => unreachable,
posix.EINVAL => unreachable,
posix.EACCES => return PosixOpenError.AccessDenied,
posix.EFBIG,
posix.EOVERFLOW => return PosixOpenError.FileTooBig,
posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
posix.EISDIR => return PosixOpenError.IsDir,
posix.ELOOP => return PosixOpenError.SymLinkLoop,
posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
@ -375,8 +364,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
const err = posix.getErrno(posix.dup2(old_fd, new_fd));
if (err > 0) {
return switch (err) {
posix.EBUSY,
posix.EINTR => continue,
posix.EBUSY, posix.EINTR => continue,
posix.EMFILE => error.ProcessFdQuotaExceeded,
posix.EINVAL => unreachable,
else => unexpectedErrorPosix(err),
@ -477,7 +465,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,
@ -493,17 +481,10 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {
assert(err > 0);
return switch (err) {
posix.EFAULT => unreachable,
posix.E2BIG,
posix.EMFILE,
posix.ENAMETOOLONG,
posix.ENFILE,
posix.ENOMEM => error.SystemResources,
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EINVAL,
posix.ENOEXEC => error.InvalidExe,
posix.EIO,
posix.ELOOP => error.FileSystem,
posix.E2BIG, posix.EMFILE, posix.ENAMETOOLONG, posix.ENFILE, posix.ENOMEM => error.SystemResources,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EINVAL, posix.ENOEXEC => error.InvalidExe,
posix.EIO, posix.ELOOP => error.FileSystem,
posix.EISDIR => error.IsDir,
posix.ENOENT => error.FileNotFound,
posix.ENOTDIR => error.NotDir,
@ -512,7 +493,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 +648,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 +667,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path
}
}
pub const PosixSymLinkError = error {
pub const PosixSymLinkError = error{
OutOfMemory,
AccessDenied,
DiskQuota,
@ -717,10 +698,8 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path:
const err = posix.getErrno(posix.symlink(existing_buf.ptr, new_buf.ptr));
if (err > 0) {
return switch (err) {
posix.EFAULT,
posix.EINVAL => unreachable,
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EFAULT, posix.EINVAL => unreachable,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EDQUOT => error.DiskQuota,
posix.EEXIST => error.PathAlreadyExists,
posix.EIO => error.FileSystem,
@ -787,8 +766,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void {
return switch (err) {
windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
windows.ERROR.ACCESS_DENIED => error.AccessDenied,
windows.ERROR.FILENAME_EXCED_RANGE,
windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
else => unexpectedErrorWindows(err),
};
}
@ -804,11 +782,9 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void {
const err = posix.getErrno(posix.unlink(buf.ptr));
if (err > 0) {
return switch (err) {
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EBUSY => error.FileBusy,
posix.EFAULT,
posix.EINVAL => unreachable,
posix.EFAULT, posix.EINVAL => unreachable,
posix.EIO => error.FileSystem,
posix.EISDIR => error.IsDir,
posix.ELOOP => error.SymLinkLoop,
@ -879,14 +855,20 @@ pub const AtomicFile = struct {
const dirname = os.path.dirname(dest_path);
var rand_buf: [12]u8 = undefined;
const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
const dirname_component_len = if (dirname.len == 0) 0 else dirname.len + 1;
const tmp_path = try allocator.alloc(u8, dirname_component_len +
base64.Base64Encoder.calcSize(rand_buf.len));
errdefer allocator.free(tmp_path);
mem.copy(u8, tmp_path[0..], dirname);
tmp_path[dirname.len] = os.path.sep;
if (dirname.len != 0) {
mem.copy(u8, tmp_path[0..], dirname);
tmp_path[dirname.len] = os.path.sep;
}
while (true) {
try getRandomBytes(rand_buf[0..]);
b64_fs_encoder.encode(tmp_path[dirname.len + 1..], rand_buf);
b64_fs_encoder.encode(tmp_path[dirname_component_len..], rand_buf);
const file = os.File.openWriteNoClobber(allocator, tmp_path, mode) catch |err| switch (err) {
error.PathAlreadyExists => continue,
@ -895,7 +877,7 @@ pub const AtomicFile = struct {
else => return err,
};
return AtomicFile {
return AtomicFile{
.allocator = allocator,
.file = file,
.tmp_path = tmp_path,
@ -948,12 +930,10 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
const err = posix.getErrno(posix.rename(old_buf.ptr, new_buf.ptr));
if (err > 0) {
return switch (err) {
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EBUSY => error.FileBusy,
posix.EDQUOT => error.DiskQuota,
posix.EFAULT,
posix.EINVAL => unreachable,
posix.EFAULT, posix.EINVAL => unreachable,
posix.EISDIR => error.IsDir,
posix.ELOOP => error.SymLinkLoop,
posix.EMLINK => error.LinkQuotaExceeded,
@ -962,8 +942,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
posix.ENOTDIR => error.NotDir,
posix.ENOMEM => error.SystemResources,
posix.ENOSPC => error.NoSpaceLeft,
posix.EEXIST,
posix.ENOTEMPTY => error.PathAlreadyExists,
posix.EEXIST, posix.ENOTEMPTY => error.PathAlreadyExists,
posix.EROFS => error.ReadOnlyFileSystem,
posix.EXDEV => error.RenameAcrossMountPoints,
else => unexpectedErrorPosix(err),
@ -1001,8 +980,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void {
const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755));
if (err > 0) {
return switch (err) {
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EDQUOT => error.DiskQuota,
posix.EEXIST => error.PathAlreadyExists,
posix.EFAULT => unreachable,
@ -1065,18 +1043,15 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
const err = posix.getErrno(posix.rmdir(path_buf.ptr));
if (err > 0) {
return switch (err) {
posix.EACCES,
posix.EPERM => error.AccessDenied,
posix.EACCES, posix.EPERM => error.AccessDenied,
posix.EBUSY => error.FileBusy,
posix.EFAULT,
posix.EINVAL => unreachable,
posix.EFAULT, posix.EINVAL => unreachable,
posix.ELOOP => error.SymLinkLoop,
posix.ENAMETOOLONG => error.NameTooLong,
posix.ENOENT => error.FileNotFound,
posix.ENOMEM => error.SystemResources,
posix.ENOTDIR => error.NotDir,
posix.EEXIST,
posix.ENOTEMPTY => error.DirNotEmpty,
posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
posix.EROFS => error.ReadOnlyFileSystem,
else => unexpectedErrorPosix(err),
};
@ -1087,7 +1062,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,
@ -1128,7 +1103,8 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
error.NotDir,
error.FileSystem,
error.FileBusy,
error.Unexpected => return err,
error.Unexpected,
=> return err,
}
{
var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
@ -1152,7 +1128,8 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
error.SystemResources,
error.NoSpaceLeft,
error.PathAlreadyExists,
error.Unexpected => return err,
error.Unexpected,
=> return err,
};
defer dir.close();
@ -1182,8 +1159,7 @@ pub const Dir = struct {
end_index: usize,
const darwin_seek_t = switch (builtin.os) {
Os.macosx,
Os.ios => i64,
Os.macosx, Os.ios => i64,
else => void,
};
@ -1208,16 +1184,19 @@ pub const Dir = struct {
const fd = switch (builtin.os) {
Os.windows => @compileError("TODO support Dir.open for windows"),
Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, 0),
Os.macosx,
Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, 0),
Os.macosx, Os.ios => try posixOpen(
allocator,
dir_path,
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
0,
),
else => @compileError("Dir.open is not supported for this platform"),
};
const darwin_seek_init = switch (builtin.os) {
Os.macosx,
Os.ios => 0,
Os.macosx, Os.ios => 0,
else => {},
};
return Dir {
return Dir{
.allocator = allocator,
.fd = fd,
.darwin_seek = darwin_seek_init,
@ -1237,8 +1216,7 @@ pub const Dir = struct {
pub fn next(self: &Dir) !?Entry {
switch (builtin.os) {
Os.linux => return self.nextLinux(),
Os.macosx,
Os.ios => return self.nextDarwin(),
Os.macosx, Os.ios => return self.nextDarwin(),
Os.windows => return self.nextWindows(),
else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
}
@ -1256,9 +1234,7 @@ pub const Dir = struct {
const err = posix.getErrno(result);
if (err > 0) {
switch (err) {
posix.EBADF,
posix.EFAULT,
posix.ENOTDIR => unreachable,
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
posix.EINVAL => {
self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
continue;
@ -1294,7 +1270,7 @@ pub const Dir = struct {
posix.DT_WHT => Entry.Kind.Whiteout,
else => Entry.Kind.Unknown,
};
return Entry {
return Entry{
.name = name,
.kind = entry_kind,
};
@ -1317,9 +1293,7 @@ pub const Dir = struct {
const err = posix.getErrno(result);
if (err > 0) {
switch (err) {
posix.EBADF,
posix.EFAULT,
posix.ENOTDIR => unreachable,
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
posix.EINVAL => {
self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
continue;
@ -1355,7 +1329,7 @@ pub const Dir = struct {
posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
else => Entry.Kind.Unknown,
};
return Entry {
return Entry{
.name = name,
.kind = entry_kind,
};
@ -1402,8 +1376,7 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
if (err > 0) {
return switch (err) {
posix.EACCES => error.AccessDenied,
posix.EFAULT,
posix.EINVAL => unreachable,
posix.EFAULT, posix.EINVAL => unreachable,
posix.EIO => error.FileSystem,
posix.ELOOP => error.SymLinkLoop,
posix.ENAMETOOLONG => error.NameTooLong,
@ -1465,7 +1438,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) !void {
};
}
pub const WindowsGetStdHandleErrs = error {
pub const WindowsGetStdHandleErrs = error{
NoStdHandles,
Unexpected,
};
@ -1489,7 +1462,7 @@ pub const ArgIteratorPosix = struct {
count: usize,
pub fn init() ArgIteratorPosix {
return ArgIteratorPosix {
return ArgIteratorPosix{
.index = 0,
.count = raw.len,
};
@ -1522,16 +1495,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,
@ -1547,8 +1518,7 @@ pub const ArgIteratorWindows = struct {
const byte = self.cmd_line[self.index];
switch (byte) {
0 => return null,
' ',
'\t' => continue,
' ', '\t' => continue,
else => break,
}
}
@ -1562,8 +1532,7 @@ pub const ArgIteratorWindows = struct {
const byte = self.cmd_line[self.index];
switch (byte) {
0 => return false,
' ',
'\t' => continue,
' ', '\t' => continue,
else => break,
}
}
@ -1582,8 +1551,7 @@ pub const ArgIteratorWindows = struct {
'\\' => {
backslash_count += 1;
},
' ',
'\t' => {
' ', '\t' => {
if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
return true;
}
@ -1623,8 +1591,7 @@ pub const ArgIteratorWindows = struct {
'\\' => {
backslash_count += 1;
},
' ',
'\t' => {
' ', '\t' => {
try self.emitBackslashes(&buf, backslash_count);
backslash_count = 0;
if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
@ -1676,9 +1643,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 +1722,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 +1756,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 +1776,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,
};
@ -1844,8 +1809,7 @@ pub fn openSelfExe() !os.File {
var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
return os.File.openRead(&fixed_allocator.allocator, proc_file_path);
},
Os.macosx,
Os.ios => {
Os.macosx, Os.ios => {
var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;
var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
const self_exe_path = try selfExePath(&fixed_allocator.allocator);
@ -1857,9 +1821,7 @@ pub fn openSelfExe() !os.File {
test "openSelfExe" {
switch (builtin.os) {
Os.linux,
Os.macosx,
Os.ios => (try openSelfExe()).close(),
Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),
else => return, // Unsupported OS.
}
}
@ -1897,8 +1859,7 @@ pub fn selfExePath(allocator: &mem.Allocator) ![]u8 {
try out_path.resize(new_len);
}
},
Os.macosx,
Os.ios => {
Os.macosx, Os.ios => {
var u32_len: u32 = 0;
const ret1 = c._NSGetExecutablePath(undefined, &u32_len);
assert(ret1 != 0);
@ -1926,9 +1887,7 @@ pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 {
const dir = path.dirname(full_exe_path);
return allocator.shrink(u8, full_exe_path, dir.len);
},
Os.windows,
Os.macosx,
Os.ios => {
Os.windows, Os.macosx, Os.ios => {
const self_exe_path = try selfExePath(allocator);
errdefer allocator.free(self_exe_path);
const dirname = os.path.dirname(self_exe_path);
@ -1950,7 +1909,7 @@ pub fn isTty(handle: FileHandle) bool {
}
}
pub const PosixSocketError = error {
pub const PosixSocketError = error{
/// Permission to create a socket of the specified type and/or
/// protocol is denied.
PermissionDenied,
@ -1985,16 +1944,15 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
posix.ENOBUFS,
posix.ENOMEM => return PosixSocketError.SystemResources,
posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
else => return unexpectedErrorPosix(err),
}
}
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
/// For UNIX domain sockets: Search permission is denied on a component
/// of the path prefix.
AccessDenied,
@ -2065,7 +2023,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 +2056,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,
@ -2155,8 +2113,7 @@ pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!
posix.EINVAL => return PosixAcceptError.InvalidSyscall,
posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
posix.ENOBUFS,
posix.ENOMEM => return PosixAcceptError.SystemResources,
posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources,
posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
posix.EPROTO => return PosixAcceptError.ProtocolFailure,
@ -2165,7 +2122,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 +2155,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 +2228,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 +2252,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
@ -2367,8 +2324,7 @@ pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConn
const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
const err = posix.getErrno(rc);
switch (err) {
0,
posix.EINPROGRESS => return,
0, posix.EINPROGRESS => return,
else => return unexpectedErrorPosix(err),
posix.EACCES => return PosixConnectError.PermissionDenied,
@ -2420,7 +2376,7 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
},
else => return unexpectedErrorPosix(err),
posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
posix.EINVAL => unreachable,
posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
@ -2431,11 +2387,13 @@ pub const Thread = struct {
data: Data,
pub const use_pthreads = is_posix and builtin.link_libc;
const Data = if (use_pthreads) struct {
handle: c.pthread_t,
stack_addr: usize,
stack_len: usize,
} else switch (builtin.os) {
const Data = if (use_pthreads)
struct {
handle: c.pthread_t,
stack_addr: usize,
stack_len: usize,
}
else switch (builtin.os) {
builtin.Os.linux => struct {
pid: i32,
stack_addr: usize,
@ -2485,7 +2443,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)),
@ -2517,7 +2475,7 @@ pub const SpawnThreadError = error {
/// caller must call wait on the returned thread
pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread {
// TODO compile-time call graph analysis to determine stack upper bound
// https://github.com/zig-lang/zig/issues/157
// https://github.com/ziglang/zig/issues/157
const default_stack_size = 8 * 1024 * 1024;
const Context = @typeOf(context);
@ -2533,7 +2491,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 +2521,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 +2529,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 +2549,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;
}

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