diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-12-04 15:28:17 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-12-04 15:28:17 -0500 |
| commit | 42004f9013ba2d06b457f858e0e269ef4ad23554 (patch) | |
| tree | ee99dd89c9ce7e7c30a76e7bf0d9f7da7c0c64c7 /std | |
| parent | afe3aae582d5051406832e32fc01374f2a0029b7 (diff) | |
| parent | a966275e509670e750ef54a37f7202078aa4cf07 (diff) | |
| download | zig-42004f9013ba2d06b457f858e0e269ef4ad23554.tar.gz zig-42004f9013ba2d06b457f858e0e269ef4ad23554.zip | |
Merge branch 'master' into llvm6
Diffstat (limited to 'std')
| -rw-r--r-- | std/buffer.zig | 6 | ||||
| -rw-r--r-- | std/build.zig | 42 | ||||
| -rw-r--r-- | std/debug.zig | 46 | ||||
| -rw-r--r-- | std/elf.zig | 79 | ||||
| -rw-r--r-- | std/endian.zig | 4 | ||||
| -rw-r--r-- | std/io.zig | 14 | ||||
| -rw-r--r-- | std/mem.zig | 111 | ||||
| -rw-r--r-- | std/os/child_process.zig | 18 | ||||
| -rw-r--r-- | std/os/index.zig | 5 | ||||
| -rw-r--r-- | std/os/path.zig | 2 | ||||
| -rw-r--r-- | std/rand.zig | 6 | ||||
| -rw-r--r-- | std/sort.zig | 70 | ||||
| -rw-r--r-- | std/special/compiler_rt/udivmod.zig | 2 |
13 files changed, 264 insertions, 141 deletions
diff --git a/std/buffer.zig b/std/buffer.zig index a1aa8faf9d..96abaeb762 100644 --- a/std/buffer.zig +++ b/std/buffer.zig @@ -4,6 +4,8 @@ const Allocator = mem.Allocator; const assert = debug.assert; const ArrayList = @import("array_list.zig").ArrayList; +const fmt = @import("fmt/index.zig"); + /// A buffer that allocates memory and maintains a null byte at the end. pub const Buffer = struct { list: ArrayList(u8), @@ -96,6 +98,10 @@ pub const Buffer = struct { mem.copy(u8, self.list.toSlice()[old_len..], m); } + pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void { + return fmt.format(self, append, format, args); + } + pub fn appendByte(self: &Buffer, byte: u8) -> %void { return self.appendByteNTimes(byte, 1); } diff --git a/std/build.zig b/std/build.zig index 009295c6ad..9bdc4b3076 100644 --- a/std/build.zig +++ b/std/build.zig @@ -69,8 +69,8 @@ pub const Builder = struct { used: bool, }; - const UserValue = enum { - Flag, + const UserValue = union(enum) { + Flag: void, Scalar: []const u8, List: ArrayList([]const u8), }; @@ -450,7 +450,7 @@ pub const Builder = struct { pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool { if (%%self.user_input_options.put(name, UserInputOption { .name = name, - .value = UserValue.Scalar { value }, + .value = UserValue { .Scalar = value }, .used = false, })) |*prev_value| { // option already exists @@ -462,7 +462,7 @@ pub const Builder = struct { %%list.append(value); _ = %%self.user_input_options.put(name, UserInputOption { .name = name, - .value = UserValue.List { list }, + .value = UserValue { .List = list }, .used = false, }); }, @@ -471,7 +471,7 @@ pub const Builder = struct { %%list.append(value); _ = %%self.user_input_options.put(name, UserInputOption { .name = name, - .value = UserValue.List { *list }, + .value = UserValue { .List = *list }, .used = false, }); }, @@ -487,7 +487,7 @@ pub const Builder = struct { pub fn addUserInputFlag(self: &Builder, name: []const u8) -> bool { if (%%self.user_input_options.put(name, UserInputOption { .name = name, - .value = UserValue.Flag, + .value = UserValue {.Flag = {} }, .used = false, })) |*prev_value| { switch (prev_value.value) { @@ -685,8 +685,8 @@ const CrossTarget = struct { environ: builtin.Environ, }; -const Target = enum { - Native, +const Target = union(enum) { + Native: void, Cross: CrossTarget, pub fn oFileExt(self: &const Target) -> []const u8 { @@ -844,7 +844,7 @@ pub const LibExeObjStep = struct { .kind = kind, .root_src = root_src, .name = name, - .target = Target.Native, + .target = Target { .Native = {} }, .linker_script = null, .link_libs = BufSet.init(builder.allocator), .frameworks = BufSet.init(builder.allocator), @@ -879,7 +879,7 @@ pub const LibExeObjStep = struct { .kind = kind, .version = *version, .static = static, - .target = Target.Native, + .target = Target { .Native = {} }, .cflags = ArrayList([]const u8).init(builder.allocator), .source_files = ArrayList([]const u8).init(builder.allocator), .object_files = ArrayList([]const u8).init(builder.allocator), @@ -948,8 +948,8 @@ pub const LibExeObjStep = struct { pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) { - self.target = Target.Cross { - CrossTarget { + self.target = Target { + .Cross = CrossTarget { .arch = target_arch, .os = target_os, .environ = target_environ, @@ -1186,13 +1186,13 @@ pub const LibExeObjStep = struct { Target.Native => {}, Target.Cross => |cross_target| { %%zig_args.append("--target-arch"); - %%zig_args.append(@enumTagName(cross_target.arch)); + %%zig_args.append(@tagName(cross_target.arch)); %%zig_args.append("--target-os"); - %%zig_args.append(@enumTagName(cross_target.os)); + %%zig_args.append(@tagName(cross_target.os)); %%zig_args.append("--target-environ"); - %%zig_args.append(@enumTagName(cross_target.environ)); + %%zig_args.append(@tagName(cross_target.environ)); }, } @@ -1553,7 +1553,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, } } @@ -1581,8 +1581,8 @@ pub const TestStep = struct { pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) { - self.target = Target.Cross { - CrossTarget { + self.target = Target { + .Cross = CrossTarget { .arch = target_arch, .os = target_os, .environ = target_environ, @@ -1620,13 +1620,13 @@ pub const TestStep = struct { Target.Native => {}, Target.Cross => |cross_target| { %%zig_args.append("--target-arch"); - %%zig_args.append(@enumTagName(cross_target.arch)); + %%zig_args.append(@tagName(cross_target.arch)); %%zig_args.append("--target-os"); - %%zig_args.append(@enumTagName(cross_target.os)); + %%zig_args.append(@tagName(cross_target.os)); %%zig_args.append("--target-environ"); - %%zig_args.append(@enumTagName(cross_target.environ)); + %%zig_args.append(@tagName(cross_target.environ)); }, } diff --git a/std/debug.zig b/std/debug.zig index 50322024c3..a2bea9eddd 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -280,7 +280,7 @@ const AbbrevAttr = struct { form_id: u64, }; -const FormValue = enum { +const FormValue = union(enum) { Address: u64, Block: []u8, Const: Constant, @@ -303,7 +303,7 @@ const Constant = struct { return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readInt(self.payload, u64, false); + return mem.readInt(self.payload, u64, builtin.Endian.Little); } }; @@ -475,16 +475,16 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usiz fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { const buf = %return readAllocBytes(allocator, in_stream, size); - return FormValue.Block { buf }; + return FormValue { .Block = buf }; } fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { - const block_len = %return in_stream.readVarInt(false, usize, size); + const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue { - FormValue.Const { Constant { + FormValue { .Const = Constant { .signed = signed, .payload = %return readAllocBytes(allocator, in_stream, size), }} @@ -510,7 +510,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 { fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { const buf = %return readAllocBytes(allocator, in_stream, size); - return FormValue.Ref { buf }; + return FormValue { .Ref = buf }; } fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue { @@ -520,7 +520,7 @@ fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptim fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue { return switch (form_id) { - DW.FORM_addr => FormValue.Address { %return parseFormValueTargetAddrSize(in_stream) }, + DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) }, DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), @@ -540,13 +540,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u DW.FORM_exprloc => { const size = %return readULeb128(in_stream); const buf = %return readAllocBytes(allocator, in_stream, size); - return FormValue.ExprLoc { buf }; - }, - DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 }, - DW.FORM_flag_present => FormValue.Flag { true }, - DW.FORM_sec_offset => FormValue.SecOffset { - %return parseFormValueDwarfOffsetSize(in_stream, is_64) + return FormValue { .ExprLoc = buf }; }, + DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 }, + DW.FORM_flag_present => FormValue { .Flag = true }, + DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8), DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16), @@ -557,11 +555,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u parseFormValueRefLen(allocator, in_stream, ref_len) }, - DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) }, + DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, + DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) }, - DW.FORM_string => FormValue.String { %return readStringRaw(allocator, in_stream) }, - DW.FORM_strp => FormValue.StrPtr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, + DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) }, + DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, DW.FORM_indirect => { const child_form_id = %return readULeb128(in_stream); parseFormValue(allocator, in_stream, child_form_id, is_64) @@ -671,10 +669,10 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe continue; } - const version = %return in_stream.readInt(st.elf.is_big_endian, u16); + const version = %return in_stream.readInt(st.elf.endian, u16); if (version != 2) return error.InvalidDebugInfo; - const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32); + const prologue_length = %return in_stream.readInt(st.elf.endian, u32); const prog_start_offset = (%return in_file.getPos()) + prologue_length; const minimum_instruction_length = %return in_stream.readByte(); @@ -741,7 +739,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = %return in_stream.readInt(st.elf.is_big_endian, usize); + const addr = %return in_stream.readInt(st.elf.endian, usize); prog.address = addr; }, DW.LNE_define_file => { @@ -803,7 +801,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = %return in_stream.readInt(st.elf.is_big_endian, u16); + const arg = %return in_stream.readInt(st.elf.endian, u16); prog.address += arg; }, DW.LNS_set_prologue_end => { @@ -841,13 +839,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = %return in_stream.readInt(st.elf.is_big_endian, u16); + const version = %return in_stream.readInt(st.elf.endian, u16); if (version < 2 or version > 5) return error.InvalidDebugInfo; const debug_abbrev_offset = if (is_64) { - %return in_stream.readInt(st.elf.is_big_endian, u64) + %return in_stream.readInt(st.elf.endian, u64) } else { - %return in_stream.readInt(st.elf.is_big_endian, u32) + %return in_stream.readInt(st.elf.endian, u32) }; const address_size = %return in_stream.readByte(); diff --git a/std/elf.zig b/std/elf.zig index f3f7de512f..f7be236d15 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("index.zig"); const io = std.io; const math = std.math; @@ -67,7 +68,7 @@ pub const Elf = struct { in_file: &io.File, auto_close_stream: bool, is_64: bool, - is_big_endian: bool, + endian: builtin.Endian, file_type: FileType, arch: Arch, entry_addr: u64, @@ -105,9 +106,9 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.is_big_endian = switch (%return in.readByte()) { - 1 => false, - 2 => true, + elf.endian = switch (%return in.readByte()) { + 1 => builtin.Endian.Little, + 2 => builtin.Endian.Big, else => return error.InvalidFormat, }; @@ -117,7 +118,7 @@ pub const Elf = struct { // skip over padding %return elf.in_file.seekForward(9); - elf.file_type = switch (%return in.readInt(elf.is_big_endian, u16)) { + elf.file_type = switch (%return in.readInt(elf.endian, u16)) { 1 => FileType.Relocatable, 2 => FileType.Executable, 3 => FileType.Shared, @@ -125,7 +126,7 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.arch = switch (%return in.readInt(elf.is_big_endian, u16)) { + elf.arch = switch (%return in.readInt(elf.endian, u16)) { 0x02 => Arch.Sparc, 0x03 => Arch.x86, 0x08 => Arch.Mips, @@ -138,34 +139,34 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - const elf_version = %return in.readInt(elf.is_big_endian, u32); + const elf_version = %return in.readInt(elf.endian, u32); if (elf_version != 1) return error.InvalidFormat; if (elf.is_64) { - elf.entry_addr = %return in.readInt(elf.is_big_endian, u64); - elf.program_header_offset = %return in.readInt(elf.is_big_endian, u64); - elf.section_header_offset = %return in.readInt(elf.is_big_endian, u64); + elf.entry_addr = %return in.readInt(elf.endian, u64); + elf.program_header_offset = %return in.readInt(elf.endian, u64); + elf.section_header_offset = %return in.readInt(elf.endian, u64); } else { - elf.entry_addr = u64(%return in.readInt(elf.is_big_endian, u32)); - elf.program_header_offset = u64(%return in.readInt(elf.is_big_endian, u32)); - elf.section_header_offset = u64(%return in.readInt(elf.is_big_endian, u32)); + elf.entry_addr = u64(%return in.readInt(elf.endian, u32)); + elf.program_header_offset = u64(%return in.readInt(elf.endian, u32)); + elf.section_header_offset = u64(%return in.readInt(elf.endian, u32)); } // skip over flags %return elf.in_file.seekForward(4); - const header_size = %return in.readInt(elf.is_big_endian, u16); + const header_size = %return in.readInt(elf.endian, u16); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { return error.InvalidFormat; } - const ph_entry_size = %return in.readInt(elf.is_big_endian, u16); - const ph_entry_count = %return in.readInt(elf.is_big_endian, u16); - const sh_entry_size = %return in.readInt(elf.is_big_endian, u16); - const sh_entry_count = %return in.readInt(elf.is_big_endian, u16); - elf.string_section_index = u64(%return in.readInt(elf.is_big_endian, u16)); + const ph_entry_size = %return in.readInt(elf.endian, u16); + const ph_entry_count = %return in.readInt(elf.endian, u16); + const sh_entry_size = %return in.readInt(elf.endian, u16); + const sh_entry_count = %return in.readInt(elf.endian, u16); + elf.string_section_index = u64(%return in.readInt(elf.endian, u16)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -188,32 +189,32 @@ pub const Elf = struct { if (sh_entry_size != 64) return error.InvalidFormat; for (elf.section_headers) |*section| { - section.name = %return in.readInt(elf.is_big_endian, u32); - section.sh_type = %return in.readInt(elf.is_big_endian, u32); - section.flags = %return in.readInt(elf.is_big_endian, u64); - section.addr = %return in.readInt(elf.is_big_endian, u64); - section.offset = %return in.readInt(elf.is_big_endian, u64); - section.size = %return in.readInt(elf.is_big_endian, u64); - section.link = %return in.readInt(elf.is_big_endian, u32); - section.info = %return in.readInt(elf.is_big_endian, u32); - section.addr_align = %return in.readInt(elf.is_big_endian, u64); - section.ent_size = %return in.readInt(elf.is_big_endian, u64); + section.name = %return in.readInt(elf.endian, u32); + section.sh_type = %return in.readInt(elf.endian, u32); + section.flags = %return in.readInt(elf.endian, u64); + section.addr = %return in.readInt(elf.endian, u64); + section.offset = %return in.readInt(elf.endian, u64); + section.size = %return in.readInt(elf.endian, u64); + section.link = %return in.readInt(elf.endian, u32); + section.info = %return in.readInt(elf.endian, u32); + section.addr_align = %return in.readInt(elf.endian, u64); + section.ent_size = %return in.readInt(elf.endian, u64); } } else { if (sh_entry_size != 40) return error.InvalidFormat; for (elf.section_headers) |*section| { // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? - section.name = %return in.readInt(elf.is_big_endian, u32); - section.sh_type = %return in.readInt(elf.is_big_endian, u32); - section.flags = u64(%return in.readInt(elf.is_big_endian, u32)); - section.addr = u64(%return in.readInt(elf.is_big_endian, u32)); - section.offset = u64(%return in.readInt(elf.is_big_endian, u32)); - section.size = u64(%return in.readInt(elf.is_big_endian, u32)); - section.link = %return in.readInt(elf.is_big_endian, u32); - section.info = %return in.readInt(elf.is_big_endian, u32); - section.addr_align = u64(%return in.readInt(elf.is_big_endian, u32)); - section.ent_size = u64(%return in.readInt(elf.is_big_endian, u32)); + section.name = %return in.readInt(elf.endian, u32); + section.sh_type = %return in.readInt(elf.endian, u32); + section.flags = u64(%return in.readInt(elf.endian, u32)); + section.addr = u64(%return in.readInt(elf.endian, u32)); + section.offset = u64(%return in.readInt(elf.endian, u32)); + section.size = u64(%return in.readInt(elf.endian, u32)); + section.link = %return in.readInt(elf.endian, u32); + section.info = %return in.readInt(elf.endian, u32); + section.addr_align = u64(%return in.readInt(elf.endian, u32)); + section.ent_size = u64(%return in.readInt(elf.endian, u32)); } } diff --git a/std/endian.zig b/std/endian.zig index 8ae8ae22f8..2dc6b8d34e 100644 --- a/std/endian.zig +++ b/std/endian.zig @@ -9,8 +9,8 @@ pub fn swapIfBe(comptime T: type, x: T) -> T { swapIf(true, T, x) } -pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T { - if (builtin.is_big_endian == is_be) swap(T, x) else x +pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { + if (builtin.endian == endian) swap(T, x) else x } pub fn swap(comptime T: type, x: T) -> T { diff --git a/std/io.zig b/std/io.zig index d570927488..c86ebed326 100644 --- a/std/io.zig +++ b/std/io.zig @@ -259,7 +259,7 @@ pub const File = struct { if (err > 0) { return switch (err) { system.EBADF => error.BadFd, - system.ENOMEM => error.OutOfMemory, + system.ENOMEM => error.SystemResources, else => os.unexpectedErrorPosix(err), } } @@ -441,26 +441,26 @@ pub const InStream = struct { } pub fn readIntLe(self: &InStream, comptime T: type) -> %T { - return self.readInt(false, T); + return self.readInt(builtin.Endian.Little, T); } pub fn readIntBe(self: &InStream, comptime T: type) -> %T { - return self.readInt(true, T); + return self.readInt(builtin.Endian.Big, T); } - pub fn readInt(self: &InStream, is_be: bool, comptime T: type) -> %T { + pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) -> %T { var bytes: [@sizeOf(T)]u8 = undefined; %return self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, is_be); + return mem.readInt(bytes, T, endian); } - pub fn readVarInt(self: &InStream, is_be: bool, comptime T: type, size: usize) -> %T { + pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) -> %T { assert(size <= @sizeOf(T)); assert(size <= 8); var input_buf: [8]u8 = undefined; const input_slice = input_buf[0..size]; %return self.readNoEof(input_slice); - return mem.readInt(input_slice, T, is_be); + return mem.readInt(input_slice, T, endian); } diff --git a/std/mem.zig b/std/mem.zig index 3cfdb25b35..815e122812 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -1,6 +1,7 @@ const debug = @import("debug.zig"); const assert = debug.assert; const math = @import("math/index.zig"); +const builtin = @import("builtin"); pub const Cmp = math.Cmp; @@ -180,43 +181,78 @@ test "mem.indexOf" { /// Reads an integer from memory with size equal to bytes.len. /// T specifies the return type, which must be large enough to store /// the result. -pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T { +/// See also ::readIntBE or ::readIntLE. +pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) -> T { if (T.bit_count == 8) { return bytes[0]; } var result: T = 0; - if (big_endian) { - for (bytes) |b| { - result = (result << 8) | b; - } - } else { - const ShiftType = math.Log2Int(T); - for (bytes) |b, index| { - result = result | (T(b) << ShiftType(index * 8)); - } + switch (endian) { + builtin.Endian.Big => { + for (bytes) |b| { + result = (result << 8) | b; + } + }, + builtin.Endian.Little => { + const ShiftType = math.Log2Int(T); + for (bytes) |b, index| { + result = result | (T(b) << ShiftType(index * 8)); + } + }, } return result; } +/// Reads a big-endian int of type T from bytes. +/// bytes.len must be exactly @sizeOf(T). +pub fn readIntBE(comptime T: type, bytes: []const u8) -> T { + if (T.is_signed) { + return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes)); + } + assert(bytes.len == @sizeOf(T)); + var result: T = 0; + {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) { + result = (result << 8) | T(bytes[i]); + }} + return result; +} + +/// Reads a little-endian int of type T from bytes. +/// bytes.len must be exactly @sizeOf(T). +pub fn readIntLE(comptime T: type, bytes: []const u8) -> T { + if (T.is_signed) { + return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes)); + } + assert(bytes.len == @sizeOf(T)); + var result: T = 0; + {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) { + result |= T(bytes[i]) << i * 8; + }} + return result; +} + /// Writes an integer to memory with size equal to bytes.len. Pads with zeroes /// to fill the entire buffer provided. /// value must be an integer. -pub fn writeInt(buf: []u8, value: var, big_endian: bool) { +pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) { const uint = @IntType(false, @typeOf(value).bit_count); var bits = @truncate(uint, value); - if (big_endian) { - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - } else { - for (buf) |*b| { - *b = @truncate(u8, bits); - bits >>= 8; - } + switch (endian) { + builtin.Endian.Big => { + var index: usize = buf.len; + while (index != 0) { + index -= 1; + + buf[index] = @truncate(u8, bits); + bits >>= 8; + } + }, + builtin.Endian.Little => { + for (buf) |*b| { + *b = @truncate(u8, bits); + bits >>= 8; + } + }, } assert(bits == 0); } @@ -348,19 +384,30 @@ test "testReadInt" { fn testReadIntImpl() { { const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 }; - assert(readInt(bytes, u32, true) == 0x12345678); - assert(readInt(bytes, u32, false) == 0x78563412); + assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); + assert(readIntBE(u32, bytes) == 0x12345678); + assert(readIntBE(i32, bytes) == 0x12345678); + assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); + assert(readIntLE(u32, bytes) == 0x78563412); + assert(readIntLE(i32, bytes) == 0x78563412); } { const buf = []u8{0x00, 0x00, 0x12, 0x34}; - const answer = readInt(buf, u64, true); + const answer = readInt(buf, u64, builtin.Endian.Big); assert(answer == 0x00001234); } { const buf = []u8{0x12, 0x34, 0x00, 0x00}; - const answer = readInt(buf, u64, false); + const answer = readInt(buf, u64, builtin.Endian.Little); assert(answer == 0x00003412); } + { + const bytes = []u8{0xff, 0xfe}; + assert(readIntBE(u16, bytes) == 0xfffe); + assert(readIntBE(i16, bytes) == -0x0002); + assert(readIntLE(u16, bytes) == 0xfeff); + assert(readIntLE(i16, bytes) == -0x0101); + } } test "testWriteInt" { @@ -370,16 +417,16 @@ test "testWriteInt" { fn testWriteIntImpl() { var bytes: [4]u8 = undefined; - writeInt(bytes[0..], u32(0x12345678), true); + writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); - writeInt(bytes[0..], u32(0x78563412), false); + writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); - writeInt(bytes[0..], u16(0x1234), true); + writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 })); - writeInt(bytes[0..], u16(0x1234), false); + writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 })); } diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 005d9772e4..75a2dcf24d 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -58,7 +58,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 Term = enum { + pub const Term = union(enum) { Exited: i32, Signal: i32, Stopped: i32, @@ -213,9 +213,9 @@ pub const ChildProcess = struct { self.term = (%Term)({ var exit_code: windows.DWORD = undefined; if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { - Term.Unknown{0} + Term { .Unknown = 0 } } else { - Term.Exited {@bitCast(i32, exit_code)} + Term { .Exited = @bitCast(i32, exit_code)} } }); @@ -281,13 +281,13 @@ 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 } }; } @@ -722,14 +722,14 @@ const ErrInt = @IntType(false, @sizeOf(error) * 8); fn writeIntFd(fd: i32, value: ErrInt) -> %void { var bytes: [@sizeOf(ErrInt)]u8 = undefined; - mem.writeInt(bytes[0..], value, true); + mem.writeInt(bytes[0..], value, builtin.endian); os.posixWrite(fd, bytes[0..]) %% return error.SystemResources; } fn readIntFd(fd: i32) -> %ErrInt { var bytes: [@sizeOf(ErrInt)]u8 = undefined; os.posixRead(fd, bytes[0..]) %% return error.SystemResources; - return mem.readInt(bytes[0..], ErrInt, true); + return mem.readInt(bytes[0..], ErrInt, builtin.endian); } extern fn sigchld_handler(_: i32) { diff --git a/std/os/index.zig b/std/os/index.zig index e6a5fc4d15..361750aedc 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -939,6 +939,7 @@ start_over: } pub const Dir = struct { + // See man getdents fd: i32, allocator: &Allocator, buf: []u8, @@ -981,7 +982,7 @@ pub const Dir = struct { pub fn close(self: &Dir) { self.allocator.free(self.buf); - close(self.fd); + os.close(self.fd); } /// Memory such as file names referenced in this returned entry becomes invalid @@ -1013,7 +1014,7 @@ pub const Dir = struct { break; } } - const linux_entry = @ptrCast(&LinuxEntry, &self.buf[self.index]); + const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); const next_index = self.index + linux_entry.d_reclen; self.index = next_index; diff --git a/std/os/path.zig b/std/os/path.zig index a372b5b077..3fd7b5e2db 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1016,7 +1016,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { return os.readLink(allocator, proc_path); }, - else => @compileError("TODO implement os.path.real for " ++ @enumTagName(builtin.os)), + else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)), } } diff --git a/std/rand.zig b/std/rand.zig index d7798df3da..09e0c8ac78 100644 --- a/std/rand.zig +++ b/std/rand.zig @@ -50,12 +50,12 @@ pub const Rand = struct { pub fn fillBytes(r: &Rand, buf: []u8) { var bytes_left = buf.len; while (bytes_left >= @sizeOf(usize)) { - mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), false); + mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little); bytes_left -= @sizeOf(usize); } if (bytes_left > 0) { var rand_val_array: [@sizeOf(usize)]u8 = undefined; - mem.writeInt(rand_val_array[0..], r.rng.get(), false); + mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little); while (bytes_left > 0) { buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left]; bytes_left -= 1; @@ -98,7 +98,7 @@ pub const Rand = struct { while (true) { r.fillBytes(rand_val_array[0..]); - const rand_val = mem.readInt(rand_val_array, T, false); + const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little); if (rand_val < upper_bound) { return start + (rand_val % total_range); } diff --git a/std/sort.zig b/std/sort.zig index 1d7ca507ee..d02d685e07 100644 --- a/std/sort.zig +++ b/std/sort.zig @@ -4,6 +4,19 @@ const math = @import("math/index.zig"); pub const Cmp = math.Cmp; +/// Stable sort using O(1) space. Currently implemented as insertion sort. +pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { + {var i: usize = 1; while (i < array.len) : (i += 1) { + const x = array[i]; + var j: usize = i; + while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) { + array[j] = array[j - 1]; + } + array[j] = x; + }} +} + +/// Unstable sort using O(n) stack space. Currently implemented as quicksort. pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { if (array.len > 0) { quicksort(T, array, 0, array.len - 1, cmp); @@ -58,6 +71,63 @@ fn reverse(was: Cmp) -> Cmp { // --------------------------------------- // tests +test "stable sort" { + testStableSort(); + // TODO: uncomment this after https://github.com/zig-lang/zig/issues/639 + //comptime testStableSort(); +} +fn testStableSort() { + 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}, + }, + []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| { + sort_stable(IdAndValue, (*case)[0..], cmpByValue); + for (*case) |item, i| { + assert(item.id == expected[i].id); + assert(item.value == expected[i].value); + } + } +} +const IdAndValue = struct { + id: i32, + value: i32, +}; +fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp { + return i32asc(a.value, b.value); +} + test "testSort" { const u8cases = [][]const []const u8 { [][]const u8{"", ""}, diff --git a/std/special/compiler_rt/udivmod.zig b/std/special/compiler_rt/udivmod.zig index c6a2babbf6..7e09c3d4d7 100644 --- a/std/special/compiler_rt/udivmod.zig +++ b/std/special/compiler_rt/udivmod.zig @@ -1,7 +1,7 @@ const builtin = @import("builtin"); const is_test = builtin.is_test; -const low = if (builtin.is_big_endian) 1 else 0; +const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 }; const high = 1 - low; pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) -> DoubleInt { |
