| ... | ... | @@ -979,9 +979,59 @@ test "std.meta.cast" { |
| 979 | 979 | /// Given a value returns its size as C's sizeof operator would. |
| 980 | 980 | /// This is for translate-c and is not intended for general use. |
| 981 | 981 | pub fn sizeof(target: anytype) usize { |
| 982 | | switch (@typeInfo(@TypeOf(target))) { |
| 983 | | .Type => return @sizeOf(target), |
| 984 | | .Float, .Int, .Struct, .Union, .Enum => return @sizeOf(@TypeOf(target)), |
| 982 | const T: type = if (@TypeOf(target) == type) target else @TypeOf(target); |
| 983 | switch (@typeInfo(T)) { |
| 984 | .Float, .Int, .Struct, .Union, .Enum, .Array, .Bool, .Vector => return @sizeOf(T), |
| 985 | .Fn => { |
| 986 | // sizeof(main) returns 1, sizeof(&main) returns pointer size. |
| 987 | // We cannot distinguish those types in Zig, so use pointer size. |
| 988 | return @sizeOf(T); |
| 989 | }, |
| 990 | .Null => return @sizeOf(*c_void), |
| 991 | .Void => { |
| 992 | // Note: sizeof(void) is 1 on clang/gcc and 0 on MSVC. |
| 993 | return 1; |
| 994 | }, |
| 995 | .Opaque => { |
| 996 | if (T == c_void) { |
| 997 | // Note: sizeof(void) is 1 on clang/gcc and 0 on MSVC. |
| 998 | return 1; |
| 999 | } else { |
| 1000 | @compileError("Cannot use C sizeof on opaque type "++@typeName(T)); |
| 1001 | } |
| 1002 | }, |
| 1003 | .Optional => |opt| { |
| 1004 | if (@typeInfo(opt.child) == .Pointer) { |
| 1005 | return sizeof(opt.child); |
| 1006 | } else { |
| 1007 | @compileError("Cannot use C sizeof on non-pointer optional "++@typeName(T)); |
| 1008 | } |
| 1009 | }, |
| 1010 | .Pointer => |ptr| { |
| 1011 | if (ptr.size == .Slice) { |
| 1012 | @compileError("Cannot use C sizeof on slice type "++@typeName(T)); |
| 1013 | } |
| 1014 | // for strings, sizeof("a") returns 2. |
| 1015 | // normal pointer decay scenarios from C are handled |
| 1016 | // in the .Array case above, but strings remain literals |
| 1017 | // and are therefore always pointers, so they need to be |
| 1018 | // specially handled here. |
| 1019 | if (ptr.size == .One and ptr.is_const and @typeInfo(ptr.child) == .Array) { |
| 1020 | const array_info = @typeInfo(ptr.child).Array; |
| 1021 | if ((array_info.child == u8 or array_info.child == u16) and |
| 1022 | array_info.sentinel != null and |
| 1023 | array_info.sentinel.? == 0) { |
| 1024 | // length of the string plus one for the null terminator. |
| 1025 | return (array_info.len + 1) * @sizeOf(array_info.child); |
| 1026 | } |
| 1027 | } |
| 1028 | // When zero sized pointers are removed, this case will no |
| 1029 | // longer be reachable and can be deleted. |
| 1030 | if (@sizeOf(T) == 0) { |
| 1031 | return @sizeOf(*c_void); |
| 1032 | } |
| 1033 | return @sizeOf(T); |
| 1034 | }, |
| 985 | 1035 | .ComptimeFloat => return @sizeOf(f64), // TODO c_double #3999 |
| 986 | 1036 | .ComptimeInt => { |
| 987 | 1037 | // TODO to get the correct result we have to translate |
| ... | ... | @@ -991,7 +1041,7 @@ pub fn sizeof(target: anytype) usize { |
| 991 | 1041 | // TODO test if target fits in int, long or long long |
| 992 | 1042 | return @sizeOf(c_int); |
| 993 | 1043 | }, |
| 994 | | else => @compileError("TODO implement std.meta.sizeof for type " ++ @typeName(@TypeOf(target))), |
| 1044 | else => @compileError("std.meta.sizeof does not support type " ++ @typeName(T)), |
| 995 | 1045 | } |
| 996 | 1046 | } |
| 997 | 1047 | |
| ... | ... | @@ -999,12 +1049,45 @@ test "sizeof" { |
| 999 | 1049 | const E = extern enum(c_int) { One, _ }; |
| 1000 | 1050 | const S = extern struct { a: u32 }; |
| 1001 | 1051 | |
| 1052 | const ptr_size = @sizeOf(*c_void); |
| 1053 | |
| 1002 | 1054 | testing.expect(sizeof(u32) == 4); |
| 1003 | 1055 | testing.expect(sizeof(@as(u32, 2)) == 4); |
| 1004 | 1056 | testing.expect(sizeof(2) == @sizeOf(c_int)); |
| 1057 | |
| 1058 | testing.expect(sizeof(2.0) == @sizeOf(f64)); |
| 1059 | |
| 1005 | 1060 | testing.expect(sizeof(E) == @sizeOf(c_int)); |
| 1006 | 1061 | testing.expect(sizeof(E.One) == @sizeOf(c_int)); |
| 1062 | |
| 1007 | 1063 | testing.expect(sizeof(S) == 4); |
| 1064 | |
| 1065 | testing.expect(sizeof([_]u32{4, 5, 6}) == 12); |
| 1066 | testing.expect(sizeof([3]u32) == 12); |
| 1067 | testing.expect(sizeof([3:0]u32) == 16); |
| 1068 | testing.expect(sizeof(&[_]u32{4, 5, 6}) == ptr_size); |
| 1069 | |
| 1070 | testing.expect(sizeof(*u32) == ptr_size); |
| 1071 | testing.expect(sizeof([*]u32) == ptr_size); |
| 1072 | testing.expect(sizeof([*c]u32) == ptr_size); |
| 1073 | testing.expect(sizeof(?*u32) == ptr_size); |
| 1074 | testing.expect(sizeof(?[*]u32) == ptr_size); |
| 1075 | testing.expect(sizeof(*c_void) == ptr_size); |
| 1076 | testing.expect(sizeof(*void) == ptr_size); |
| 1077 | testing.expect(sizeof(null) == ptr_size); |
| 1078 | |
| 1079 | testing.expect(sizeof("foobar") == 7); |
| 1080 | testing.expect(sizeof(&[_:0]u16{'f','o','o','b','a','r'}) == 14); |
| 1081 | testing.expect(sizeof(*const [4:0]u8) == 5); |
| 1082 | testing.expect(sizeof(*[4:0]u8) == ptr_size); |
| 1083 | testing.expect(sizeof([*]const [4:0]u8) == ptr_size); |
| 1084 | testing.expect(sizeof(*const *const [4:0]u8) == ptr_size); |
| 1085 | testing.expect(sizeof(*const [4]u8) == ptr_size); |
| 1086 | |
| 1087 | testing.expect(sizeof(sizeof) == @sizeOf(@TypeOf(sizeof))); |
| 1088 | |
| 1089 | testing.expect(sizeof(void) == 1); |
| 1090 | testing.expect(sizeof(c_void) == 1); |
| 1008 | 1091 | } |
| 1009 | 1092 | |
| 1010 | 1093 | /// For a given function type, returns a tuple type which fields will |