Commit d5e21a4f1a
Changed files (23)
lib
src
link
Wasm
test
behavior
cases
lib/std/atomic/Atomic.zig
@@ -153,163 +153,155 @@ pub fn Atomic(comptime T: type) type {
return @atomicRmw(T, &self.value, op, value, ordering);
}
- fn exportWhen(comptime condition: bool, comptime functions: type) type {
- return if (condition) functions else struct {};
+ pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Add, value, ordering);
}
- pub usingnamespace exportWhen(std.meta.trait.isNumber(T), struct {
- pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Add, value, ordering);
- }
-
- pub inline fn fetchSub(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Sub, value, ordering);
- }
+ pub inline fn fetchSub(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Sub, value, ordering);
+ }
- pub inline fn fetchMin(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Min, value, ordering);
- }
+ pub inline fn fetchMin(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Min, value, ordering);
+ }
- pub inline fn fetchMax(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Max, value, ordering);
- }
- });
+ pub inline fn fetchMax(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Max, value, ordering);
+ }
- pub usingnamespace exportWhen(std.meta.trait.isIntegral(T), struct {
- pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.And, value, ordering);
- }
+ pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.And, value, ordering);
+ }
- pub inline fn fetchNand(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Nand, value, ordering);
- }
+ pub inline fn fetchNand(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Nand, value, ordering);
+ }
- pub inline fn fetchOr(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Or, value, ordering);
- }
+ pub inline fn fetchOr(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Or, value, ordering);
+ }
- pub inline fn fetchXor(self: *Self, value: T, comptime ordering: Ordering) T {
- return self.rmw(.Xor, value, ordering);
- }
+ pub inline fn fetchXor(self: *Self, value: T, comptime ordering: Ordering) T {
+ return self.rmw(.Xor, value, ordering);
+ }
- const Bit = std.math.Log2Int(T);
- const BitRmwOp = enum {
- Set,
- Reset,
- Toggle,
- };
+ const Bit = std.math.Log2Int(T);
+ const BitRmwOp = enum {
+ Set,
+ Reset,
+ Toggle,
+ };
- pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
- return bitRmw(self, .Set, bit, ordering);
- }
+ pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
+ return bitRmw(self, .Set, bit, ordering);
+ }
- pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
- return bitRmw(self, .Reset, bit, ordering);
- }
+ pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
+ return bitRmw(self, .Reset, bit, ordering);
+ }
- pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
- return bitRmw(self, .Toggle, bit, ordering);
- }
+ pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {
+ return bitRmw(self, .Toggle, bit, ordering);
+ }
- inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
- // x86 supports dedicated bitwise instructions
- if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {
- // TODO: this causes std lib test failures when enabled
- if (false) {
- return x86BitRmw(self, op, bit, ordering);
- }
+ inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
+ // x86 supports dedicated bitwise instructions
+ if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {
+ // TODO: this causes std lib test failures when enabled
+ if (false) {
+ return x86BitRmw(self, op, bit, ordering);
}
+ }
- const mask = @as(T, 1) << bit;
- const value = switch (op) {
- .Set => self.fetchOr(mask, ordering),
- .Reset => self.fetchAnd(~mask, ordering),
- .Toggle => self.fetchXor(mask, ordering),
- };
+ const mask = @as(T, 1) << bit;
+ const value = switch (op) {
+ .Set => self.fetchOr(mask, ordering),
+ .Reset => self.fetchAnd(~mask, ordering),
+ .Toggle => self.fetchXor(mask, ordering),
+ };
- return @intFromBool(value & mask != 0);
- }
+ return @intFromBool(value & mask != 0);
+ }
- inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
- const old_bit: u8 = switch (@sizeOf(T)) {
- 2 => switch (op) {
- .Set => asm volatile ("lock btsw %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Reset => asm volatile ("lock btrw %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Toggle => asm volatile ("lock btcw %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- },
- 4 => switch (op) {
- .Set => asm volatile ("lock btsl %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Reset => asm volatile ("lock btrl %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Toggle => asm volatile ("lock btcl %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- },
- 8 => switch (op) {
- .Set => asm volatile ("lock btsq %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Reset => asm volatile ("lock btrq %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- .Toggle => asm volatile ("lock btcq %[bit], %[ptr]"
- // LLVM doesn't support u1 flag register return values
- : [result] "={@ccc}" (-> u8),
- : [ptr] "*m" (&self.value),
- [bit] "X" (@as(T, bit)),
- : "cc", "memory"
- ),
- },
- else => @compileError("Invalid atomic type " ++ @typeName(T)),
- };
+ inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {
+ const old_bit: u8 = switch (@sizeOf(T)) {
+ 2 => switch (op) {
+ .Set => asm volatile ("lock btsw %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Reset => asm volatile ("lock btrw %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Toggle => asm volatile ("lock btcw %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ },
+ 4 => switch (op) {
+ .Set => asm volatile ("lock btsl %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Reset => asm volatile ("lock btrl %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Toggle => asm volatile ("lock btcl %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ },
+ 8 => switch (op) {
+ .Set => asm volatile ("lock btsq %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Reset => asm volatile ("lock btrq %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ .Toggle => asm volatile ("lock btcq %[bit], %[ptr]"
+ // LLVM doesn't support u1 flag register return values
+ : [result] "={@ccc}" (-> u8),
+ : [ptr] "*m" (&self.value),
+ [bit] "X" (@as(T, bit)),
+ : "cc", "memory"
+ ),
+ },
+ else => @compileError("Invalid atomic type " ++ @typeName(T)),
+ };
- // TODO: emit appropriate tsan fence if compiling with tsan
- _ = ordering;
+ // TODO: emit appropriate tsan fence if compiling with tsan
+ _ = ordering;
- return @as(u1, @intCast(old_bit));
- }
- });
+ return @intCast(old_bit);
+ }
};
}
lib/std/hash/auto_hash.zig
@@ -1,7 +1,6 @@
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
-const meta = std.meta;
/// Describes how pointer types should be hashed.
pub const HashStrategy = enum {
@@ -69,7 +68,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
else => @TypeOf(hasher),
};
- if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) {
+ if (strat == .Shallow and std.meta.hasUniqueRepresentation(Key)) {
@call(.always_inline, Hasher.update, .{ hasher, mem.asBytes(&key) });
return;
}
@@ -97,7 +96,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
.signedness = .unsigned,
} }), @bitCast(key)), strat),
.unsigned => {
- if (comptime meta.trait.hasUniqueRepresentation(Key)) {
+ if (std.meta.hasUniqueRepresentation(Key)) {
@call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) });
} else {
// Take only the part containing the key value, the remaining
@@ -120,7 +119,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
.Array => hashArray(hasher, key, strat),
.Vector => |info| {
- if (comptime meta.trait.hasUniqueRepresentation(Key)) {
+ if (std.meta.hasUniqueRepresentation(Key)) {
hasher.update(mem.asBytes(&key));
} else {
comptime var i = 0;
@@ -140,7 +139,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
.Union => |info| {
if (info.tag_type) |tag_type| {
- const tag = meta.activeTag(key);
+ const tag = std.meta.activeTag(key);
hash(hasher, tag, strat);
inline for (info.fields) |field| {
if (@field(tag_type, field.name) == tag) {
@@ -166,27 +165,21 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
}
}
-fn typeContainsSlice(comptime K: type) bool {
- comptime {
- if (meta.trait.isSlice(K)) {
- return true;
- }
- if (meta.trait.is(.Struct)(K)) {
- inline for (@typeInfo(K).Struct.fields) |field| {
- if (typeContainsSlice(field.type)) {
- return true;
- }
- }
- }
- if (meta.trait.is(.Union)(K)) {
- inline for (@typeInfo(K).Union.fields) |field| {
+inline fn typeContainsSlice(comptime K: type) bool {
+ return switch (@typeInfo(K)) {
+ .Pointer => |info| info.size == .Slice,
+
+ inline .Struct, .Union => |info| {
+ inline for (info.fields) |field| {
if (typeContainsSlice(field.type)) {
return true;
}
}
- }
- return false;
- }
+ return false;
+ },
+
+ else => false,
+ };
}
/// Provides generic hashing for any eligible type.
@@ -236,7 +229,7 @@ fn testHashDeepRecursive(key: anytype) u64 {
test "typeContainsSlice" {
comptime {
- try testing.expect(!typeContainsSlice(meta.Tag(std.builtin.Type)));
+ try testing.expect(!typeContainsSlice(std.meta.Tag(std.builtin.Type)));
try testing.expect(typeContainsSlice([]const u8));
try testing.expect(!typeContainsSlice(u8));
lib/std/hash/xxhash.zig
@@ -185,8 +185,6 @@ pub const XxHash64 = struct {
}
pub fn update(self: *XxHash64, input: anytype) void {
- validateType(@TypeOf(input));
-
if (input.len < 32 - self.buf_len) {
@memcpy(self.buf[self.buf_len..][0..input.len], input);
self.buf_len += input.len;
@@ -232,8 +230,6 @@ pub const XxHash64 = struct {
};
pub fn hash(seed: u64, input: anytype) u64 {
- validateType(@TypeOf(input));
-
if (input.len < 32) {
return finalize(seed +% prime_5, 0, input);
} else {
@@ -315,8 +311,6 @@ pub const XxHash32 = struct {
}
pub fn update(self: *XxHash32, input: []const u8) void {
- validateType(@TypeOf(input));
-
if (input.len < 16 - self.buf_len) {
@memcpy(self.buf[self.buf_len..][0..input.len], input);
self.buf_len += input.len;
@@ -416,8 +410,6 @@ pub const XxHash32 = struct {
}
pub fn hash(seed: u32, input: anytype) u32 {
- validateType(@TypeOf(input));
-
if (input.len < 16) {
return finalize(seed +% prime_5, 0, input);
} else {
@@ -587,8 +579,6 @@ pub const XxHash3 = struct {
// Public API - Oneshot
pub fn hash(seed: u64, input: anytype) u64 {
- validateType(@TypeOf(input));
-
const secret = &default_secret;
if (input.len > 240) return hashLong(seed, input);
if (input.len > 128) return hash240(seed, input, secret);
@@ -709,8 +699,6 @@ pub const XxHash3 = struct {
}
pub fn update(self: *XxHash3, input: anytype) void {
- validateType(@TypeOf(input));
-
self.total_len += input.len;
std.debug.assert(self.buffered <= self.buffer.len);
@@ -783,18 +771,6 @@ pub const XxHash3 = struct {
const verify = @import("verify.zig");
-fn validateType(comptime T: type) void {
- comptime {
- if (!((std.meta.trait.isSlice(T) or
- std.meta.trait.is(.Array)(T) or
- std.meta.trait.isPtrTo(.Array)(T)) and
- std.meta.Elem(T) == u8))
- {
- @compileError("expect a slice, array or pointer to array of u8, got " ++ @typeName(T));
- }
- }
-}
-
fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) !void {
try expectEqual(expected, H.hash(seed, input));
lib/std/io/bit_reader.zig
@@ -2,7 +2,6 @@ const std = @import("../std.zig");
const io = std.io;
const assert = std.debug.assert;
const testing = std.testing;
-const trait = std.meta.trait;
const meta = std.meta;
const math = std.math;
@@ -43,8 +42,6 @@ pub fn BitReader(comptime endian: std.builtin.Endian, comptime ReaderType: type)
/// containing them in the least significant end. The number of bits successfully
/// read is placed in `out_bits`, as reaching the end of the stream is not an error.
pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
- comptime assert(trait.isUnsignedInt(U));
-
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
// related to shifting and casting.
const u_bit_count = @bitSizeOf(U);
lib/std/io/bit_writer.zig
@@ -2,8 +2,6 @@ const std = @import("../std.zig");
const io = std.io;
const testing = std.testing;
const assert = std.debug.assert;
-const trait = std.meta.trait;
-const meta = std.meta;
const math = std.math;
/// Creates a stream which allows for writing bit fields to another stream
@@ -35,7 +33,7 @@ pub fn BitWriter(comptime endian: std.builtin.Endian, comptime WriterType: type)
if (bits == 0) return;
const U = @TypeOf(value);
- comptime assert(trait.isUnsignedInt(U));
+ comptime assert(@typeInfo(U).Int.signedness == .unsigned);
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
// related to shifting and casting.
lib/std/io/test.zig
@@ -1,7 +1,5 @@
const std = @import("std");
const io = std.io;
-const meta = std.meta;
-const trait = std.trait;
const DefaultPrng = std.rand.DefaultPrng;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
lib/std/json/static.zig
@@ -247,7 +247,7 @@ pub fn innerParse(
}
},
.Enum => {
- if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
+ if (std.meta.hasFn(T, "jsonParse")) {
return T.jsonParse(allocator, source, options);
}
@@ -260,7 +260,7 @@ pub fn innerParse(
return sliceToEnum(T, slice);
},
.Union => |unionInfo| {
- if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
+ if (std.meta.hasFn(T, "jsonParse")) {
return T.jsonParse(allocator, source, options);
}
@@ -318,7 +318,7 @@ pub fn innerParse(
return r;
}
- if (comptime std.meta.trait.hasFn("jsonParse")(T)) {
+ if (std.meta.hasFn(T, "jsonParse")) {
return T.jsonParse(allocator, source, options);
}
@@ -581,7 +581,7 @@ pub fn innerParseFromValue(
}
},
.Enum => {
- if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
+ if (std.meta.hasFn(T, "jsonParseFromValue")) {
return T.jsonParseFromValue(allocator, source, options);
}
@@ -593,7 +593,7 @@ pub fn innerParseFromValue(
}
},
.Union => |unionInfo| {
- if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
+ if (std.meta.hasFn(T, "jsonParseFromValue")) {
return T.jsonParseFromValue(allocator, source, options);
}
@@ -635,7 +635,7 @@ pub fn innerParseFromValue(
return r;
}
- if (comptime std.meta.trait.hasFn("jsonParseFromValue")(T)) {
+ if (std.meta.hasFn(T, "jsonParseFromValue")) {
return T.jsonParseFromValue(allocator, source, options);
}
lib/std/json/stringify.zig
@@ -451,14 +451,14 @@ pub fn WriteStream(
}
},
.Enum, .EnumLiteral => {
- if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
+ if (std.meta.hasFn(T, "jsonStringify")) {
return value.jsonStringify(self);
}
return self.stringValue(@tagName(value));
},
.Union => {
- if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
+ if (std.meta.hasFn(T, "jsonStringify")) {
return value.jsonStringify(self);
}
@@ -487,7 +487,7 @@ pub fn WriteStream(
}
},
.Struct => |S| {
- if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
+ if (std.meta.hasFn(T, "jsonStringify")) {
return value.jsonStringify(self);
}
lib/std/meta/trait.zig
@@ -1,652 +0,0 @@
-const std = @import("../std.zig");
-const mem = std.mem;
-const debug = std.debug;
-const testing = std.testing;
-
-const meta = @import("../meta.zig");
-
-pub const TraitFn = fn (type) bool;
-
-pub fn multiTrait(comptime traits: anytype) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- inline for (traits) |t|
- if (!t(T)) return false;
- return true;
- }
- };
- return Closure.trait;
-}
-
-test "multiTrait" {
- const Vector2 = struct {
- const MyType = @This();
-
- x: u8,
- y: u8,
-
- pub fn add(self: MyType, other: MyType) MyType {
- return MyType{
- .x = self.x + other.x,
- .y = self.y + other.y,
- };
- }
- };
-
- const isVector = multiTrait(.{
- hasFn("add"),
- hasField("x"),
- hasField("y"),
- });
- try testing.expect(isVector(Vector2));
- try testing.expect(!isVector(u8));
-}
-
-pub fn hasFn(comptime name: []const u8) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- if (!comptime isContainer(T)) return false;
- if (!comptime @hasDecl(T, name)) return false;
- const DeclType = @TypeOf(@field(T, name));
- return @typeInfo(DeclType) == .Fn;
- }
- };
- return Closure.trait;
-}
-
-test "hasFn" {
- const TestStruct = struct {
- pub fn useless() void {}
- };
-
- try testing.expect(hasFn("useless")(TestStruct));
- try testing.expect(!hasFn("append")(TestStruct));
- try testing.expect(!hasFn("useless")(u8));
-}
-
-pub fn hasField(comptime name: []const u8) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- const fields = switch (@typeInfo(T)) {
- .Struct => |s| s.fields,
- .Union => |u| u.fields,
- .Enum => |e| e.fields,
- else => return false,
- };
-
- inline for (fields) |field| {
- if (mem.eql(u8, field.name, name)) return true;
- }
-
- return false;
- }
- };
- return Closure.trait;
-}
-
-test "hasField" {
- const TestStruct = struct {
- value: u32,
- };
-
- try testing.expect(hasField("value")(TestStruct));
- try testing.expect(!hasField("value")(*TestStruct));
- try testing.expect(!hasField("x")(TestStruct));
- try testing.expect(!hasField("x")(**TestStruct));
- try testing.expect(!hasField("value")(u8));
-}
-
-pub fn is(comptime id: std.builtin.TypeId) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- return id == @typeInfo(T);
- }
- };
- return Closure.trait;
-}
-
-test "is" {
- try testing.expect(is(.Int)(u8));
- try testing.expect(!is(.Int)(f32));
- try testing.expect(is(.Pointer)(*u8));
- try testing.expect(is(.Void)(void));
- try testing.expect(!is(.Optional)(anyerror));
-}
-
-pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- if (!comptime isSingleItemPtr(T)) return false;
- return id == @typeInfo(meta.Child(T));
- }
- };
- return Closure.trait;
-}
-
-test "isPtrTo" {
- try testing.expect(!isPtrTo(.Struct)(struct {}));
- try testing.expect(isPtrTo(.Struct)(*struct {}));
- try testing.expect(!isPtrTo(.Struct)(**struct {}));
-}
-
-pub fn isSliceOf(comptime id: std.builtin.TypeId) TraitFn {
- const Closure = struct {
- pub fn trait(comptime T: type) bool {
- if (!comptime isSlice(T)) return false;
- return id == @typeInfo(meta.Child(T));
- }
- };
- return Closure.trait;
-}
-
-test "isSliceOf" {
- try testing.expect(!isSliceOf(.Struct)(struct {}));
- try testing.expect(isSliceOf(.Struct)([]struct {}));
- try testing.expect(!isSliceOf(.Struct)([][]struct {}));
-}
-
-///////////Strait trait Fns
-
-//@TODO:
-// Somewhat limited since we can't apply this logic to normal variables, fields, or
-// Fns yet. Should be isExternType?
-pub fn isExtern(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Struct => |s| s.layout == .Extern,
- .Union => |u| u.layout == .Extern,
- else => false,
- };
-}
-
-test "isExtern" {
- const TestExStruct = extern struct {};
- const TestStruct = struct {};
-
- try testing.expect(isExtern(TestExStruct));
- try testing.expect(!isExtern(TestStruct));
- try testing.expect(!isExtern(u8));
-}
-
-pub fn isPacked(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Struct => |s| s.layout == .Packed,
- .Union => |u| u.layout == .Packed,
- else => false,
- };
-}
-
-test "isPacked" {
- const TestPStruct = packed struct {};
- const TestStruct = struct {};
-
- try testing.expect(isPacked(TestPStruct));
- try testing.expect(!isPacked(TestStruct));
- try testing.expect(!isPacked(u8));
-}
-
-pub fn isUnsignedInt(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Int => |i| i.signedness == .unsigned,
- else => false,
- };
-}
-
-test "isUnsignedInt" {
- try testing.expect(isUnsignedInt(u32) == true);
- try testing.expect(isUnsignedInt(comptime_int) == false);
- try testing.expect(isUnsignedInt(i64) == false);
- try testing.expect(isUnsignedInt(f64) == false);
-}
-
-pub fn isSignedInt(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .ComptimeInt => true,
- .Int => |i| i.signedness == .signed,
- else => false,
- };
-}
-
-test "isSignedInt" {
- try testing.expect(isSignedInt(u32) == false);
- try testing.expect(isSignedInt(comptime_int) == true);
- try testing.expect(isSignedInt(i64) == true);
- try testing.expect(isSignedInt(f64) == false);
-}
-
-pub fn isSingleItemPtr(comptime T: type) bool {
- if (comptime is(.Pointer)(T)) {
- return @typeInfo(T).Pointer.size == .One;
- }
- return false;
-}
-
-test "isSingleItemPtr" {
- const array = [_]u8{0} ** 10;
- try comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
- try comptime testing.expect(!isSingleItemPtr(@TypeOf(array)));
- var runtime_zero: usize = 0;
- _ = &runtime_zero;
- try testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1])));
-}
-
-pub fn isManyItemPtr(comptime T: type) bool {
- if (comptime is(.Pointer)(T)) {
- return @typeInfo(T).Pointer.size == .Many;
- }
- return false;
-}
-
-test "isManyItemPtr" {
- const array = [_]u8{0} ** 10;
- const mip = @as([*]const u8, @ptrCast(&array[0]));
- try testing.expect(isManyItemPtr(@TypeOf(mip)));
- try testing.expect(!isManyItemPtr(@TypeOf(array)));
- try testing.expect(!isManyItemPtr(@TypeOf(array[0..1])));
-}
-
-pub fn isSlice(comptime T: type) bool {
- if (comptime is(.Pointer)(T)) {
- return @typeInfo(T).Pointer.size == .Slice;
- }
- return false;
-}
-
-test "isSlice" {
- const array = [_]u8{0} ** 10;
- var runtime_zero: usize = 0;
- _ = &runtime_zero;
- try testing.expect(isSlice(@TypeOf(array[runtime_zero..])));
- try testing.expect(!isSlice(@TypeOf(array)));
- try testing.expect(!isSlice(@TypeOf(&array[0])));
-}
-
-pub fn isIndexable(comptime T: type) bool {
- if (comptime is(.Pointer)(T)) {
- if (@typeInfo(T).Pointer.size == .One) {
- return (comptime is(.Array)(meta.Child(T)));
- }
- return true;
- }
- return comptime is(.Array)(T) or is(.Vector)(T) or isTuple(T);
-}
-
-test "isIndexable" {
- const array = [_]u8{0} ** 10;
- const slice = @as([]const u8, &array);
- const vector: @Vector(2, u32) = [_]u32{0} ** 2;
- const tuple = .{ 1, 2, 3 };
-
- try testing.expect(isIndexable(@TypeOf(array)));
- try testing.expect(isIndexable(@TypeOf(&array)));
- try testing.expect(isIndexable(@TypeOf(slice)));
- try testing.expect(!isIndexable(meta.Child(@TypeOf(slice))));
- try testing.expect(isIndexable(@TypeOf(vector)));
- try testing.expect(isIndexable(@TypeOf(tuple)));
-}
-
-pub fn isNumber(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Int, .Float, .ComptimeInt, .ComptimeFloat => true,
- else => false,
- };
-}
-
-test "isNumber" {
- const NotANumber = struct {
- number: u8,
- };
-
- try testing.expect(isNumber(u32));
- try testing.expect(isNumber(f32));
- try testing.expect(isNumber(u64));
- try testing.expect(isNumber(@TypeOf(102)));
- try testing.expect(isNumber(@TypeOf(102.123)));
- try testing.expect(!isNumber([]u8));
- try testing.expect(!isNumber(NotANumber));
-}
-
-pub fn isIntegral(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Int, .ComptimeInt => true,
- else => false,
- };
-}
-
-test "isIntegral" {
- try testing.expect(isIntegral(u32));
- try testing.expect(!isIntegral(f32));
- try testing.expect(isIntegral(@TypeOf(102)));
- try testing.expect(!isIntegral(@TypeOf(102.123)));
- try testing.expect(!isIntegral(*u8));
- try testing.expect(!isIntegral([]u8));
-}
-
-pub fn isFloat(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Float, .ComptimeFloat => true,
- else => false,
- };
-}
-
-test "isFloat" {
- try testing.expect(!isFloat(u32));
- try testing.expect(isFloat(f32));
- try testing.expect(!isFloat(@TypeOf(102)));
- try testing.expect(isFloat(@TypeOf(102.123)));
- try testing.expect(!isFloat(*f64));
- try testing.expect(!isFloat([]f32));
-}
-
-pub fn isConstPtr(comptime T: type) bool {
- if (!comptime is(.Pointer)(T)) return false;
- return @typeInfo(T).Pointer.is_const;
-}
-
-test "isConstPtr" {
- var t: u8 = 0;
- t = t;
- const c: u8 = 0;
- try testing.expect(isConstPtr(*const @TypeOf(t)));
- try testing.expect(isConstPtr(@TypeOf(&c)));
- try testing.expect(!isConstPtr(*@TypeOf(t)));
- try testing.expect(!isConstPtr(@TypeOf(6)));
-}
-
-pub fn isContainer(comptime T: type) bool {
- return switch (@typeInfo(T)) {
- .Struct, .Union, .Enum, .Opaque => true,
- else => false,
- };
-}
-
-test "isContainer" {
- const TestStruct = struct {};
- const TestUnion = union {
- a: void,
- };
- const TestEnum = enum {
- A,
- B,
- };
- const TestOpaque = opaque {};
-
- try testing.expect(isContainer(TestStruct));
- try testing.expect(isContainer(TestUnion));
- try testing.expect(isContainer(TestEnum));
- try testing.expect(isContainer(TestOpaque));
- try testing.expect(!isContainer(u8));
-}
-
-pub fn isTuple(comptime T: type) bool {
- return is(.Struct)(T) and @typeInfo(T).Struct.is_tuple;
-}
-
-test "isTuple" {
- const t1 = struct {};
- const t2 = .{ .a = 0 };
- const t3 = .{ 1, 2, 3 };
- try testing.expect(!isTuple(t1));
- try testing.expect(!isTuple(@TypeOf(t2)));
- try testing.expect(isTuple(@TypeOf(t3)));
-}
-
-/// Returns true if the passed type will coerce to []const u8.
-/// Any of the following are considered strings:
-/// ```
-/// []const u8, [:S]const u8, *const [N]u8, *const [N:S]u8,
-/// []u8, [:S]u8, *[:S]u8, *[N:S]u8.
-/// ```
-/// These types are not considered strings:
-/// ```
-/// u8, [N]u8, [*]const u8, [*:0]const u8,
-/// [*]const [N]u8, []const u16, []const i8,
-/// *const u8, ?[]const u8, ?*const [N]u8.
-/// ```
-pub fn isZigString(comptime T: type) bool {
- return comptime blk: {
- // Only pointer types can be strings, no optionals
- const info = @typeInfo(T);
- if (info != .Pointer) break :blk false;
-
- const ptr = &info.Pointer;
- // Check for CV qualifiers that would prevent coerction to []const u8
- if (ptr.is_volatile or ptr.is_allowzero) break :blk false;
-
- // If it's already a slice, simple check.
- if (ptr.size == .Slice) {
- break :blk ptr.child == u8;
- }
-
- // Otherwise check if it's an array type that coerces to slice.
- if (ptr.size == .One) {
- const child = @typeInfo(ptr.child);
- if (child == .Array) {
- const arr = &child.Array;
- break :blk arr.child == u8;
- }
- }
-
- break :blk false;
- };
-}
-
-test "isZigString" {
- try testing.expect(isZigString([]const u8));
- try testing.expect(isZigString([]u8));
- try testing.expect(isZigString([:0]const u8));
- try testing.expect(isZigString([:0]u8));
- try testing.expect(isZigString([:5]const u8));
- try testing.expect(isZigString([:5]u8));
- try testing.expect(isZigString(*const [0]u8));
- try testing.expect(isZigString(*[0]u8));
- try testing.expect(isZigString(*const [0:0]u8));
- try testing.expect(isZigString(*[0:0]u8));
- try testing.expect(isZigString(*const [0:5]u8));
- try testing.expect(isZigString(*[0:5]u8));
- try testing.expect(isZigString(*const [10]u8));
- try testing.expect(isZigString(*[10]u8));
- try testing.expect(isZigString(*const [10:0]u8));
- try testing.expect(isZigString(*[10:0]u8));
- try testing.expect(isZigString(*const [10:5]u8));
- try testing.expect(isZigString(*[10:5]u8));
-
- try testing.expect(!isZigString(u8));
- try testing.expect(!isZigString([4]u8));
- try testing.expect(!isZigString([4:0]u8));
- try testing.expect(!isZigString([*]const u8));
- try testing.expect(!isZigString([*]const [4]u8));
- try testing.expect(!isZigString([*c]const u8));
- try testing.expect(!isZigString([*c]const [4]u8));
- try testing.expect(!isZigString([*:0]const u8));
- try testing.expect(!isZigString([*:0]const u8));
- try testing.expect(!isZigString(*[]const u8));
- try testing.expect(!isZigString(?[]const u8));
- try testing.expect(!isZigString(?*const [4]u8));
- try testing.expect(!isZigString([]allowzero u8));
- try testing.expect(!isZigString([]volatile u8));
- try testing.expect(!isZigString(*allowzero [4]u8));
- try testing.expect(!isZigString(*volatile [4]u8));
-}
-
-pub fn hasDecls(comptime T: type, comptime names: anytype) bool {
- inline for (names) |name| {
- if (!@hasDecl(T, name))
- return false;
- }
- return true;
-}
-
-test "hasDecls" {
- const TestStruct1 = struct {};
- const TestStruct2 = struct {
- pub var a: u32 = undefined;
- pub var b: u32 = undefined;
- c: bool,
- pub fn useless() void {}
- };
-
- const tuple = .{ "a", "b", "c" };
-
- try testing.expect(!hasDecls(TestStruct1, .{"a"}));
- try testing.expect(hasDecls(TestStruct2, .{ "a", "b" }));
- try testing.expect(hasDecls(TestStruct2, .{ "a", "b", "useless" }));
- try testing.expect(!hasDecls(TestStruct2, .{ "a", "b", "c" }));
- try testing.expect(!hasDecls(TestStruct2, tuple));
-}
-
-pub fn hasFields(comptime T: type, comptime names: anytype) bool {
- inline for (names) |name| {
- if (!@hasField(T, name))
- return false;
- }
- return true;
-}
-
-test "hasFields" {
- const TestStruct1 = struct {};
- const TestStruct2 = struct {
- a: u32,
- b: u32,
- c: bool,
- pub fn useless() void {}
- };
-
- const tuple = .{ "a", "b", "c" };
-
- try testing.expect(!hasFields(TestStruct1, .{"a"}));
- try testing.expect(hasFields(TestStruct2, .{ "a", "b" }));
- try testing.expect(hasFields(TestStruct2, .{ "a", "b", "c" }));
- try testing.expect(hasFields(TestStruct2, tuple));
- try testing.expect(!hasFields(TestStruct2, .{ "a", "b", "useless" }));
-}
-
-pub fn hasFunctions(comptime T: type, comptime names: anytype) bool {
- inline for (names) |name| {
- if (!hasFn(name)(T))
- return false;
- }
- return true;
-}
-
-test "hasFunctions" {
- const TestStruct1 = struct {};
- const TestStruct2 = struct {
- pub fn a() void {}
- fn b() void {}
- };
-
- const tuple = .{ "a", "b", "c" };
-
- try testing.expect(!hasFunctions(TestStruct1, .{"a"}));
- try testing.expect(hasFunctions(TestStruct2, .{ "a", "b" }));
- try testing.expect(!hasFunctions(TestStruct2, .{ "a", "b", "c" }));
- try testing.expect(!hasFunctions(TestStruct2, tuple));
-}
-
-/// True if every value of the type `T` has a unique bit pattern representing it.
-/// In other words, `T` has no unused bits and no padding.
-pub fn hasUniqueRepresentation(comptime T: type) bool {
- switch (@typeInfo(T)) {
- else => return false, // TODO can we know if it's true for some of these types ?
-
- .AnyFrame,
- .Enum,
- .ErrorSet,
- .Fn,
- => return true,
-
- .Bool => return false,
-
- .Int => |info| return @sizeOf(T) * 8 == info.bits,
-
- .Pointer => |info| return info.size != .Slice,
-
- .Array => |info| return comptime hasUniqueRepresentation(info.child),
-
- .Struct => |info| {
- var sum_size = @as(usize, 0);
-
- inline for (info.fields) |field| {
- const FieldType = field.type;
- if (comptime !hasUniqueRepresentation(FieldType)) return false;
- sum_size += @sizeOf(FieldType);
- }
-
- return @sizeOf(T) == sum_size;
- },
-
- .Vector => |info| return comptime hasUniqueRepresentation(info.child) and
- @sizeOf(T) == @sizeOf(info.child) * info.len,
- }
-}
-
-test "hasUniqueRepresentation" {
- const TestStruct1 = struct {
- a: u32,
- b: u32,
- };
-
- try testing.expect(hasUniqueRepresentation(TestStruct1));
-
- const TestStruct2 = struct {
- a: u32,
- b: u16,
- };
-
- try testing.expect(!hasUniqueRepresentation(TestStruct2));
-
- const TestStruct3 = struct {
- a: u32,
- b: u32,
- };
-
- try testing.expect(hasUniqueRepresentation(TestStruct3));
-
- const TestStruct4 = struct { a: []const u8 };
-
- try testing.expect(!hasUniqueRepresentation(TestStruct4));
-
- const TestStruct5 = struct { a: TestStruct4 };
-
- try testing.expect(!hasUniqueRepresentation(TestStruct5));
-
- const TestUnion1 = packed union {
- a: u32,
- b: u16,
- };
-
- try testing.expect(!hasUniqueRepresentation(TestUnion1));
-
- const TestUnion2 = extern union {
- a: u32,
- b: u16,
- };
-
- try testing.expect(!hasUniqueRepresentation(TestUnion2));
-
- const TestUnion3 = union {
- a: u32,
- b: u16,
- };
-
- try testing.expect(!hasUniqueRepresentation(TestUnion3));
-
- const TestUnion4 = union(enum) {
- a: u32,
- b: u16,
- };
-
- try testing.expect(!hasUniqueRepresentation(TestUnion4));
-
- inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
- try testing.expect(hasUniqueRepresentation(T));
- }
- inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
- try testing.expect(!hasUniqueRepresentation(T));
- }
-
- try testing.expect(!hasUniqueRepresentation([]u8));
- try testing.expect(!hasUniqueRepresentation([]const u8));
-
- try testing.expect(hasUniqueRepresentation(@Vector(4, u16)));
-}
lib/std/array_hash_map.zig
@@ -4,8 +4,6 @@ const assert = debug.assert;
const testing = std.testing;
const math = std.math;
const mem = std.mem;
-const meta = std.meta;
-const trait = meta.trait;
const autoHash = std.hash.autoHash;
const Wyhash = std.hash.Wyhash;
const Allocator = mem.Allocator;
@@ -2341,13 +2339,13 @@ test "reIndex" {
test "auto store_hash" {
const HasCheapEql = AutoArrayHashMap(i32, i32);
const HasExpensiveEql = AutoArrayHashMap([32]i32, i32);
- try testing.expect(meta.fieldInfo(HasCheapEql.Data, .hash).type == void);
- try testing.expect(meta.fieldInfo(HasExpensiveEql.Data, .hash).type != void);
+ try testing.expect(std.meta.fieldInfo(HasCheapEql.Data, .hash).type == void);
+ try testing.expect(std.meta.fieldInfo(HasExpensiveEql.Data, .hash).type != void);
const HasCheapEqlUn = AutoArrayHashMapUnmanaged(i32, i32);
const HasExpensiveEqlUn = AutoArrayHashMapUnmanaged([32]i32, i32);
- try testing.expect(meta.fieldInfo(HasCheapEqlUn.Data, .hash).type == void);
- try testing.expect(meta.fieldInfo(HasExpensiveEqlUn.Data, .hash).type != void);
+ try testing.expect(std.meta.fieldInfo(HasCheapEqlUn.Data, .hash).type == void);
+ try testing.expect(std.meta.fieldInfo(HasExpensiveEqlUn.Data, .hash).type != void);
}
test "sort" {
@@ -2434,12 +2432,12 @@ pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K)
return struct {
fn hash(ctx: Context, key: K) u32 {
_ = ctx;
- if (comptime trait.hasUniqueRepresentation(K)) {
- return @as(u32, @truncate(Wyhash.hash(0, std.mem.asBytes(&key))));
+ if (std.meta.hasUniqueRepresentation(K)) {
+ return @truncate(Wyhash.hash(0, std.mem.asBytes(&key)));
} else {
var hasher = Wyhash.init(0);
autoHash(&hasher, key);
- return @as(u32, @truncate(hasher.final()));
+ return @truncate(hasher.final());
}
}
}.hash;
@@ -2450,7 +2448,7 @@ pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K
fn eql(ctx: Context, a: K, b: K, b_index: usize) bool {
_ = b_index;
_ = ctx;
- return meta.eql(a, b);
+ return std.meta.eql(a, b);
}
}.eql;
}
lib/std/enums.zig
@@ -201,7 +201,7 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E {
if (V == E) break :blk value;
const name: ?[]const u8 = switch (@typeInfo(V)) {
.EnumLiteral, .Enum => @tagName(value),
- .Pointer => if (std.meta.trait.isZigString(V)) value else null,
+ .Pointer => value,
else => null,
};
if (name) |n| {
lib/std/fmt.zig
@@ -478,7 +478,7 @@ pub fn formatType(
return formatAddress(value, options, writer);
}
- if (comptime std.meta.trait.hasFn("format")(T)) {
+ if (std.meta.hasFn(T, "format")) {
return try value.format(actual_fmt, options, writer);
}
@@ -611,15 +611,12 @@ pub fn formatType(
else => {},
}
}
- if (comptime std.meta.trait.isZigString(info.child)) {
- for (value, 0..) |item, i| {
- comptime checkTextFmt(actual_fmt);
- if (i != 0) try formatBuf(", ", options, writer);
- try formatBuf(item, options, writer);
- }
- return;
+ for (value, 0..) |item, i| {
+ comptime checkTextFmt(actual_fmt);
+ if (i != 0) try formatBuf(", ", options, writer);
+ try formatBuf(item, options, writer);
}
- invalidFmtError(fmt, value);
+ return;
},
.Enum, .Union, .Struct => {
return formatType(value.*, actual_fmt, options, writer, max_depth);
lib/std/hash_map.zig
@@ -4,8 +4,6 @@ const assert = std.debug.assert;
const autoHash = std.hash.autoHash;
const math = std.math;
const mem = std.mem;
-const meta = std.meta;
-const trait = meta.trait;
const Allocator = mem.Allocator;
const Wyhash = std.hash.Wyhash;
@@ -24,7 +22,7 @@ pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K)
return struct {
fn hash(ctx: Context, key: K) u64 {
_ = ctx;
- if (comptime trait.hasUniqueRepresentation(K)) {
+ if (std.meta.hasUniqueRepresentation(K)) {
return Wyhash.hash(0, std.mem.asBytes(&key));
} else {
var hasher = Wyhash.init(0);
@@ -39,7 +37,7 @@ pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K
return struct {
fn eql(ctx: Context, a: K, b: K) bool {
_ = ctx;
- return meta.eql(a, b);
+ return std.meta.eql(a, b);
}
}.eql;
}
lib/std/math.zig
@@ -801,7 +801,7 @@ fn testDivFloor() !void {
/// zero.
pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T {
@setRuntimeSafety(false);
- if ((comptime std.meta.trait.isNumber(T)) and denominator == 0) return error.DivisionByZero;
+ if (denominator == 0) return error.DivisionByZero;
const info = @typeInfo(T);
switch (info) {
.ComptimeFloat, .Float => return @ceil(numerator / denominator),
lib/std/mem.zig
@@ -4,8 +4,6 @@ const debug = std.debug;
const assert = debug.assert;
const math = std.math;
const mem = @This();
-const meta = std.meta;
-const trait = meta.trait;
const testing = std.testing;
const Endian = std.builtin.Endian;
const native_endian = builtin.cpu.arch.endian();
@@ -736,7 +734,7 @@ test "span" {
}
/// Helper for the return type of sliceTo()
-fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
+fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type {
switch (@typeInfo(T)) {
.Optional => |optional_info| {
return ?SliceTo(optional_info.child, end);
@@ -796,7 +794,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
/// resulting slice is also sentinel terminated.
/// Pointer properties such as mutability and alignment are preserved.
/// C pointers are assumed to be non-null.
-pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
+pub fn sliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
if (@typeInfo(@TypeOf(ptr)) == .Optional) {
const non_null = ptr orelse return null;
return sliceTo(non_null, end);
@@ -852,7 +850,7 @@ test "sliceTo" {
}
/// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len
-fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
+fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
switch (@typeInfo(@TypeOf(ptr))) {
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => switch (@typeInfo(ptr_info.child)) {
@@ -1319,7 +1317,7 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us
if (needle.len > haystack.len) return null;
if (needle.len == 0) return haystack.len;
- if (!meta.trait.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
+ if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
return lastIndexOfLinear(T, haystack, needle);
const haystack_bytes = sliceAsBytes(haystack);
@@ -1350,7 +1348,7 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
return indexOfScalarPos(T, haystack, start_index, needle[0]);
}
- if (!meta.trait.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
+ if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
return indexOfPosLinear(T, haystack, start_index, needle);
const haystack_bytes = sliceAsBytes(haystack);
@@ -3368,13 +3366,7 @@ fn ReverseIterator(comptime T: type) type {
/// Iterates over a slice in reverse.
pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {
- const T = @TypeOf(slice);
- if (comptime trait.isPtrTo(.Array)(T)) {
- return .{ .ptr = slice, .index = slice.len };
- } else {
- comptime assert(trait.isSlice(T));
- return .{ .ptr = slice.ptr, .index = slice.len };
- }
+ return .{ .ptr = slice.ptr, .index = slice.len };
}
test "reverseIterator" {
@@ -3394,7 +3386,7 @@ test "reverseIterator" {
try testing.expectEqual(@as(?i32, null), it.next());
it = reverseIterator(slice);
- try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
+ try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
@@ -3414,7 +3406,7 @@ test "reverseIterator" {
try testing.expectEqual(@as(?i32, null), it.next());
it = reverseIterator(ptr_to_array);
- try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
+ try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
@@ -3730,11 +3722,7 @@ fn CopyPtrAttrs(
}
fn AsBytesReturnType(comptime P: type) type {
- if (!trait.isSingleItemPtr(P))
- @compileError("expected single item pointer, passed " ++ @typeName(P));
-
- const size = @sizeOf(meta.Child(P));
-
+ const size = @sizeOf(std.meta.Child(P));
return CopyPtrAttrs(P, .One, [size]u8);
}
@@ -3818,21 +3806,13 @@ test "toBytes" {
}
fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
- const size = @as(usize, @sizeOf(T));
-
- if (comptime !trait.is(.Pointer)(B) or
- (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))
- {
- @compileError(std.fmt.comptimePrint("expected *[{}]u8, passed " ++ @typeName(B), .{size}));
- }
-
return CopyPtrAttrs(B, .One, T);
}
/// Given a pointer to an array of bytes, returns a pointer to a value of the specified type
/// backed by those bytes, preserving pointer attributes.
pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
- return @as(BytesAsValueReturnType(T, @TypeOf(bytes)), @ptrCast(bytes));
+ return @ptrCast(bytes);
}
test "bytesAsValue" {
@@ -3872,7 +3852,7 @@ test "bytesAsValue" {
.big => "\xA1\xDE\xEF\xBE",
};
const inst2 = bytesAsValue(S, inst_bytes);
- try testing.expect(meta.eql(inst, inst2.*));
+ try testing.expect(std.meta.eql(inst, inst2.*));
}
test "bytesAsValue preserves pointer attributes" {
@@ -3905,14 +3885,6 @@ test "bytesToValue" {
}
fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
- if (!(trait.isSlice(bytesType) or trait.isPtrTo(.Array)(bytesType)) or meta.Elem(bytesType) != u8) {
- @compileError("expected []u8 or *[_]u8, passed " ++ @typeName(bytesType));
- }
-
- if (trait.isPtrTo(.Array)(bytesType) and @typeInfo(meta.Child(bytesType)).Array.len % @sizeOf(T) != 0) {
- @compileError("number of bytes in " ++ @typeName(bytesType) ++ " is not divisible by size of " ++ @typeName(T));
- }
-
return CopyPtrAttrs(bytesType, .Slice, T);
}
@@ -4000,10 +3972,6 @@ test "bytesAsSlice preserves pointer attributes" {
}
fn SliceAsBytesReturnType(comptime Slice: type) type {
- if (!trait.isSlice(Slice) and !trait.isPtrTo(.Array)(Slice)) {
- @compileError("expected []T or *[_]T, passed " ++ @typeName(Slice));
- }
-
return CopyPtrAttrs(Slice, .Slice, u8);
}
@@ -4012,15 +3980,15 @@ pub fn sliceAsBytes(slice: anytype) SliceAsBytesReturnType(@TypeOf(slice)) {
const Slice = @TypeOf(slice);
// a slice of zero-bit values always occupies zero bytes
- if (@sizeOf(meta.Elem(Slice)) == 0) return &[0]u8{};
+ if (@sizeOf(std.meta.Elem(Slice)) == 0) return &[0]u8{};
// let's not give an undefined pointer to @ptrCast
// it may be equal to zero and fail a null check
- if (slice.len == 0 and comptime meta.sentinel(Slice) == null) return &[0]u8{};
+ if (slice.len == 0 and std.meta.sentinel(Slice) == null) return &[0]u8{};
const cast_target = CopyPtrAttrs(Slice, .Many, u8);
- return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
+ return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(std.meta.Elem(Slice))];
}
test "sliceAsBytes" {
lib/std/meta.zig
@@ -5,7 +5,6 @@ const math = std.math;
const testing = std.testing;
const root = @import("root");
-pub const trait = @import("meta/trait.zig");
pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags;
const Type = std.builtin.Type;
@@ -135,7 +134,8 @@ test "std.meta.Elem" {
/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
/// or `null` if there is not one.
/// Types which cannot possibly have a sentinel will be a compile error.
-pub fn sentinel(comptime T: type) ?Elem(T) {
+/// Result is always comptime-known.
+pub inline fn sentinel(comptime T: type) ?Elem(T) {
switch (@typeInfo(T)) {
.Array => |info| {
const sentinel_ptr = info.sentinel orelse return null;
@@ -162,7 +162,7 @@ pub fn sentinel(comptime T: type) ?Elem(T) {
@compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
}
-test "std.meta.sentinel" {
+test sentinel {
try testSentinel();
try comptime testSentinel();
}
@@ -712,8 +712,6 @@ test "std.meta.activeTag" {
const TagPayloadType = TagPayload;
pub fn TagPayloadByName(comptime U: type, comptime tag_name: []const u8) type {
- comptime debug.assert(trait.is(.Union)(U));
-
const info = @typeInfo(U).Union;
inline for (info.fields) |field_info| {
@@ -1117,3 +1115,124 @@ test "isError" {
try std.testing.expect(isError(math.divTrunc(u8, 5, 0)));
try std.testing.expect(!isError(math.divTrunc(u8, 5, 5)));
}
+
+/// Returns true if a type has a namespace and the namespace contains `name`;
+/// `false` otherwise. Result is always comptime-known.
+pub inline fn hasFn(comptime T: type, comptime name: []const u8) bool {
+ switch (@typeInfo(T)) {
+ .Struct, .Union, .Enum, .Opaque => {},
+ else => return false,
+ }
+ if (!@hasDecl(T, name))
+ return false;
+
+ return @typeInfo(@TypeOf(@field(T, name))) == .Fn;
+}
+
+/// True if every value of the type `T` has a unique bit pattern representing it.
+/// In other words, `T` has no unused bits and no padding.
+/// Result is always comptime-known.
+pub inline fn hasUniqueRepresentation(comptime T: type) bool {
+ return switch (@typeInfo(T)) {
+ else => false, // TODO can we know if it's true for some of these types ?
+
+ .AnyFrame,
+ .Enum,
+ .ErrorSet,
+ .Fn,
+ => true,
+
+ .Bool => false,
+
+ .Int => |info| @sizeOf(T) * 8 == info.bits,
+
+ .Pointer => |info| info.size != .Slice,
+
+ .Array => |info| hasUniqueRepresentation(info.child),
+
+ .Struct => |info| {
+ var sum_size = @as(usize, 0);
+
+ inline for (info.fields) |field| {
+ if (!hasUniqueRepresentation(field.type)) return false;
+ sum_size += @sizeOf(field.type);
+ }
+
+ return @sizeOf(T) == sum_size;
+ },
+
+ .Vector => |info| hasUniqueRepresentation(info.child) and
+ @sizeOf(T) == @sizeOf(info.child) * info.len,
+ };
+}
+
+test "hasUniqueRepresentation" {
+ const TestStruct1 = struct {
+ a: u32,
+ b: u32,
+ };
+
+ try testing.expect(hasUniqueRepresentation(TestStruct1));
+
+ const TestStruct2 = struct {
+ a: u32,
+ b: u16,
+ };
+
+ try testing.expect(!hasUniqueRepresentation(TestStruct2));
+
+ const TestStruct3 = struct {
+ a: u32,
+ b: u32,
+ };
+
+ try testing.expect(hasUniqueRepresentation(TestStruct3));
+
+ const TestStruct4 = struct { a: []const u8 };
+
+ try testing.expect(!hasUniqueRepresentation(TestStruct4));
+
+ const TestStruct5 = struct { a: TestStruct4 };
+
+ try testing.expect(!hasUniqueRepresentation(TestStruct5));
+
+ const TestUnion1 = packed union {
+ a: u32,
+ b: u16,
+ };
+
+ try testing.expect(!hasUniqueRepresentation(TestUnion1));
+
+ const TestUnion2 = extern union {
+ a: u32,
+ b: u16,
+ };
+
+ try testing.expect(!hasUniqueRepresentation(TestUnion2));
+
+ const TestUnion3 = union {
+ a: u32,
+ b: u16,
+ };
+
+ try testing.expect(!hasUniqueRepresentation(TestUnion3));
+
+ const TestUnion4 = union(enum) {
+ a: u32,
+ b: u16,
+ };
+
+ try testing.expect(!hasUniqueRepresentation(TestUnion4));
+
+ inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
+ try testing.expect(hasUniqueRepresentation(T));
+ }
+ inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
+ try testing.expect(!hasUniqueRepresentation(T));
+ }
+
+ try testing.expect(!hasUniqueRepresentation([]u8));
+ try testing.expect(!hasUniqueRepresentation([]const u8));
+
+ try testing.expect(hasUniqueRepresentation(@Vector(4, u16)));
+}
lib/std/rand.zig
@@ -3,8 +3,6 @@
//! use `std.crypto.random`.
//! Be sure to use a CSPRNG when required, otherwise using a normal PRNG will
//! be faster and use substantially less stack space.
-//!
-//! TODO(tiehuis): Benchmark these against other reference implementations.
const std = @import("std.zig");
const builtin = @import("builtin");
@@ -383,34 +381,34 @@ pub const Random = struct {
/// This is useful for selecting an item from a slice where weights are not equal.
/// `T` must be a numeric type capable of holding the sum of `proportions`.
pub fn weightedIndex(r: std.rand.Random, comptime T: type, proportions: []const T) usize {
- // This implementation works by summing the proportions and picking a random
- // point in [0, sum). We then loop over the proportions, accumulating
- // until our accumulator is greater than the random point.
-
- var sum: T = 0;
- for (proportions) |v| {
- sum += v;
- }
+ // This implementation works by summing the proportions and picking a
+ // random point in [0, sum). We then loop over the proportions,
+ // accumulating until our accumulator is greater than the random point.
+
+ const sum = s: {
+ var sum: T = 0;
+ for (proportions) |v| sum += v;
+ break :s sum;
+ };
- const point = if (comptime std.meta.trait.isSignedInt(T))
- r.intRangeLessThan(T, 0, sum)
- else if (comptime std.meta.trait.isUnsignedInt(T))
- r.uintLessThan(T, sum)
- else if (comptime std.meta.trait.isFloat(T))
+ const point = switch (@typeInfo(T)) {
+ .Int => |int_info| switch (int_info.signedness) {
+ .signed => r.intRangeLessThan(T, 0, sum),
+ .unsigned => r.uintLessThan(T, sum),
+ },
// take care that imprecision doesn't lead to a value slightly greater than sum
- @min(r.float(T) * sum, sum - std.math.floatEps(T))
- else
- @compileError("weightedIndex does not support proportions of type " ++ @typeName(T));
+ .Float => @min(r.float(T) * sum, sum - std.math.floatEps(T)),
+ else => @compileError("weightedIndex does not support proportions of type " ++
+ @typeName(T)),
+ };
- std.debug.assert(point < sum);
+ assert(point < sum);
var accumulator: T = 0;
for (proportions, 0..) |p, index| {
accumulator += p;
if (point < accumulator) return index;
- }
-
- unreachable;
+ } else unreachable;
}
/// Returns the smallest of `Index` and `usize`.
lib/std/target.zig
@@ -823,7 +823,6 @@ pub const Target = struct {
/// Returns true if any specified feature is enabled.
pub fn featureSetHasAny(set: Set, features: anytype) bool {
- comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
inline for (features) |feature| {
if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
}
@@ -832,7 +831,6 @@ pub const Target = struct {
/// Returns true if every specified feature is enabled.
pub fn featureSetHasAll(set: Set, features: anytype) bool {
- comptime std.debug.assert(std.meta.trait.isIndexable(@TypeOf(features)));
inline for (features) |feature| {
if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
}
src/link/Wasm/Object.zig
@@ -838,11 +838,10 @@ fn ElementType(comptime ptr: type) type {
/// signedness of the given type `T`.
/// Asserts `T` is an integer.
fn readLeb(comptime T: type, reader: anytype) !T {
- if (comptime std.meta.trait.isSignedInt(T)) {
- return try leb.readILEB128(T, reader);
- } else {
- return try leb.readULEB128(T, reader);
- }
+ return switch (@typeInfo(T).Int.signedness) {
+ .signed => try leb.readILEB128(T, reader),
+ .unsigned => try leb.readULEB128(T, reader),
+ };
}
/// Reads an enum type from the given reader.
src/translate_c.zig
@@ -4567,7 +4567,10 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
}
fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
- const fmt_s = if (comptime meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}";
+ const fmt_s = switch (@typeInfo(@TypeOf(num))) {
+ .Int, .ComptimeInt => "{d}",
+ else => "{s}",
+ };
const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num});
if (num_kind == .float)
return Tag.float_literal.create(c.arena, str)
test/behavior/vector.zig
@@ -542,7 +542,11 @@ test "vector division operators" {
const S = struct {
fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
- if (!comptime std.meta.trait.isSignedInt(T)) {
+ const is_signed_int = switch (@typeInfo(T)) {
+ .Int => |info| info.signedness == .signed,
+ else => false,
+ };
+ if (!is_signed_int) {
const d0 = x / y;
for (@as([4]T, d0), 0..) |v, i| {
try expect(x[i] / y[i] == v);
@@ -563,7 +567,11 @@ test "vector division operators" {
}
fn doTheTestMod(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
- if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {
+ const is_signed_int = switch (@typeInfo(T)) {
+ .Int => |info| info.signedness == .signed,
+ else => false,
+ };
+ if (!is_signed_int and @typeInfo(T) != .Float) {
const r0 = x % y;
for (@as([4]T, r0), 0..) |v, i| {
try expect(x[i] % y[i] == v);
test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig
@@ -5,10 +5,38 @@ pub export fn entry() void {
_ = sliceAsBytes(ohnoes);
_ = &ohnoes;
}
-fn sliceAsBytes(slice: anytype) std.meta.trait.isPtrTo(.Array)(@TypeOf(slice)) {}
+fn sliceAsBytes(slice: anytype) isPtrTo(.Array)(@TypeOf(slice)) {}
+
+pub const TraitFn = fn (type) bool;
+
+pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn {
+ const Closure = struct {
+ pub fn trait(comptime T: type) bool {
+ if (!comptime isSingleItemPtr(T)) return false;
+ return id == @typeInfo(std.meta.Child(T));
+ }
+ };
+ return Closure.trait;
+}
+
+pub fn isSingleItemPtr(comptime T: type) bool {
+ if (comptime is(.Pointer)(T)) {
+ return @typeInfo(T).Pointer.size == .One;
+ }
+ return false;
+}
+
+pub fn is(comptime id: std.builtin.TypeId) TraitFn {
+ const Closure = struct {
+ pub fn trait(comptime T: type) bool {
+ return id == @typeInfo(T);
+ }
+ };
+ return Closure.trait;
+}
// error
// backend=llvm
// target=native
//
-// :8:63: error: expected type 'type', found 'bool'
+// :8:48: error: expected type 'type', found 'bool'
CMakeLists.txt
@@ -290,7 +290,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/mem/Allocator.zig"
"${CMAKE_SOURCE_DIR}/lib/std/meta.zig"
"${CMAKE_SOURCE_DIR}/lib/std/meta/trailer_flags.zig"
- "${CMAKE_SOURCE_DIR}/lib/std/meta/trait.zig"
"${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"