Skip to content

Commit b831fd1

Browse files
committed
Merge remote-tracking branch 'origin/master' into align-16-for-128-bit-and-up-int-types
2 parents 958d2a8 + 7f23dac commit b831fd1

14 files changed

+613
-131
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Here are some examples:
2525

2626
* [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html)
2727
* [The Right Tool for the Right Job: Redis Modules & Zig](https://www.youtube.com/watch?v=eCHM8-_poZY)
28+
* [Writing a small ray tracer in Rust and Zig](https://nelari.us/post/raytracer_with_rust_and_zig/)
2829

2930
Zig is a brand new language, with no advertising budget. Word of mouth is the
3031
only way people find out about the project, and the more people hear about it,
@@ -45,8 +46,8 @@ The most highly regarded argument in such a discussion is a real world use case.
4546

4647
The issue label
4748
[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22)
48-
exists to help contributors find issues that are "limited in scope and/or
49-
knowledge of Zig internals."
49+
exists to help you find issues that are **limited in scope and/or
50+
knowledge of Zig internals.**
5051

5152
### Editing Source Code
5253

@@ -61,8 +62,7 @@ To test changes, do the following from the build directory:
6162

6263
1. Run `make install` (on POSIX) or
6364
`msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
64-
2. `bin/zig build --build-file ../build.zig test` (on POSIX) or
65-
`bin\zig.exe build --build-file ..\build.zig test` (on Windows).
65+
2. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
6666

6767
That runs the whole test suite, which does a lot of extra testing that you
6868
likely won't always need, and can take upwards of 2 hours. This is what the
@@ -79,8 +79,8 @@ Another example is choosing a different set of things to test. For example,
7979
not the other ones. Combining this suggestion with the previous one, you could
8080
do this:
8181

82-
`bin/zig build --build-file ../build.zig test-std -Dskip-release` (on POSIX) or
83-
`bin\zig.exe build --build-file ..\build.zig test-std -Dskip-release` (on Windows).
82+
`bin/zig build test-std -Dskip-release` (on POSIX) or
83+
`bin\zig.exe build test-std -Dskip-release` (on Windows).
8484

8585
This will run only the standard library tests, in debug mode only, for all
8686
targets (it will cross-compile the tests for non-native targets but not run

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
![ZIG](https://ziglang.org/zig-logo.svg)
22

3-
Zig is an open-source programming language designed for **robustness**,
3+
A general-purpose programming language designed for **robustness**,
44
**optimality**, and **maintainability**.
55

66
## Resources

std/c/freebsd.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub const _errno = __error;
66

77
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
88
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
9+
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;

std/debug.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,8 +1024,7 @@ pub fn openElfDebugInfo(
10241024
elf_seekable_stream: *DwarfSeekableStream,
10251025
elf_in_stream: *DwarfInStream,
10261026
) !DwarfInfo {
1027-
var efile: elf.Elf = undefined;
1028-
try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
1027+
var efile = try elf.Elf.openStream(allocator, elf_seekable_stream, elf_in_stream);
10291028
errdefer efile.close();
10301029

10311030
var di = DwarfInfo{

std/elf.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ pub const SectionHeader = struct {
356356
pub const Elf = struct {
357357
seekable_stream: *io.SeekableStream(anyerror, anyerror),
358358
in_stream: *io.InStream(anyerror),
359-
auto_close_stream: bool,
360359
is_64: bool,
361360
endian: builtin.Endian,
362361
file_type: FileType,
@@ -368,25 +367,23 @@ pub const Elf = struct {
368367
string_section: *SectionHeader,
369368
section_headers: []SectionHeader,
370369
allocator: *mem.Allocator,
371-
prealloc_file: File,
372370

373371
/// Call close when done.
374-
pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
372+
pub fn openPath(allocator: *mem.Allocator, path: []const u8) !Elf {
375373
@compileError("TODO implement");
376374
}
377375

378376
/// Call close when done.
379-
pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: File) !void {
377+
pub fn openFile(allocator: *mem.Allocator, file: File) !Elf {
380378
@compileError("TODO implement");
381379
}
382380

383381
pub fn openStream(
384-
elf: *Elf,
385382
allocator: *mem.Allocator,
386383
seekable_stream: *io.SeekableStream(anyerror, anyerror),
387384
in: *io.InStream(anyerror),
388-
) !void {
389-
elf.auto_close_stream = false;
385+
) !Elf {
386+
var elf: Elf = undefined;
390387
elf.allocator = allocator;
391388
elf.seekable_stream = seekable_stream;
392389
elf.in_stream = in;
@@ -523,12 +520,12 @@ pub const Elf = struct {
523520
// not a string table
524521
return error.InvalidFormat;
525522
}
523+
524+
return elf;
526525
}
527526

528527
pub fn close(elf: *Elf) void {
529528
elf.allocator.free(elf.section_headers);
530-
531-
if (elf.auto_close_stream) elf.prealloc_file.close();
532529
}
533530

534531
pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {

std/hash.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
const adler = @import("hash/adler.zig");
22
pub const Adler32 = adler.Adler32;
33

4+
const auto_hash = @import("hash/auto_hash.zig");
5+
pub const autoHash = auto_hash.autoHash;
6+
47
// pub for polynomials + generic crc32 construction
58
pub const crc = @import("hash/crc.zig");
69
pub const Crc32 = crc.Crc32;
@@ -16,18 +19,25 @@ pub const SipHash128 = siphash.SipHash128;
1619

1720
pub const murmur = @import("hash/murmur.zig");
1821
pub const Murmur2_32 = murmur.Murmur2_32;
22+
23+
1924
pub const Murmur2_64 = murmur.Murmur2_64;
2025
pub const Murmur3_32 = murmur.Murmur3_32;
2126

2227
pub const cityhash = @import("hash/cityhash.zig");
2328
pub const CityHash32 = cityhash.CityHash32;
2429
pub const CityHash64 = cityhash.CityHash64;
2530

31+
const wyhash = @import("hash/wyhash.zig");
32+
pub const Wyhash = wyhash.Wyhash;
33+
2634
test "hash" {
2735
_ = @import("hash/adler.zig");
36+
_ = @import("hash/auto_hash.zig");
2837
_ = @import("hash/crc.zig");
2938
_ = @import("hash/fnv.zig");
3039
_ = @import("hash/siphash.zig");
3140
_ = @import("hash/murmur.zig");
3241
_ = @import("hash/cityhash.zig");
42+
_ = @import("hash/wyhash.zig");
3343
}

std/hash/auto_hash.zig

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
const std = @import("std");
2+
const builtin = @import("builtin");
3+
const mem = std.mem;
4+
const meta = std.meta;
5+
6+
/// Provides generic hashing for any eligible type.
7+
/// Only hashes `key` itself, pointers are not followed.
8+
pub fn autoHash(hasher: var, key: var) void {
9+
const Key = @typeOf(key);
10+
switch (@typeInfo(Key)) {
11+
builtin.TypeId.NoReturn,
12+
builtin.TypeId.Opaque,
13+
builtin.TypeId.Undefined,
14+
builtin.TypeId.ArgTuple,
15+
builtin.TypeId.Void,
16+
builtin.TypeId.Null,
17+
builtin.TypeId.BoundFn,
18+
builtin.TypeId.ComptimeFloat,
19+
builtin.TypeId.ComptimeInt,
20+
builtin.TypeId.Type,
21+
builtin.TypeId.EnumLiteral,
22+
=> @compileError("cannot hash this type"),
23+
24+
// Help the optimizer see that hashing an int is easy by inlining!
25+
// TODO Check if the situation is better after #561 is resolved.
26+
builtin.TypeId.Int => @inlineCall(hasher.update, std.mem.asBytes(&key)),
27+
28+
builtin.TypeId.Float => |info| autoHash(hasher, @bitCast(@IntType(false, info.bits), key)),
29+
30+
builtin.TypeId.Bool => autoHash(hasher, @boolToInt(key)),
31+
builtin.TypeId.Enum => autoHash(hasher, @enumToInt(key)),
32+
builtin.TypeId.ErrorSet => autoHash(hasher, @errorToInt(key)),
33+
builtin.TypeId.Promise, builtin.TypeId.Fn => autoHash(hasher, @ptrToInt(key)),
34+
35+
builtin.TypeId.Pointer => |info| switch (info.size) {
36+
builtin.TypeInfo.Pointer.Size.One,
37+
builtin.TypeInfo.Pointer.Size.Many,
38+
builtin.TypeInfo.Pointer.Size.C,
39+
=> autoHash(hasher, @ptrToInt(key)),
40+
41+
builtin.TypeInfo.Pointer.Size.Slice => {
42+
autoHash(hasher, key.ptr);
43+
autoHash(hasher, key.len);
44+
},
45+
},
46+
47+
builtin.TypeId.Optional => if (key) |k| autoHash(hasher, k),
48+
49+
builtin.TypeId.Array => {
50+
// TODO detect via a trait when Key has no padding bits to
51+
// hash it as an array of bytes.
52+
// Otherwise, hash every element.
53+
for (key) |element| {
54+
autoHash(hasher, element);
55+
}
56+
},
57+
58+
builtin.TypeId.Vector => |info| {
59+
if (info.child.bit_count % 8 == 0) {
60+
// If there's no unused bits in the child type, we can just hash
61+
// this as an array of bytes.
62+
hasher.update(mem.asBytes(&key));
63+
} else {
64+
// Otherwise, hash every element.
65+
// TODO remove the copy to an array once field access is done.
66+
const array: [info.len]info.child = key;
67+
comptime var i: u32 = 0;
68+
inline while (i < info.len) : (i += 1) {
69+
autoHash(hasher, array[i]);
70+
}
71+
}
72+
},
73+
74+
builtin.TypeId.Struct => |info| {
75+
// TODO detect via a trait when Key has no padding bits to
76+
// hash it as an array of bytes.
77+
// Otherwise, hash every field.
78+
inline for (info.fields) |field| {
79+
// We reuse the hash of the previous field as the seed for the
80+
// next one so that they're dependant.
81+
autoHash(hasher, @field(key, field.name));
82+
}
83+
},
84+
85+
builtin.TypeId.Union => |info| blk: {
86+
if (info.tag_type) |tag_type| {
87+
const tag = meta.activeTag(key);
88+
const s = autoHash(hasher, tag);
89+
inline for (info.fields) |field| {
90+
const enum_field = field.enum_field.?;
91+
if (enum_field.value == @enumToInt(tag)) {
92+
autoHash(hasher, @field(key, enum_field.name));
93+
// TODO use a labelled break when it does not crash the compiler.
94+
// break :blk;
95+
return;
96+
}
97+
}
98+
unreachable;
99+
} else @compileError("cannot hash untagged union type: " ++ @typeName(Key) ++ ", provide your own hash function");
100+
},
101+
102+
builtin.TypeId.ErrorUnion => blk: {
103+
const payload = key catch |err| {
104+
autoHash(hasher, err);
105+
break :blk;
106+
};
107+
autoHash(hasher, payload);
108+
},
109+
}
110+
}
111+
112+
const testing = std.testing;
113+
const Wyhash = std.hash.Wyhash;
114+
115+
fn testAutoHash(key: var) u64 {
116+
// Any hash could be used here, for testing autoHash.
117+
var hasher = Wyhash.init(0);
118+
autoHash(&hasher, key);
119+
return hasher.final();
120+
}
121+
122+
test "autoHash slice" {
123+
// Allocate one array dynamically so that we're assured it is not merged
124+
// with the other by the optimization passes.
125+
const array1 = try std.heap.direct_allocator.create([6]u32);
126+
defer std.heap.direct_allocator.destroy(array1);
127+
array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };
128+
const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };
129+
const a = array1[0..];
130+
const b = array2[0..];
131+
const c = array1[0..3];
132+
testing.expect(testAutoHash(a) == testAutoHash(a));
133+
testing.expect(testAutoHash(a) != testAutoHash(array1));
134+
testing.expect(testAutoHash(a) != testAutoHash(b));
135+
testing.expect(testAutoHash(a) != testAutoHash(c));
136+
}
137+
138+
test "testAutoHash optional" {
139+
const a: ?u32 = 123;
140+
const b: ?u32 = null;
141+
testing.expectEqual(testAutoHash(a), testAutoHash(u32(123)));
142+
testing.expect(testAutoHash(a) != testAutoHash(b));
143+
testing.expectEqual(testAutoHash(b), 0);
144+
}
145+
146+
test "testAutoHash array" {
147+
const a = [_]u32{ 1, 2, 3 };
148+
const h = testAutoHash(a);
149+
var hasher = Wyhash.init(0);
150+
autoHash(&hasher, u32(1));
151+
autoHash(&hasher, u32(2));
152+
autoHash(&hasher, u32(3));
153+
testing.expectEqual(h, hasher.final());
154+
}
155+
156+
test "testAutoHash struct" {
157+
const Foo = struct {
158+
a: u32 = 1,
159+
b: u32 = 2,
160+
c: u32 = 3,
161+
};
162+
const f = Foo{};
163+
const h = testAutoHash(f);
164+
var hasher = Wyhash.init(0);
165+
autoHash(&hasher, u32(1));
166+
autoHash(&hasher, u32(2));
167+
autoHash(&hasher, u32(3));
168+
testing.expectEqual(h, hasher.final());
169+
}
170+
171+
test "testAutoHash union" {
172+
const Foo = union(enum) {
173+
A: u32,
174+
B: f32,
175+
C: u32,
176+
};
177+
178+
const a = Foo{ .A = 18 };
179+
var b = Foo{ .B = 12.34 };
180+
const c = Foo{ .C = 18 };
181+
testing.expect(testAutoHash(a) == testAutoHash(a));
182+
testing.expect(testAutoHash(a) != testAutoHash(b));
183+
testing.expect(testAutoHash(a) != testAutoHash(c));
184+
185+
b = Foo{ .A = 18 };
186+
testing.expect(testAutoHash(a) == testAutoHash(b));
187+
}
188+
189+
test "testAutoHash vector" {
190+
const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 };
191+
const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 };
192+
const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 };
193+
testing.expect(testAutoHash(a) == testAutoHash(a));
194+
testing.expect(testAutoHash(a) != testAutoHash(b));
195+
testing.expect(testAutoHash(a) != testAutoHash(c));
196+
}
197+
198+
test "testAutoHash error union" {
199+
const Errors = error{Test};
200+
const Foo = struct {
201+
a: u32 = 1,
202+
b: u32 = 2,
203+
c: u32 = 3,
204+
};
205+
const f = Foo{};
206+
const g: Errors!Foo = Errors.Test;
207+
testing.expect(testAutoHash(f) != testAutoHash(g));
208+
testing.expect(testAutoHash(f) == testAutoHash(Foo{}));
209+
testing.expect(testAutoHash(g) == testAutoHash(Errors.Test));
210+
}

0 commit comments

Comments
 (0)