partial conversion to post-fix pointer deref using zig fmt

This commit is contained in:
Andrew Kelley 2018-05-10 00:29:49 -04:00
parent 6928badd85
commit 4787127cf6
30 changed files with 1617 additions and 1061 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@ -93,7 +93,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
/// Deinitialize with `deinit`
pub fn init(allocator: &Allocator) Self {
return Self {
return Self{
.allocator = allocator,
.len = 0,
.prealloc_segment = undefined,
@ -104,7 +104,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
pub fn deinit(self: &Self) void {
self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);
self.allocator.free(self.dynamic_segments);
*self = undefined;
self.* = undefined;
}
pub fn at(self: &Self, i: usize) &T {
@ -118,7 +118,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
pub fn push(self: &Self, item: &const T) !void {
const new_item_ptr = try self.addOne();
*new_item_ptr = *item;
new_item_ptr.* = item.*;
}
pub fn pushMany(self: &Self, items: []const T) !void {
@ -128,11 +128,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
}
pub fn pop(self: &Self) ?T {
if (self.len == 0)
return null;
if (self.len == 0) return null;
const index = self.len - 1;
const result = *self.uncheckedAt(index);
const result = self.uncheckedAt(index).*;
self.len = index;
return result;
}
@ -245,8 +244,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
shelf_size: usize,
pub fn next(it: &Iterator) ?&T {
if (it.index >= it.list.len)
return null;
if (it.index >= it.list.len) return null;
if (it.index < prealloc_item_count) {
const ptr = &it.list.prealloc_segment[it.index];
it.index += 1;
@ -270,12 +268,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
}
pub fn prev(it: &Iterator) ?&T {
if (it.index == 0)
return null;
if (it.index == 0) return null;
it.index -= 1;
if (it.index < prealloc_item_count)
return &it.list.prealloc_segment[it.index];
if (it.index < prealloc_item_count) return &it.list.prealloc_segment[it.index];
if (it.box_index == 0) {
it.shelf_index -= 1;
@ -290,7 +286,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
};
pub fn iterator(self: &Self, start_index: usize) Iterator {
var it = Iterator {
var it = Iterator{
.list = self,
.index = start_index,
.shelf_index = undefined,
@ -324,25 +320,31 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
var list = SegmentedList(i32, prealloc).init(allocator);
defer list.deinit();
{var i: usize = 0; while (i < 100) : (i += 1) {
try list.push(i32(i + 1));
assert(list.len == i + 1);
}}
{
var i: usize = 0;
while (i < 100) : (i += 1) {
try list.push(i32(i + 1));
assert(list.len == i + 1);
}
}
{var i: usize = 0; while (i < 100) : (i += 1) {
assert(*list.at(i) == i32(i + 1));
}}
{
var i: usize = 0;
while (i < 100) : (i += 1) {
assert(list.at(i).* == i32(i + 1));
}
}
{
var it = list.iterator(0);
var x: i32 = 0;
while (it.next()) |item| {
x += 1;
assert(*item == x);
assert(item.* == x);
}
assert(x == 100);
while (it.prev()) |item| : (x -= 1) {
assert(*item == x);
assert(item.* == x);
}
assert(x == 0);
}
@ -350,14 +352,18 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
assert(??list.pop() == 100);
assert(list.len == 99);
try list.pushMany([]i32 { 1, 2, 3 });
try list.pushMany([]i32{
1,
2,
3,
});
assert(list.len == 102);
assert(??list.pop() == 3);
assert(??list.pop() == 2);
assert(??list.pop() == 1);
assert(list.len == 99);
try list.pushMany([]const i32 {});
try list.pushMany([]const i32{});
assert(list.len == 99);
var i: i32 = 99;

View File

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