| ... | @@ -276,8 +276,12 @@ pub fn set(comptime T: type, dest: []T, value: T) void { | ... | @@ -276,8 +276,12 @@ pub fn set(comptime T: type, dest: []T, value: T) void { |
| 276 | d.* = value; | 276 | d.* = value; |
| 277 | } | 277 | } |
| 278 | | 278 | |
| | 279 | /// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function. |
| | 280 | /// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when |
| | 281 | /// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this |
| | 282 | /// function used, examine closely - it may be a code smell. |
| 279 | /// Zero initializes the type. | 283 | /// Zero initializes the type. |
| 280 | /// This can be used to zero initialize a C-struct. | 284 | /// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively. |
| 281 | pub fn zeroes(comptime T: type) T { | 285 | pub fn zeroes(comptime T: type) T { |
| 282 | switch (@typeInfo(T)) { | 286 | switch (@typeInfo(T)) { |
| 283 | .ComptimeInt, .Int, .ComptimeFloat, .Float => { | 287 | .ComptimeInt, .Int, .ComptimeFloat, .Float => { |
| ... | @@ -295,7 +299,7 @@ pub fn zeroes(comptime T: type) T { | ... | @@ -295,7 +299,7 @@ pub fn zeroes(comptime T: type) T { |
| 295 | .Optional, .Null => { | 299 | .Optional, .Null => { |
| 296 | return null; | 300 | return null; |
| 297 | }, | 301 | }, |
| 298 | .Struct => { | 302 | .Struct => |struct_info| { |
| 299 | if (@sizeOf(T) == 0) return T{}; | 303 | if (@sizeOf(T) == 0) return T{}; |
| 300 | if (comptime meta.containerLayout(T) == .Extern) { | 304 | if (comptime meta.containerLayout(T) == .Extern) { |
| 301 | var item: T = undefined; | 305 | var item: T = undefined; |
| ... | @@ -303,25 +307,23 @@ pub fn zeroes(comptime T: type) T { | ... | @@ -303,25 +307,23 @@ pub fn zeroes(comptime T: type) T { |
| 303 | return item; | 307 | return item; |
| 304 | } else { | 308 | } else { |
| 305 | var structure: T = undefined; | 309 | var structure: T = undefined; |
| 306 | comptime var field_i = 0; | 310 | inline for (struct_info.fields) |field| { |
| 307 | inline while (field_i < @memberCount(T)) : (field_i += 1) { | 311 | @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name))); |
| 308 | @field(structure, @memberName(T, field_i)) = zeroes(@TypeOf(@field(structure, @memberName(T, field_i)))); | | |
| 309 | } | 312 | } |
| 310 | return structure; | 313 | return structure; |
| 311 | } | 314 | } |
| 312 | }, | 315 | }, |
| 313 | .Pointer => |ptr_info| { | 316 | .Pointer => |ptr_info| { |
| 314 | if (ptr_info.is_allowzero) { | 317 | switch (ptr_info.size) { |
| 315 | return null; | 318 | .Slice => { |
| 316 | } else { | 319 | return &[_]ptr_info.child{}; |
| 317 | switch (ptr_info.size) { | 320 | }, |
| 318 | .Slice => { | 321 | .C => { |
| 319 | return &[_]ptr_info.child{}; | 322 | return null; |
| 320 | }, | 323 | }, |
| 321 | .One, .Many, .C => { | 324 | .One, .Many => { |
| 322 | @compileError("Can't set a non nullable pointer to zero."); | 325 | @compileError("Can't set a non nullable pointer to zero."); |
| 323 | }, | 326 | }, |
| 324 | } | | |
| 325 | } | 327 | } |
| 326 | }, | 328 | }, |
| 327 | .Array => |info| { | 329 | .Array => |info| { |
| ... | @@ -372,6 +374,7 @@ test "mem.zeroes" { | ... | @@ -372,6 +374,7 @@ test "mem.zeroes" { |
| 372 | | 374 | |
| 373 | const Pointers = struct { | 375 | const Pointers = struct { |
| 374 | optional: ?*u8, | 376 | optional: ?*u8, |
| | 377 | c_pointer: [*c]u8, |
| 375 | slice: []u8, | 378 | slice: []u8, |
| 376 | }; | 379 | }; |
| 377 | pointers: Pointers, | 380 | pointers: Pointers, |
| ... | @@ -397,6 +400,7 @@ test "mem.zeroes" { | ... | @@ -397,6 +400,7 @@ test "mem.zeroes" { |
| 397 | testing.expectEqual(@as(f32, 0), b.integral_types.float_32); | 400 | testing.expectEqual(@as(f32, 0), b.integral_types.float_32); |
| 398 | testing.expectEqual(@as(f64, 0), b.integral_types.float_64); | 401 | testing.expectEqual(@as(f64, 0), b.integral_types.float_64); |
| 399 | testing.expectEqual(@as(?*u8, null), b.pointers.optional); | 402 | testing.expectEqual(@as(?*u8, null), b.pointers.optional); |
| | 403 | testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer); |
| 400 | testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); | 404 | testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); |
| 401 | for (b.array) |e| { | 405 | for (b.array) |e| { |
| 402 | testing.expectEqual(@as(u32, 0), e); | 406 | testing.expectEqual(@as(u32, 0), e); |