diff --git a/doc/langref.html.in b/doc/langref.html.in index a1903331a4..f820a05b69 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5312,6 +5312,15 @@ comptime {

{#header_close#} + {#header_open|@bswap#} +
{#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

+

+ Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, + and converts a little endian integer to a big endian integer. +

+ {#header_close#} + {#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}

diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 66264666bc..b4eb1c292a 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -15,7 +15,7 @@ pub fn main() !void { std.debug.warn("unable to seed random number generator: {}", err); return err; }; - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = std.mem.readIntNative(u64, &seed_bytes); var prng = std.rand.DefaultPrng.init(seed); const answer = prng.random.range(u8, 0, 100) + 1; diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index a8c3e13e33..0594cbd749 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -55,7 +55,7 @@ pub const ZigCompiler = struct { var seed_bytes: [@sizeOf(u64)]u8 = undefined; try std.os.getRandomBytes(seed_bytes[0..]); - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = mem.readIntNative(u64, &seed_bytes); return ZigCompiler{ .loop = loop, diff --git a/src/all_types.hpp b/src/all_types.hpp index f7ada09a57..83b7e8495f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,7 @@ enum BuiltinFnId { BuiltinFnIdErrorReturnTrace, BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, + BuiltinFnIdBswap, }; struct BuiltinFnEntry { @@ -1487,6 +1488,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdFloor, ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, + ZigLLVMFnIdBswap, }; enum AddSubMul { @@ -1516,6 +1518,9 @@ struct ZigLLVMFnKey { uint32_t bit_count; bool is_signed; } overflow_arithmetic; + struct { + uint32_t bit_count; + } bswap; } data; }; @@ -2158,6 +2163,7 @@ enum IrInstructionId { IrInstructionIdMergeErrRetTraces, IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, + IrInstructionIdBswap, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3251,6 +3257,13 @@ struct IrInstructionCheckRuntimeScope { IrInstruction *is_comptime; }; +struct IrInstructionBswap { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 2f4b173c5f..46686ce772 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -401,7 +401,8 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { } ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) + bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, + uint32_t bit_offset_in_host, uint32_t host_int_bytes) { assert(!type_is_invalid(child_type)); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); @@ -6110,6 +6111,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; case ZigLLVMFnIdSqrt: return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; + case ZigLLVMFnIdBswap: + return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6128,6 +6131,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.clz.bit_count == b.data.clz.bit_count; case ZigLLVMFnIdPopCount: return a.data.pop_count.bit_count == b.data.pop_count.bit_count; + case ZigLLVMFnIdBswap: + return a.data.bswap.bit_count == b.data.bswap.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/codegen.cpp b/src/codegen.cpp index 1033ed8120..08dd11800a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3814,6 +3814,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdPopCount; key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBswap) { + fn_name = "bswap"; + n_args = 1; + key.id = ZigLLVMFnIdBswap; + key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5098,6 +5103,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + if (int_type->data.integral.bit_count % 16 == 0) { + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); + } + // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate + ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, + int_type->data.integral.bit_count + 8); + // aabbcc + LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, ""); + // 00aabbcc + LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); + LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); + // ccbbaa00 + LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, + LLVMConstInt(extended_type->type_ref, 8, false), ""); + // 00ccbbaa + return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5363,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); } zig_unreachable(); } @@ -6757,6 +6787,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1); create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); + create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 68a0b7f6f6..dc87f040bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -856,6 +856,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { return IrInstructionIdSqrt; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { + return IrInstructionIdBswap; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2705,6 +2709,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc return &instruction->base; } +static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBswap *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -4689,6 +4704,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBswap: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -13674,18 +13704,55 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, return ErrorNone; } - if (dst_size > src_size) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; + if (dst_size <= src_size) { + Buf buf = BUF_INIT; + buf_resize(&buf, src_size); + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); - return ErrorNone; + switch (ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", + dst_size, buf_ptr(&pointee->type->name), src_size)); + return ErrorSemanticAnalyzeFail; + } + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + size_t elem_size = src_size; + src_size = elem_size * + (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + if (dst_size > src_size) { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", + dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, + src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; + } + case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialDiscard: + case ConstPtrSpecialHardCodedAddr: + case ConstPtrSpecialFunction: + zig_panic("TODO"); + } + zig_unreachable(); } static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { @@ -18054,6 +18121,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + if (src_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); @@ -20299,6 +20372,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(child_type)) { + align_bytes = 0; + } } else { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20898,6 +20974,63 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS return result; } +static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + if (int_type->data.integral.bit_count % 8 != 0) { + ir_add_error(ira, instruction->type, + buf_sprintf("@bswap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", + buf_ptr(&int_type->name), int_type->data.integral.bit_count)); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (int_type->data.integral.bit_count == 8) { + return casted_op; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t buf_size = int_type->data.integral.bit_count / 8; + uint8_t *buf = allocate_nonzero(buf_size); + bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); + bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, + int_type->data.integral.is_signed); + return result; + } + + IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; IrInstruction *target = instruction->target->child; @@ -21233,6 +21366,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21454,6 +21589,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdBswap: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 13c06e4e2d..e09b0073eb 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1323,6 +1323,18 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { + fprintf(irp->f, "@bswap("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1736,6 +1748,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSqrt: ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); break; + case IrInstructionIdBswap: + ir_print_bswap(irp, (IrInstructionBswap *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/std/coff.zig b/std/coff.zig index 6a1aa34b46..53bd2a4b7a 100644 --- a/std/coff.zig +++ b/std/coff.zig @@ -51,7 +51,7 @@ pub const Coff = struct { // Seek to PE File Header (coff header) try self.in_file.seekTo(pe_pointer_offset); - const pe_magic_offset = try in.readIntLe(u32); + const pe_magic_offset = try in.readIntLittle(u32); try self.in_file.seekTo(pe_magic_offset); var pe_header_magic: [4]u8 = undefined; @@ -60,13 +60,13 @@ pub const Coff = struct { return error.InvalidPEHeader; self.coff_header = CoffHeader{ - .machine = try in.readIntLe(u16), - .number_of_sections = try in.readIntLe(u16), - .timedate_stamp = try in.readIntLe(u32), - .pointer_to_symbol_table = try in.readIntLe(u32), - .number_of_symbols = try in.readIntLe(u32), - .size_of_optional_header = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u16), + .machine = try in.readIntLittle(u16), + .number_of_sections = try in.readIntLittle(u16), + .timedate_stamp = try in.readIntLittle(u32), + .pointer_to_symbol_table = try in.readIntLittle(u32), + .number_of_symbols = try in.readIntLittle(u32), + .size_of_optional_header = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u16), }; switch (self.coff_header.machine) { @@ -79,7 +79,7 @@ pub const Coff = struct { fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void { const in = &file_stream.stream; - self.pe_header.magic = try in.readIntLe(u16); + self.pe_header.magic = try in.readIntLittle(u16); // For now we're only interested in finding the reference to the .pdb, // so we'll skip most of this header, which size is different in 32 // 64 bits by the way. @@ -93,14 +93,14 @@ pub const Coff = struct { try self.in_file.seekForward(skip_size); - const number_of_rva_and_sizes = try in.readIntLe(u32); + const number_of_rva_and_sizes = try in.readIntLittle(u32); if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return error.InvalidPEHeader; for (self.pe_header.data_directory) |*data_dir| { data_dir.* = OptionalHeader.DataDirectory{ - .virtual_address = try in.readIntLe(u32), - .size = try in.readIntLe(u32), + .virtual_address = try in.readIntLittle(u32), + .size = try in.readIntLittle(u32), }; } } @@ -124,7 +124,7 @@ pub const Coff = struct { if (!mem.eql(u8, cv_signature, "RSDS")) return error.InvalidPEMagic; try in.readNoEof(self.guid[0..]); - self.age = try in.readIntLe(u32); + self.age = try in.readIntLittle(u32); // Finally read the null-terminated string. var byte = try in.readByte(); @@ -157,15 +157,15 @@ pub const Coff = struct { try self.sections.append(Section{ .header = SectionHeader{ .name = name, - .misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) }, - .virtual_address = try in.readIntLe(u32), - .size_of_raw_data = try in.readIntLe(u32), - .pointer_to_raw_data = try in.readIntLe(u32), - .pointer_to_relocations = try in.readIntLe(u32), - .pointer_to_line_numbers = try in.readIntLe(u32), - .number_of_relocations = try in.readIntLe(u16), - .number_of_line_numbers = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u32), + .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) }, + .virtual_address = try in.readIntLittle(u32), + .size_of_raw_data = try in.readIntLittle(u32), + .pointer_to_raw_data = try in.readIntLittle(u32), + .pointer_to_relocations = try in.readIntLittle(u32), + .pointer_to_line_numbers = try in.readIntLittle(u32), + .number_of_relocations = try in.readIntLittle(u16), + .number_of_line_numbers = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u32), }, }); } diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index dc68d806d2..e3de65916a 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } @@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]); + // TODO https://github.com/ziglang/zig/issues/863 + r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); } var k: usize = 0; @@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); } } @@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); } var k: usize = 0; diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 059bc82088..5ec1e79756 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); } } @@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = []u32{ - mem.readIntLE(u32, c[0..4]), - mem.readIntLE(u32, c[4..8]), - mem.readIntLE(u32, c[8..12]), - mem.readIntLE(u32, c[12..16]), + mem.readIntSliceLittle(u32, c[0..4]), + mem.readIntSliceLittle(u32, c[4..8]), + mem.readIntSliceLittle(u32, c[8..12]), + mem.readIntSliceLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntLE(u32, nonce[0..4]); - c[2] = mem.readIntLE(u32, nonce[4..8]); - c[3] = mem.readIntLE(u32, nonce[8..12]); + c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLE(u32, nonce[0..4]); - c[3] = mem.readIntLE(u32, nonce[4..8]); + c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); const big_block = (block_size << 32); diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 8663fa751f..994a7fa25c 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -112,7 +112,8 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index a5d9fcdf57..0d7a4d672d 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -6,8 +6,8 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff; + ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc; + ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little); + ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little); - ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little); - ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little); - ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little); + ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,10 +210,11 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - writeInt(out[0..], @truncate(u32, uu0), Endian.Little); - writeInt(out[4..], @truncate(u32, uu1), Endian.Little); - writeInt(out[8..], @truncate(u32, uu2), Endian.Little); - writeInt(out[12..], @truncate(u32, uu3), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); + writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); + writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); + writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index 1cb0b17434..d5aab8f33f 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -109,7 +109,8 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 7e9749364b..0476a3a25e 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } @@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); } } diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig index 881370e686..e686e1337c 100644 --- a/std/crypto/sha3.zig +++ b/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = []const u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); } comptime var x: usize = 0; @@ -167,7 +167,8 @@ 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); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); } } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index 281813b457..daccb56808 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readInt(s[0..4], u32, Endian.Little); - t[1] = readInt(s[4..7], u32, Endian.Little) << 6; - t[2] = readInt(s[7..10], u32, Endian.Little) << 5; - t[3] = readInt(s[10..13], u32, Endian.Little) << 3; - t[4] = readInt(s[13..16], u32, Endian.Little) << 2; - t[5] = readInt(s[16..20], u32, Endian.Little); - t[6] = readInt(s[20..23], u32, Endian.Little) << 7; - t[7] = readInt(s[23..26], u32, Endian.Little) << 5; - t[8] = readInt(s[26..29], u32, Endian.Little) << 4; - t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2; + t[0] = readIntSliceLittle(u32, s[0..4]); + t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6; + t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5; + t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3; + t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2; + t[5] = readIntSliceLittle(u32, s[16..20]); + t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7; + t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5; + t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4; + t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,14 +544,15 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little); - writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); - writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); - writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); - writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); - writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); - writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); - writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/std/debug/index.zig b/std/debug/index.zig index 4a96e9d259..3967e5a8be 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -523,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void { const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo; - const signature = try modi.stream.readIntLe(u32); + const signature = try modi.stream.readIntLittle(u32); if (signature != 4) return error.InvalidDebugInfo; @@ -757,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { try di.pdb.openFile(di.coff, path); var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo; - const version = try pdb_stream.stream.readIntLe(u32); - const signature = try pdb_stream.stream.readIntLe(u32); - const age = try pdb_stream.stream.readIntLe(u32); + const version = try pdb_stream.stream.readIntLittle(u32); + const signature = try pdb_stream.stream.readIntLittle(u32); + const age = try pdb_stream.stream.readIntLittle(u32); var guid: [16]u8 = undefined; try pdb_stream.stream.readNoEof(guid[0..]); if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age) @@ -767,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { // We validated the executable and pdb match. const string_table_index = str_tab_index: { - const name_bytes_len = try pdb_stream.stream.readIntLe(u32); + const name_bytes_len = try pdb_stream.stream.readIntLittle(u32); const name_bytes = try allocator.alloc(u8, name_bytes_len); try pdb_stream.stream.readNoEof(name_bytes); @@ -797,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { }; const bucket_list = try allocator.alloc(Bucket, present.len); for (present) |_| { - const name_offset = try pdb_stream.stream.readIntLe(u32); - const name_index = try pdb_stream.stream.readIntLe(u32); + const name_offset = try pdb_stream.stream.readIntLittle(u32); + const name_index = try pdb_stream.stream.readIntLittle(u32); const name = mem.toSlice(u8, name_bytes.ptr + name_offset); if (mem.eql(u8, name, "/names")) { break :str_tab_index name_index; @@ -859,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator); var sect_cont_offset: usize = 0; if (section_contrib_size != 0) { - const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32)); + const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32)); if (ver != pdb.SectionContrSubstreamVersion.Ver60) return error.InvalidDebugInfo; sect_cont_offset += @sizeOf(u32); @@ -879,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { } fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { - const num_words = try stream.readIntLe(u32); + const num_words = try stream.readIntLittle(u32); var word_i: usize = 0; var list = ArrayList(usize).init(allocator); while (word_i != num_words) : (word_i += 1) { - const word = try stream.readIntLe(u32); + const word = try stream.readIntLittle(u32); var bit_i: u5 = 0; while (true) : (bit_i += 1) { if (word & (u32(1) << bit_i) != 0) { @@ -1200,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readInt(self.payload, u64, builtin.Endian.Little); + return mem.readIntSliceLittle(u64, self.payload); } }; @@ -1381,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize } fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); + const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } @@ -1395,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo } fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32)); + return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32)); } fn parseFormValueTargetAddrSize(in_stream: var) !u64 { - return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable; + return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable; } fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { @@ -1408,7 +1408,7 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) } fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue { - const block_len = try in_stream.readIntLe(T); + const block_len = try in_stream.readIntLittle(T); return parseFormValueRefLen(allocator, in_stream, block_len); } @@ -1450,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }, DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) }, + DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) }, DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) }, DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, @@ -1747,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr continue; } - const version = try di.dwarf_in_stream.readInt(di.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; const minimum_instruction_length = try di.dwarf_in_stream.readByte(); @@ -1820,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(di.endian, usize); + const addr = try di.dwarf_in_stream.readInt(usize, di.endian); prog.address = addr; }, DW.LNE_define_file => { @@ -1882,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(di.endian, u16); + const arg = try di.dwarf_in_stream.readInt(u16, di.endian); prog.address += arg; }, DW.LNS_set_prologue_end => {}, @@ -1914,10 +1914,10 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = try di.dwarf_in_stream.readInt(di.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); const address_size = try di.dwarf_in_stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; @@ -1978,8 +1978,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { if (di.debug_ranges) |debug_ranges| { try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); while (true) { - const begin_addr = try di.dwarf_in_stream.readIntLe(usize); - const end_addr = try di.dwarf_in_stream.readIntLe(usize); + const begin_addr = try di.dwarf_in_stream.readIntLittle(usize); + const end_addr = try di.dwarf_in_stream.readIntLittle(usize); if (begin_addr == 0 and end_addr == 0) { break; } @@ -2001,7 +2001,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { } fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { - const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian); + // TODO https://github.com/ziglang/zig/issues/863 + const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian); ptr.* += @sizeOf(T); return result; } @@ -2017,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 { } fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { - const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]); + // TODO this code can be improved with https://github.com/ziglang/zig/issues/863 + const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { ptr.* += 4; - const result = mem.readIntLE(u64, ptr.*[0..8]); + const result = mem.readIntSliceLittle(u64, ptr.*[0..8]); ptr.* += 8; return result; } else { @@ -2084,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 { } fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { - const first_32_bits = try in_stream.readIntLe(u32); + const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { - return in_stream.readIntLe(u64); + return in_stream.readIntLittle(u64); } else { if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; return u64(first_32_bits); diff --git a/std/elf.zig b/std/elf.zig index cf7c29b1e5..6a564c3283 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -412,7 +412,7 @@ pub const Elf = struct { // skip over padding try seekable_stream.seekForward(9); - elf.file_type = switch (try in.readInt(elf.endian, u16)) { + elf.file_type = switch (try in.readInt(u16, elf.endian)) { 1 => FileType.Relocatable, 2 => FileType.Executable, 3 => FileType.Shared, @@ -420,7 +420,7 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.arch = switch (try in.readInt(elf.endian, u16)) { + elf.arch = switch (try in.readInt(u16, elf.endian)) { 0x02 => Arch.Sparc, 0x03 => Arch.x86, 0x08 => Arch.Mips, @@ -433,32 +433,32 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - const elf_version = try in.readInt(elf.endian, u32); + const elf_version = try in.readInt(u32, elf.endian); if (elf_version != 1) return error.InvalidFormat; if (elf.is_64) { - elf.entry_addr = try in.readInt(elf.endian, u64); - elf.program_header_offset = try in.readInt(elf.endian, u64); - elf.section_header_offset = try in.readInt(elf.endian, u64); + elf.entry_addr = try in.readInt(u64, elf.endian); + elf.program_header_offset = try in.readInt(u64, elf.endian); + elf.section_header_offset = try in.readInt(u64, elf.endian); } else { - elf.entry_addr = u64(try in.readInt(elf.endian, u32)); - elf.program_header_offset = u64(try in.readInt(elf.endian, u32)); - elf.section_header_offset = u64(try in.readInt(elf.endian, u32)); + elf.entry_addr = u64(try in.readInt(u32, elf.endian)); + elf.program_header_offset = u64(try in.readInt(u32, elf.endian)); + elf.section_header_offset = u64(try in.readInt(u32, elf.endian)); } // skip over flags try seekable_stream.seekForward(4); - const header_size = try in.readInt(elf.endian, u16); + const header_size = try in.readInt(u16, elf.endian); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { return error.InvalidFormat; } - const ph_entry_size = try in.readInt(elf.endian, u16); - const ph_entry_count = try in.readInt(elf.endian, u16); - const sh_entry_size = try in.readInt(elf.endian, u16); - const sh_entry_count = try in.readInt(elf.endian, u16); - elf.string_section_index = u64(try in.readInt(elf.endian, u16)); + const ph_entry_size = try in.readInt(u16, elf.endian); + const ph_entry_count = try in.readInt(u16, elf.endian); + const sh_entry_size = try in.readInt(u16, elf.endian); + const sh_entry_count = try in.readInt(u16, elf.endian); + elf.string_section_index = u64(try in.readInt(u16, elf.endian)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -481,32 +481,32 @@ pub const Elf = struct { if (sh_entry_size != 64) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = try in.readInt(elf.endian, u64); - elf_section.addr = try in.readInt(elf.endian, u64); - elf_section.offset = try in.readInt(elf.endian, u64); - elf_section.size = try in.readInt(elf.endian, u64); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = try in.readInt(elf.endian, u64); - elf_section.ent_size = try in.readInt(elf.endian, u64); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = try in.readInt(u64, elf.endian); + elf_section.addr = try in.readInt(u64, elf.endian); + elf_section.offset = try in.readInt(u64, elf.endian); + elf_section.size = try in.readInt(u64, elf.endian); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = try in.readInt(u64, elf.endian); + elf_section.ent_size = try in.readInt(u64, elf.endian); } } else { if (sh_entry_size != 40) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = u64(try in.readInt(elf.endian, u32)); - elf_section.addr = u64(try in.readInt(elf.endian, u32)); - elf_section.offset = u64(try in.readInt(elf.endian, u32)); - elf_section.size = u64(try in.readInt(elf.endian, u32)); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = u64(try in.readInt(elf.endian, u32)); - elf_section.ent_size = u64(try in.readInt(elf.endian, u32)); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = u64(try in.readInt(u32, elf.endian)); + elf_section.addr = u64(try in.readInt(u32, elf.endian)); + elf_section.offset = u64(try in.readInt(u32, elf.endian)); + elf_section.size = u64(try in.readInt(u32, elf.endian)); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = u64(try in.readInt(u32, elf.endian)); + elf_section.ent_size = u64(try in.readInt(u32, elf.endian)); } } diff --git a/std/event/io.zig b/std/event/io.zig index bb377a3b68..b11550f7aa 100644 --- a/std/event/io.zig +++ b/std/event/io.zig @@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type { if (amt_read < buf.len) return error.EndOfStream; } - pub async fn readIntLe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Little, T) catch unreachable); + pub async fn readIntLittle(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readIntLittle(T, &bytes); } pub async fn readIntBe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Big, T) catch unreachable); - } - - pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try await (async self.readNoEof(bytes[0..]) catch unreachable); - return mem.readInt(bytes, T, endian); + return mem.readIntBig(T, &bytes); + } + + pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readInt(T, &bytes, endian); } pub async fn readStruct(self: *Self, comptime T: type) !T { diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index 0fe958c38b..ee26950272 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) pub fn init(key: []const u8) Self { debug.assert(key.len >= 16); - const k0 = mem.readInt(key[0..8], u64, Endian.Little); - const k1 = mem.readInt(key[8..16], u64, Endian.Little); + const k0 = mem.readIntSliceLittle(u64, key[0..8]); + const k1 = mem.readIntSliceLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) fn round(d: *Self, b: []const u8) void { debug.assert(b.len == 8); - const m = mem.readInt(b[0..], u64, Endian.Little); + const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; comptime var i: usize = 0; @@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; test "siphash64-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][8]u8{ "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc @@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u64, Endian.Little); + const expected = mem.readIntLittle(u64, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } test "siphash128-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][16]u8{ "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", @@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u128, Endian.Little); + const expected = mem.readIntLittle(u128, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/heap.zig b/std/heap.zig index 5c31d412cf..46b247fa7e 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -66,7 +66,7 @@ pub const DirectAllocator = struct { } } - fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { + fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { diff --git a/std/io.zig b/std/io.zig index bdca2b03e8..4442191717 100644 --- a/std/io.zig +++ b/std/io.zig @@ -152,35 +152,42 @@ pub fn InStream(comptime ReadError: type) type { } /// Reads a native-endian integer - pub fn readIntNe(self: *Self, comptime T: type) !T { - return self.readInt(builtin.endian, T); - } - - pub fn readIntLe(self: *Self, comptime T: type) !T { + pub fn readIntNative(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntLE(T, bytes); + return mem.readIntSliceNative(T, bytes); } - pub fn readIntBe(self: *Self, comptime T: type) !T { + /// Reads a foreign-endian integer + pub fn readIntForeign(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntBE(T, bytes); + return mem.readIntSliceForeign(T, bytes); } - pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { + pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, endian); + return mem.readIntSliceLittle(T, bytes); } - pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T { + pub fn readIntBig(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSliceBig(T, bytes); + } + + pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); + } + + pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { assert(size <= @sizeOf(T)); - assert(size <= 8); - var input_buf: [8]u8 = undefined; - const input_slice = input_buf[0..size]; - try self.readNoEof(input_slice); - return mem.readInt(input_slice, T, endian); + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { @@ -229,25 +236,34 @@ pub fn OutStream(comptime WriteError: type) type { } /// Write a native-endian integer. - pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void { - return self.writeInt(builtin.endian, T, value); - } - - pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void { + pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntLE(T, &bytes, value); + mem.writeIntNative(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void { + /// Write a foreign-endian integer. + pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntBE(T, &bytes, value); + mem.writeIntForeign(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void { + pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeInt(bytes[0..], value, endian); + mem.writeIntLittle(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeIntBig(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeInt(T, &bytes, value, endian); return self.writeFn(self, bytes); } }; diff --git a/std/mem.zig b/std/mem.zig index 9914a08e65..97dc46a80f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -407,186 +407,250 @@ test "mem.indexOf" { assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } -/// 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. -/// 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; - 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) << @intCast(ShiftType, index * 8)); - } - }, - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @ptrCast(*align(1) const T, bytes).*; } -/// 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)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result = (result << 8) | T(bytes[i]); - } - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @bswap(T, @ptrCast(*align(1) const T, bytes).*); } -/// 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)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result |= T(bytes[i]) << i * 8; - } - } - return result; +pub const readIntLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntNative, + builtin.Endian.Big => readIntForeign, +}; + +pub const readIntBig = switch (builtin.endian) { + builtin.Endian.Little => readIntForeign, + builtin.Endian.Big => readIntNative, +}; + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -test "readIntBE/LE" { - assert(readIntBE(u0, []u8{}) == 0x0); - assert(readIntLE(u0, []u8{}) == 0x0); - - assert(readIntBE(u8, []u8{0x32}) == 0x32); - assert(readIntLE(u8, []u8{0x12}) == 0x12); - - assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234); - assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412); - - assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - - assert(readIntBE(i8, []u8{0xff}) == -1); - assert(readIntLE(i8, []u8{0xfe}) == -2); - - assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3); - assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4); +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -/// 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, endian: builtin.Endian) void { - const uint = @IntType(false, @typeOf(value).bit_count); +pub const readIntSliceLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceNative, + builtin.Endian.Big => readIntSliceForeign, +}; + +pub const readIntSliceBig = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceForeign, + builtin.Endian.Big => readIntSliceNative, +}; + +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { + if (endian == builtin.endian) { + return readIntNative(T, bytes); + } else { + return readIntForeign(T, bytes); + } +} + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); +} + +test "readIntBig and readIntLittle" { + assert(readIntSliceBig(u0, []u8{}) == 0x0); + assert(readIntSliceLittle(u0, []u8{}) == 0x0); + + assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); + assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); + + assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); + + assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + + assert(readIntSliceBig(i8, []u8{0xff}) == -1); + assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); + + assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, and +/// accepts any integer bit width. +/// This function stores in native endian, which means it is implemented as a simple +/// memory store. +pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = value; +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +/// This function stores in foreign endian, which means it does a @bswap first. +pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = @bswap(T, value); +} + +pub const writeIntLittle = switch (builtin.endian) { + builtin.Endian.Little => writeIntNative, + builtin.Endian.Big => writeIntForeign, +}; + +pub const writeIntBig = switch (builtin.endian) { + builtin.Endian.Little => writeIntForeign, + builtin.Endian.Big => writeIntNative, +}; + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + if (endian == builtin.endian) { + return writeIntNative(T, buffer, value); + } else { + return writeIntForeign(T, buffer, value); + } +} + +/// Writes a twos-complement little-endian integer to memory. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer after writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntLittle +/// instead. +pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); var bits = @truncate(uint, value); - 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); -} - -pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - assert(bits == 0); -} - -pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - for (buf) |*b| { + for (buffer) |*b| { b.* = @truncate(u8, bits); bits >>= 8; } - assert(bits == 0); } -test "writeIntBE/LE" { +/// Writes a twos-complement big-endian integer to memory. +/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer before writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntBig instead. +pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); + var bits = @truncate(uint, value); + var index: usize = buffer.len; + while (index != 0) { + index -= 1; + buffer[index] = @truncate(u8, bits); + bits >>= 8; + } +} + +pub const writeIntSliceNative = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceLittle, + builtin.Endian.Big => writeIntSliceBig, +}; + +pub const writeIntSliceForeign = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceBig, + builtin.Endian.Big => writeIntSliceLittle, +}; + +/// Writes a twos-complement integer to memory, with the specified endianness. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Any extra bytes in buffer not part of the integer are set to zero, with +/// respect to endianness. To avoid the branch to check for extra buffer bytes, +/// use writeInt instead. +pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + switch (endian) { + builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value), + builtin.Endian.Big => return writeIntSliceBig(T, buffer, value), + } +} + +test "writeIntBig and writeIntLittle" { var buf0: [0]u8 = undefined; var buf1: [1]u8 = undefined; var buf2: [2]u8 = undefined; var buf9: [9]u8 = undefined; - writeIntBE(u0, &buf0, 0x0); + writeIntBig(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntLE(u0, &buf0, 0x0); + writeIntLittle(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntBE(u8, &buf1, 0x12); + writeIntBig(u8, &buf1, 0x12); assert(eql_slice_u8(buf1[0..], []u8{0x12})); - writeIntLE(u8, &buf1, 0x34); + writeIntLittle(u8, &buf1, 0x34); assert(eql_slice_u8(buf1[0..], []u8{0x34})); - writeIntBE(u16, &buf2, 0x1234); + writeIntBig(u16, &buf2, 0x1234); assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); - writeIntLE(u16, &buf2, 0x5678); + writeIntLittle(u16, &buf2, 0x5678); assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); - writeIntBE(u72, &buf9, 0x123456789abcdef024); + writeIntBig(u72, &buf9, 0x123456789abcdef024); assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); - writeIntLE(u72, &buf9, 0xfedcba9876543210ec); + writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); - writeIntBE(i8, &buf1, -1); + writeIntBig(i8, &buf1, -1); assert(eql_slice_u8(buf1[0..], []u8{0xff})); - writeIntLE(i8, &buf1, -2); + writeIntLittle(i8, &buf1, -2); assert(eql_slice_u8(buf1[0..], []u8{0xfe})); - writeIntBE(i16, &buf2, -3); + writeIntBig(i16, &buf2, -3); assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); - writeIntLE(i16, &buf2, -4); + writeIntLittle(i16, &buf2, -4); assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } @@ -735,12 +799,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); - assert(readIntBE(u32, bytes) == 0x12345678); - assert(readIntBE(i32, bytes) == 0x12345678); - assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); - assert(readIntLE(u32, bytes) == 0x78563412); - assert(readIntLE(i32, bytes) == 0x78563412); + assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + assert(readIntBig(u32, &bytes) == 0x12345678); + assert(readIntBig(i32, &bytes) == 0x12345678); + assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + assert(readIntLittle(u32, &bytes) == 0x78563412); + assert(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -749,7 +813,7 @@ fn testReadIntImpl() void { 0x12, 0x34, }; - const answer = readInt(buf, u64, builtin.Endian.Big); + const answer = readInt(u32, &buf, builtin.Endian.Big); assert(answer == 0x00001234); } { @@ -759,7 +823,7 @@ fn testReadIntImpl() void { 0x00, 0x00, }; - const answer = readInt(buf, u64, builtin.Endian.Little); + const answer = readInt(u32, &buf, builtin.Endian.Little); assert(answer == 0x00003412); } { @@ -767,21 +831,33 @@ fn testReadIntImpl() void { 0xff, 0xfe, }; - assert(readIntBE(u16, bytes) == 0xfffe); - assert(readIntBE(i16, bytes) == -0x0002); - assert(readIntLE(u16, bytes) == 0xfeff); - assert(readIntLE(i16, bytes) == -0x0101); + assert(readIntBig(u16, &bytes) == 0xfffe); + assert(readIntBig(i16, &bytes) == -0x0002); + assert(readIntLittle(u16, &bytes) == 0xfeff); + assert(readIntLittle(i16, &bytes) == -0x0101); } } -test "testWriteInt" { +test "std.mem.writeIntSlice" { testWriteIntImpl(); comptime testWriteIntImpl(); } fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; - writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big); + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -793,7 +869,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little); + writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -805,7 +881,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); + writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -817,7 +893,7 @@ fn testWriteIntImpl() void { 0x78, })); - writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); + writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -829,7 +905,7 @@ fn testWriteIntImpl() void { 0x00, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -841,7 +917,7 @@ fn testWriteIntImpl() void { 0x34, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x34, 0x12, @@ -939,29 +1015,52 @@ test "std.mem.rotate" { })); } -// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by -// endian-casting the pointer and then dereferencing - -pub fn endianSwapIfLe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Little, T, x); +/// Converts a little-endian integer to host endianness. +pub fn littleToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; } -pub fn endianSwapIfBe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Big, T, x); +/// Converts a big-endian integer to host endianness. +pub fn bigToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } -pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T { - return if (builtin.endian == endian) endianSwap(T, x) else x; +/// Converts an integer from specified endianness to host endianness. +pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { + return switch (endianness_of_x) { + builtin.Endian.Little => littleToNative(T, x), + builtin.Endian.Big => bigToNative(T, x), + }; } -pub fn endianSwap(comptime T: type, x: T) T { - var buf: [@sizeOf(T)]u8 = undefined; - mem.writeInt(buf[0..], x, builtin.Endian.Little); - return mem.readInt(buf, T, builtin.Endian.Big); +/// Converts an integer which has host endianness to the desired endianness. +pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { + return switch (desired_endianness) { + builtin.Endian.Little => nativeToLittle(T, x), + builtin.Endian.Big => nativeToBig(T, x), + }; } -test "std.mem.endianSwap" { - assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE); +/// Converts an integer which has host endianness to little endian. +pub fn nativeToLittle(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; +} + +/// Converts an integer which has host endianness to big endian. +pub fn nativeToBig(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } fn AsBytesReturnType(comptime P: type) type { diff --git a/std/net.zig b/std/net.zig index 006a9d4ac5..968c1f019f 100644 --- a/std/net.zig +++ b/std/net.zig @@ -23,7 +23,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{ .family = posix.AF_INET, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .addr = ip4, .zero = []u8{0} ** 8, }, @@ -37,7 +37,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{ .family = posix.AF_INET6, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .flowinfo = 0, .addr = ip6.addr, .scope_id = ip6.scope_id, @@ -47,7 +47,7 @@ pub const Address = struct { } pub fn port(self: Address) u16 { - return std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + return mem.bigToNative(u16, self.os_addr.in.port); } pub fn initPosix(addr: posix.sockaddr) Address { @@ -57,12 +57,12 @@ pub const Address = struct { pub fn format(self: *const Address, out_stream: var) !void { switch (self.os_addr.in.family) { posix.AF_INET => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port); const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]); try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port); }, posix.AF_INET6 => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port); try out_stream.print("[TODO render ip6 address]:{}", native_endian_port); }, else => try out_stream.write("(unrecognized address family)"), @@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr { } test "std.net.parseIp4" { - assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001)); + assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001)); testParseIp4Fail("256.0.0.1", error.Overflow); testParseIp4Fail("x.0.0.1", error.InvalidCharacter); diff --git a/std/os/child_process.zig b/std/os/child_process.zig index c8865bfacd..0aa896ff1b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -807,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { const stream = &os.File.openHandle(fd).outStream().stream; - stream.writeIntNe(ErrInt, value) catch return error.SystemResources; + stream.writeIntNative(ErrInt, value) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { const stream = &os.File.openHandle(fd).inStream().stream; - return stream.readIntNe(ErrInt) catch return error.SystemResources; + return stream.readIntNative(ErrInt) catch return error.SystemResources; } diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index 20a6710596..509075386f 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -98,12 +98,12 @@ pub nakedcc fn restore_rt() void { } pub const msghdr = extern struct { - msg_name: &u8, + msg_name: *u8, msg_namelen: socklen_t, - msg_iov: &iovec, + msg_iov: *iovec, msg_iovlen: i32, __pad1: i32, - msg_control: &u8, + msg_control: *u8, msg_controllen: socklen_t, __pad2: socklen_t, msg_flags: i32, diff --git a/std/pdb.zig b/std/pdb.zig index 2c5df3e597..0cfc6a6cda 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -508,11 +508,11 @@ const Msf = struct { allocator, ); - const stream_count = try self.directory.stream.readIntLe(u32); + const stream_count = try self.directory.stream.readIntLittle(u32); const stream_sizes = try allocator.alloc(u32, stream_count); for (stream_sizes) |*s| { - const size = try self.directory.stream.readIntLe(u32); + const size = try self.directory.stream.readIntLittle(u32); s.* = blockCountFromSize(size, superblock.BlockSize); } @@ -603,7 +603,7 @@ const MsfStream = struct { var i: u32 = 0; while (i < block_count) : (i += 1) { - stream.blocks[i] = try in.readIntLe(u32); + stream.blocks[i] = try in.readIntLittle(u32); } return stream; diff --git a/std/rand/index.zig b/std/rand/index.zig index 97101bc3b7..c335063e64 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.os.getRandomBytes(buf[0..]); -// const seed = mem.readIntLE(u64, buf[0..8]); +// const seed = mem.readIntSliceLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // @@ -52,7 +52,7 @@ pub const Random = struct { // use LE instead of native endian for better portability maybe? // TODO: endian portability is pointless if the underlying prng isn't endian portable. // TODO: document the endian portability of this library. - const byte_aligned_result = mem.readIntLE(ByteAlignedT, rand_bytes); + const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes); const unsigned_result = @truncate(UnsignedT, byte_aligned_result); return @bitCast(T, unsigned_result); } @@ -69,6 +69,7 @@ pub const Random = struct { return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); } } + /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. /// Within this assumption, the runtime of this function is exponentially distributed. @@ -123,6 +124,7 @@ pub const Random = struct { } return r.uintLessThanBiased(T, at_most + 1); } + /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -151,6 +153,7 @@ pub const Random = struct { return at_least + r.uintLessThanBiased(T, less_than - at_least); } } + /// Returns an evenly distributed random integer `at_least <= i < less_than`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -185,6 +188,7 @@ pub const Random = struct { return at_least + r.uintAtMostBiased(T, at_most - at_least); } } + /// Returns an evenly distributed random integer `at_least <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. diff --git a/std/unicode.zig b/std/unicode.zig index fcb748401f..2e542bcb19 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -249,12 +249,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u32 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c0: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c0 & ~u32(0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c1: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -510,46 +510,46 @@ test "utf16leToUtf8" { const utf16le_as_bytes = @sliceToBytes(utf16le[0..]); { - mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "Aa")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { // the values just outside the surrogate half range - mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { // smallest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { // largest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } @@ -583,7 +583,7 @@ pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { while (it.nextCodepoint()) |codepoint| { if (end_index == utf16le_as_bytes.len) return (end_index / 2) + 1; // TODO surrogate pairs - mem.writeInt(utf16le_as_bytes[end_index..], @intCast(u16, codepoint), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[end_index..], @intCast(u16, codepoint)); end_index += 2; } return end_index / 2; diff --git a/test/behavior.zig b/test/behavior.zig index 1d031343d6..499c20ee20 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -8,6 +8,7 @@ comptime { _ = @import("cases/atomics.zig"); _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); + _ = @import("cases/bswap.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); @@ -64,6 +65,7 @@ comptime { _ = @import("cases/switch_prong_implicit_cast.zig"); _ = @import("cases/syntax.zig"); _ = @import("cases/this.zig"); + _ = @import("cases/truncate.zig"); _ = @import("cases/try.zig"); _ = @import("cases/type_info.zig"); _ = @import("cases/undefined.zig"); diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig new file mode 100644 index 0000000000..57993077e1 --- /dev/null +++ b/test/cases/bswap.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "@bswap" { + comptime testByteSwap(); + testByteSwap(); +} + +fn testByteSwap() void { + assert(@bswap(u0, 0) == 0); + assert(@bswap(u8, 0x12) == 0x12); + assert(@bswap(u16, 0x1234) == 0x3412); + assert(@bswap(u24, 0x123456) == 0x563412); + assert(@bswap(u32, 0x12345678) == 0x78563412); + assert(@bswap(u40, 0x123456789a) == 0x9a78563412); + assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + + assert(@bswap(i0, 0) == 0); + assert(@bswap(i8, -50) == -50); + assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); +} diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig new file mode 100644 index 0000000000..02b5085ccd --- /dev/null +++ b/test/cases/truncate.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "truncate u0 to larger integer allowed and has comptime known result" { + var x: u0 = 0; + const y = @truncate(u8, x); + comptime assert(y == 0); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index be839f0550..ee3741ee6b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,18 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "reading past end of pointer casted array", + \\comptime { + \\ const array = "aoeu"; + \\ const slice = array[2..]; + \\ const int_ptr = @ptrCast(*const u24, slice.ptr); + \\ const deref = int_ptr.*; + \\} + , + ".tmp_source.zig:5:26: error: attempt to read 3 bytes from [4]u8 at index 2 which is 2 bytes", + ); + cases.add( "error note for function parameter incompatibility", \\fn do_the_thing(func: fn (arg: i32) void) void {}