mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std: remove meta.trait
In general, I don't like the idea of std.meta.trait, and so I am providing some guidance by deleting the entire namespace from the standard library and compiler codebase. My main criticism is that it's overcomplicated machinery that bloats compile times and is ultimately unnecessary given the existence of Zig's strong type system and reference traces. Users who want this can create a third party package that provides this functionality. closes #18051
This commit is contained in:
parent
994e191643
commit
d5e21a4f1a
23 changed files with 389 additions and 974 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,11 +153,6 @@ 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 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);
|
||||
}
|
||||
|
|
@ -173,9 +168,7 @@ pub fn Atomic(comptime T: type) type {
|
|||
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);
|
||||
}
|
||||
|
|
@ -307,9 +300,8 @@ pub fn Atomic(comptime T: type) type {
|
|||
// TODO: emit appropriate tsan fence if compiling with tsan
|
||||
_ = ordering;
|
||||
|
||||
return @as(u1, @intCast(old_bit));
|
||||
return @intCast(old_bit);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
invalidFmtError(fmt, value);
|
||||
},
|
||||
.Enum, .Union, .Struct => {
|
||||
return formatType(value.*, actual_fmt, options, writer, max_depth);
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (meta.trait.is(.Union)(K)) {
|
||||
inline for (@typeInfo(K).Union.fields) |field| {
|
||||
if (typeContainsSlice(field.type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
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" {
|
||||
|
|
|
|||
129
lib/std/meta.zig
129
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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
@ -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.
|
||||
// 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;
|
||||
}
|
||||
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`.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue