authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-24 22:01:56-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-24 22:01:56-05:00
log5503f3f7c427d648c3e9a2280cc7a2ba102379d6
treeff9282739c73737e904069c57ffdb98add32b913
parent61a50a23e88945af71c0e4c56bf378869c670f49
parentf7aa4f5280e170966e8a7ed92468f76fa87963e1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4544 from BarabasGitHub/zeroes-for-non-extern-types

implement zeroes for non extern structs and native types

1 files changed, 114 insertions(+), 9 deletions(-)

lib/std/mem.zig+114-9
...@@ -276,18 +276,67 @@ pub fn set(comptime T: type, dest: []T, value: T) void {...@@ -276,18 +276,67 @@ pub fn set(comptime T: type, dest: []T, value: T) void {
276 d.* = value;276 d.* = value;
277}277}
278278
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.
281pub fn zeroes(comptime T: type) T {285pub fn zeroes(comptime T: type) T {
282 if (@sizeOf(T) == 0) return T{};286 switch (@typeInfo(T)) {
283287 .ComptimeInt, .Int, .ComptimeFloat, .Float => {
284 if (comptime meta.containerLayout(T) != .Extern) {288 return @as(T, 0);
285 @compileError("TODO: Currently this only works for extern types");289 },
290 .Enum, .EnumLiteral => {
291 return @intToEnum(T, 0);
292 },
293 .Void => {
294 return {};
295 },
296 .Bool => {
297 return false;
298 },
299 .Optional, .Null => {
300 return null;
301 },
302 .Struct => |struct_info| {
303 if (@sizeOf(T) == 0) return T{};
304 if (comptime meta.containerLayout(T) == .Extern) {
305 var item: T = undefined;
306 @memset(@ptrCast([*]u8, &item), 0, @sizeOf(T));
307 return item;
308 } else {
309 var structure: T = undefined;
310 inline for (struct_info.fields) |field| {
311 @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name)));
312 }
313 return structure;
314 }
315 },
316 .Pointer => |ptr_info| {
317 switch (ptr_info.size) {
318 .Slice => {
319 return &[_]ptr_info.child{};
320 },
321 .C => {
322 return null;
323 },
324 .One, .Many => {
325 @compileError("Can't set a non nullable pointer to zero.");
326 },
327 }
328 },
329 .Array => |info| {
330 var array: T = undefined;
331 for (array) |*element| {
332 element.* = zeroes(info.child);
333 }
334 return array;
335 },
336 .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {
337 @compileError("Can't set a "++ @typeName(T) ++" to zero.");
338 },
286 }339 }
287
288 var item: T = undefined;
289 @memset(@ptrCast([*]u8, &item), 0, @sizeOf(T));
290 return item;
291}340}
292341
293test "mem.zeroes" {342test "mem.zeroes" {
...@@ -301,6 +350,62 @@ test "mem.zeroes" {...@@ -301,6 +350,62 @@ test "mem.zeroes" {
301350
302 testing.expect(a.x == 0);351 testing.expect(a.x == 0);
303 testing.expect(a.y == 10);352 testing.expect(a.y == 10);
353
354 const ZigStruct = struct {
355 const IntegralTypes = struct {
356 integer_0: i0,
357 integer_8: i8,
358 integer_16: i16,
359 integer_32: i32,
360 integer_64: i64,
361 integer_128: i128,
362 unsigned_0: u0,
363 unsigned_8: u8,
364 unsigned_16: u16,
365 unsigned_32: u32,
366 unsigned_64: u64,
367 unsigned_128: u128,
368
369 float_32: f32,
370 float_64: f64,
371 };
372
373 integral_types: IntegralTypes,
374
375 const Pointers = struct {
376 optional: ?*u8,
377 c_pointer: [*c]u8,
378 slice: []u8,
379 };
380 pointers: Pointers,
381
382 array: [2]u32,
383 optional_int: ?u8,
384 empty: void,
385 };
386
387 const b = zeroes(ZigStruct);
388 testing.expectEqual(@as(i8, 0), b.integral_types.integer_0);
389 testing.expectEqual(@as(i8, 0), b.integral_types.integer_8);
390 testing.expectEqual(@as(i16, 0), b.integral_types.integer_16);
391 testing.expectEqual(@as(i32, 0), b.integral_types.integer_32);
392 testing.expectEqual(@as(i64, 0), b.integral_types.integer_64);
393 testing.expectEqual(@as(i128, 0), b.integral_types.integer_128);
394 testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_0);
395 testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_8);
396 testing.expectEqual(@as(u16, 0), b.integral_types.unsigned_16);
397 testing.expectEqual(@as(u32, 0), b.integral_types.unsigned_32);
398 testing.expectEqual(@as(u64, 0), b.integral_types.unsigned_64);
399 testing.expectEqual(@as(u128, 0), b.integral_types.unsigned_128);
400 testing.expectEqual(@as(f32, 0), b.integral_types.float_32);
401 testing.expectEqual(@as(f64, 0), b.integral_types.float_64);
402 testing.expectEqual(@as(?*u8, null), b.pointers.optional);
403 testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer);
404 testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice);
405 for (b.array) |e| {
406 testing.expectEqual(@as(u32, 0), e);
407 }
408 testing.expectEqual(@as(?u8, null), b.optional_int);
304}409}
305410
306pub fn secureZero(comptime T: type, s: []T) void {411pub fn secureZero(comptime T: type, s: []T) void {