Processed review comments. Updated documentation, used the typinfo for field access, generate compile error on allowzero and set C poitners to null

This commit is contained in:
Bas van den Berg 2020-02-24 22:15:04 +01:00
parent 195195d238
commit f7aa4f5280

View File

@ -276,8 +276,12 @@ pub fn set(comptime T: type, dest: []T, value: T) void {
d.* = value; d.* = value;
} }
/// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function.
/// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when
/// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this
/// function used, examine closely - it may be a code smell.
/// Zero initializes the type. /// Zero initializes the type.
/// This can be used to zero initialize a C-struct. /// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively.
pub fn zeroes(comptime T: type) T { pub fn zeroes(comptime T: type) T {
switch (@typeInfo(T)) { switch (@typeInfo(T)) {
.ComptimeInt, .Int, .ComptimeFloat, .Float => { .ComptimeInt, .Int, .ComptimeFloat, .Float => {
@ -295,7 +299,7 @@ pub fn zeroes(comptime T: type) T {
.Optional, .Null => { .Optional, .Null => {
return null; return null;
}, },
.Struct => { .Struct => |struct_info| {
if (@sizeOf(T) == 0) return T{}; if (@sizeOf(T) == 0) return T{};
if (comptime meta.containerLayout(T) == .Extern) { if (comptime meta.containerLayout(T) == .Extern) {
var item: T = undefined; var item: T = undefined;
@ -303,25 +307,23 @@ pub fn zeroes(comptime T: type) T {
return item; return item;
} else { } else {
var structure: T = undefined; var structure: T = undefined;
comptime var field_i = 0; inline for (struct_info.fields) |field| {
inline while (field_i < @memberCount(T)) : (field_i += 1) { @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name)));
@field(structure, @memberName(T, field_i)) = zeroes(@TypeOf(@field(structure, @memberName(T, field_i))));
} }
return structure; return structure;
} }
}, },
.Pointer => |ptr_info| { .Pointer => |ptr_info| {
if (ptr_info.is_allowzero) { switch (ptr_info.size) {
return null; .Slice => {
} else { return &[_]ptr_info.child{};
switch (ptr_info.size) { },
.Slice => { .C => {
return &[_]ptr_info.child{}; return null;
}, },
.One, .Many, .C => { .One, .Many => {
@compileError("Can't set a non nullable pointer to zero."); @compileError("Can't set a non nullable pointer to zero.");
}, },
}
} }
}, },
.Array => |info| { .Array => |info| {
@ -372,6 +374,7 @@ test "mem.zeroes" {
const Pointers = struct { const Pointers = struct {
optional: ?*u8, optional: ?*u8,
c_pointer: [*c]u8,
slice: []u8, slice: []u8,
}; };
pointers: Pointers, pointers: Pointers,
@ -397,6 +400,7 @@ test "mem.zeroes" {
testing.expectEqual(@as(f32, 0), b.integral_types.float_32); testing.expectEqual(@as(f32, 0), b.integral_types.float_32);
testing.expectEqual(@as(f64, 0), b.integral_types.float_64); testing.expectEqual(@as(f64, 0), b.integral_types.float_64);
testing.expectEqual(@as(?*u8, null), b.pointers.optional); testing.expectEqual(@as(?*u8, null), b.pointers.optional);
testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer);
testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice);
for (b.array) |e| { for (b.array) |e| {
testing.expectEqual(@as(u32, 0), e); testing.expectEqual(@as(u32, 0), e);