| author | |
| committer | |
| log | e4b325c1952f25d447bf106966ae598482f93c17 |
| tree | 4362f28061a325f8f8485ff2cfa7b14b7def9017 |
| parent | 358c43939c1f5236eec9e022e7d45f1741234948 |
| parent | 072744f1ac8f4f58a80dc6ca0e15bd4ecbb4abfb |
5 files changed, 157 insertions(+), 149 deletions(-)
doc/langref.html.in+4-9| ... | ... | @@ -5474,19 +5474,14 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 5474 | 5474 | {#header_close#} |
| 5475 | 5475 | |
| 5476 | 5476 | {#header_open|@splat#} |
| 5477 | <pre>{#syntax#}@splat(scalar: anytype) anytype{#endsyntax#}</pre> | |
| 5477 | <pre>{#syntax#}@splat(element: anytype) anytype{#endsyntax#}</pre> | |
| 5478 | 5478 | <p> |
| 5479 | 5479 | Produces an array or vector where each element is the value |
| 5480 | {#syntax#}scalar{#endsyntax#}. The return type and thus the length of the | |
| 5481 | vector is inferred. | |
| 5480 | {#syntax#}element{#endsyntax#}. The return type, including the number of | |
| 5481 | elements, is inferred. | |
| 5482 | 5482 | </p> |
| 5483 | 5483 | {#code|test_splat_builtin.zig#} |
| 5484 | ||
| 5485 | <p> | |
| 5486 | {#syntax#}scalar{#endsyntax#} must be an {#link|integer|Integers#}, {#link|bool|Primitive Types#}, | |
| 5487 | {#link|float|Floats#}, or {#link|pointer|Pointers#}. | |
| 5488 | </p> | |
| 5489 | {#see_also|Vectors|@shuffle#} | |
| 5484 | {#see_also|Vectors|Arrays|@shuffle#} | |
| 5490 | 5485 | {#header_close#} |
| 5491 | 5486 | |
| 5492 | 5487 | {#header_open|@reduce#} |
test/behavior.zig+1| ... | ... | @@ -78,6 +78,7 @@ test { |
| 78 | 78 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 79 | 79 | _ = @import("behavior/slice.zig"); |
| 80 | 80 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 81 | _ = @import("behavior/splat.zig"); | |
| 81 | 82 | _ = @import("behavior/src.zig"); |
| 82 | 83 | _ = @import("behavior/string_literals.zig"); |
| 83 | 84 | _ = @import("behavior/struct.zig"); |
test/behavior/array.zig-101| ... | ... | @@ -326,26 +326,6 @@ test "set global var array via slice embedded in struct" { |
| 326 | 326 | try expect(s_array[2].b == 3); |
| 327 | 327 | } |
| 328 | 328 | |
| 329 | test "read/write through global variable array of struct fields initialized via splat" { | |
| 330 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 331 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 332 | ||
| 333 | const S = struct { | |
| 334 | fn doTheTest() !void { | |
| 335 | try expect(storage[0].term == 1); | |
| 336 | storage[0] = MyStruct{ .term = 123 }; | |
| 337 | try expect(storage[0].term == 123); | |
| 338 | } | |
| 339 | ||
| 340 | pub const MyStruct = struct { | |
| 341 | term: usize, | |
| 342 | }; | |
| 343 | ||
| 344 | var storage: [1]MyStruct = @splat(.{ .term = 1 }); | |
| 345 | }; | |
| 346 | try S.doTheTest(); | |
| 347 | } | |
| 348 | ||
| 349 | 329 | test "implicit cast single-item pointer" { |
| 350 | 330 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 351 | 331 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -988,74 +968,6 @@ test "runtime index of array of zero-bit values" { |
| 988 | 968 | try std.testing.expect(result.value == {}); |
| 989 | 969 | } |
| 990 | 970 | |
| 991 | test "@splat array" { | |
| 992 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 993 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 994 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 995 | ||
| 996 | const S = struct { | |
| 997 | fn doTheTest(comptime T: type, x: T) !void { | |
| 998 | const arr: [10]T = @splat(x); | |
| 999 | for (arr) |elem| { | |
| 1000 | try expectEqual(x, elem); | |
| 1001 | } | |
| 1002 | } | |
| 1003 | }; | |
| 1004 | ||
| 1005 | try S.doTheTest(u32, 123); | |
| 1006 | try comptime S.doTheTest(u32, 123); | |
| 1007 | ||
| 1008 | const Foo = struct { x: u8 }; | |
| 1009 | try S.doTheTest(Foo, .{ .x = 10 }); | |
| 1010 | try comptime S.doTheTest(Foo, .{ .x = 10 }); | |
| 1011 | } | |
| 1012 | ||
| 1013 | test "@splat array with sentinel" { | |
| 1014 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1015 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1016 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 1017 | ||
| 1018 | const S = struct { | |
| 1019 | fn doTheTest(comptime T: type, x: T, comptime s: T) !void { | |
| 1020 | const arr: [10:s]T = @splat(x); | |
| 1021 | for (arr) |elem| { | |
| 1022 | try expectEqual(x, elem); | |
| 1023 | } | |
| 1024 | const ptr: [*]const T = &arr; | |
| 1025 | try expectEqual(s, ptr[10]); // sentinel correct | |
| 1026 | } | |
| 1027 | }; | |
| 1028 | ||
| 1029 | try S.doTheTest(u32, 100, 42); | |
| 1030 | try comptime S.doTheTest(u32, 100, 42); | |
| 1031 | ||
| 1032 | try S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 1033 | try comptime S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 1034 | } | |
| 1035 | ||
| 1036 | test "@splat zero-length array" { | |
| 1037 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1038 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1039 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 1040 | ||
| 1041 | const S = struct { | |
| 1042 | fn doTheTest(comptime T: type, comptime s: T) !void { | |
| 1043 | var runtime_undef: T = undefined; | |
| 1044 | runtime_undef = undefined; | |
| 1045 | // The array should be comptime-known despite the `@splat` operand being runtime-known. | |
| 1046 | const arr: [0:s]T = @splat(runtime_undef); | |
| 1047 | const ptr: [*]const T = &arr; | |
| 1048 | comptime assert(ptr[0] == s); | |
| 1049 | } | |
| 1050 | }; | |
| 1051 | ||
| 1052 | try S.doTheTest(u32, 42); | |
| 1053 | try comptime S.doTheTest(u32, 42); | |
| 1054 | ||
| 1055 | try S.doTheTest(?*anyopaque, null); | |
| 1056 | try comptime S.doTheTest(?*anyopaque, null); | |
| 1057 | } | |
| 1058 | ||
| 1059 | 971 | test "initialize slice with reference to empty array initializer" { |
| 1060 | 972 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1061 | 973 | |
| ... | ... | @@ -1116,19 +1028,6 @@ test "sentinel of runtime-known array initialization is populated" { |
| 1116 | 1028 | try expect(elems[1] == 123); |
| 1117 | 1029 | } |
| 1118 | 1030 | |
| 1119 | test "splat with an error union or optional result type" { | |
| 1120 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1121 | ||
| 1122 | const S = struct { | |
| 1123 | fn doTest(T: type) !?T { | |
| 1124 | return @splat(1); | |
| 1125 | } | |
| 1126 | }; | |
| 1127 | ||
| 1128 | _ = try S.doTest(@Vector(4, u32)); | |
| 1129 | _ = try S.doTest([4]u32); | |
| 1130 | } | |
| 1131 | ||
| 1132 | 1031 | test "resist alias of explicit copy of array passed as arg" { |
| 1133 | 1032 | const S = struct { |
| 1134 | 1033 | const Thing = [1]u32; |
test/behavior/splat.zig created+152| ... | ... | @@ -0,0 +1,152 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const expect = std.testing.expect; | |
| 5 | const assert = std.debug.assert; | |
| 6 | ||
| 7 | test "@splat array" { | |
| 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 11 | ||
| 12 | const Foo = struct { x: u8 }; | |
| 13 | const S = struct { | |
| 14 | fn testInt(x: u32) !void { | |
| 15 | const arr: [10]u32 = @splat(x); | |
| 16 | for (arr) |elem| { | |
| 17 | try expect(x == elem); | |
| 18 | } | |
| 19 | } | |
| 20 | ||
| 21 | fn testStruct(x: Foo) !void { | |
| 22 | const arr: [10]Foo = @splat(x); | |
| 23 | for (arr) |elem| { | |
| 24 | try expect(x.x == elem.x); | |
| 25 | } | |
| 26 | } | |
| 27 | }; | |
| 28 | ||
| 29 | try S.testInt(123); | |
| 30 | try comptime S.testInt(123); | |
| 31 | ||
| 32 | try S.testStruct(.{ .x = 10 }); | |
| 33 | try comptime S.testStruct(.{ .x = 10 }); | |
| 34 | } | |
| 35 | ||
| 36 | test "@splat array with sentinel" { | |
| 37 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 38 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 39 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 40 | ||
| 41 | const S = struct { | |
| 42 | fn doTheTest(comptime T: type, x: T, comptime s: T) !void { | |
| 43 | const arr: [10:s]T = @splat(x); | |
| 44 | for (arr) |elem| { | |
| 45 | try expect(x == elem); | |
| 46 | } | |
| 47 | const ptr: [*]const T = &arr; | |
| 48 | try expect(s == ptr[10]); // sentinel correct | |
| 49 | } | |
| 50 | }; | |
| 51 | ||
| 52 | try S.doTheTest(u32, 100, 42); | |
| 53 | try comptime S.doTheTest(u32, 100, 42); | |
| 54 | ||
| 55 | try S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 56 | try comptime S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 57 | } | |
| 58 | ||
| 59 | test "@splat zero-length array" { | |
| 60 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 61 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 62 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 63 | ||
| 64 | const S = struct { | |
| 65 | fn doTheTest(comptime T: type, comptime s: T) !void { | |
| 66 | var runtime_undef: T = undefined; | |
| 67 | runtime_undef = undefined; | |
| 68 | // The array should be comptime-known despite the `@splat` operand being runtime-known. | |
| 69 | const arr: [0:s]T = @splat(runtime_undef); | |
| 70 | const ptr: [*]const T = &arr; | |
| 71 | comptime assert(ptr[0] == s); | |
| 72 | } | |
| 73 | }; | |
| 74 | ||
| 75 | try S.doTheTest(u32, 42); | |
| 76 | try comptime S.doTheTest(u32, 42); | |
| 77 | ||
| 78 | try S.doTheTest(?*anyopaque, null); | |
| 79 | try comptime S.doTheTest(?*anyopaque, null); | |
| 80 | } | |
| 81 | ||
| 82 | test "splat with an error union or optional result type" { | |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 84 | ||
| 85 | const S = struct { | |
| 86 | fn doTest(T: type) !?T { | |
| 87 | return @splat(1); | |
| 88 | } | |
| 89 | }; | |
| 90 | ||
| 91 | _ = try S.doTest(@Vector(4, u32)); | |
| 92 | _ = try S.doTest([4]u32); | |
| 93 | } | |
| 94 | ||
| 95 | test "read/write through global variable array of struct fields initialized via splat" { | |
| 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 98 | ||
| 99 | const S = struct { | |
| 100 | fn doTheTest() !void { | |
| 101 | try expect(storage[0].term == 1); | |
| 102 | storage[0] = MyStruct{ .term = 123 }; | |
| 103 | try expect(storage[0].term == 123); | |
| 104 | } | |
| 105 | ||
| 106 | pub const MyStruct = struct { | |
| 107 | term: usize, | |
| 108 | }; | |
| 109 | ||
| 110 | var storage: [1]MyStruct = @splat(.{ .term = 1 }); | |
| 111 | }; | |
| 112 | try S.doTheTest(); | |
| 113 | } | |
| 114 | ||
| 115 | test "vector @splat" { | |
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 118 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 119 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 120 | const S = struct { | |
| 121 | fn testForT(comptime N: comptime_int, v: anytype) !void { | |
| 122 | const T = @TypeOf(v); | |
| 123 | var vec: @Vector(N, T) = @splat(v); | |
| 124 | _ = &vec; | |
| 125 | const as_array = @as([N]T, vec); | |
| 126 | for (as_array) |elem| try expect(v == elem); | |
| 127 | } | |
| 128 | fn doTheTest() !void { | |
| 129 | // Splats with multiple-of-8 bit types that fill a 128bit vector. | |
| 130 | try testForT(16, @as(u8, 0xEE)); | |
| 131 | try testForT(8, @as(u16, 0xBEEF)); | |
| 132 | try testForT(4, @as(u32, 0xDEADBEEF)); | |
| 133 | try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF)); | |
| 134 | ||
| 135 | try testForT(8, @as(f16, 3.1415)); | |
| 136 | try testForT(4, @as(f32, 3.1415)); | |
| 137 | try testForT(2, @as(f64, 3.1415)); | |
| 138 | ||
| 139 | // Same but fill more than 128 bits. | |
| 140 | try testForT(16 * 2, @as(u8, 0xEE)); | |
| 141 | try testForT(8 * 2, @as(u16, 0xBEEF)); | |
| 142 | try testForT(4 * 2, @as(u32, 0xDEADBEEF)); | |
| 143 | try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF)); | |
| 144 | ||
| 145 | try testForT(8 * 2, @as(f16, 3.1415)); | |
| 146 | try testForT(4 * 2, @as(f32, 3.1415)); | |
| 147 | try testForT(2 * 2, @as(f64, 3.1415)); | |
| 148 | } | |
| 149 | }; | |
| 150 | try S.doTheTest(); | |
| 151 | try comptime S.doTheTest(); | |
| 152 | } |
test/behavior/vector.zig-39| ... | ... | @@ -374,45 +374,6 @@ test "vector casts of sizes not divisible by 8" { |
| 374 | 374 | try comptime S.doTheTest(); |
| 375 | 375 | } |
| 376 | 376 | |
| 377 | test "vector @splat" { | |
| 378 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 379 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 380 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 381 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 382 | const S = struct { | |
| 383 | fn testForT(comptime N: comptime_int, v: anytype) !void { | |
| 384 | const T = @TypeOf(v); | |
| 385 | var vec: @Vector(N, T) = @splat(v); | |
| 386 | _ = &vec; | |
| 387 | const as_array = @as([N]T, vec); | |
| 388 | for (as_array) |elem| try expect(v == elem); | |
| 389 | } | |
| 390 | fn doTheTest() !void { | |
| 391 | // Splats with multiple-of-8 bit types that fill a 128bit vector. | |
| 392 | try testForT(16, @as(u8, 0xEE)); | |
| 393 | try testForT(8, @as(u16, 0xBEEF)); | |
| 394 | try testForT(4, @as(u32, 0xDEADBEEF)); | |
| 395 | try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF)); | |
| 396 | ||
| 397 | try testForT(8, @as(f16, 3.1415)); | |
| 398 | try testForT(4, @as(f32, 3.1415)); | |
| 399 | try testForT(2, @as(f64, 3.1415)); | |
| 400 | ||
| 401 | // Same but fill more than 128 bits. | |
| 402 | try testForT(16 * 2, @as(u8, 0xEE)); | |
| 403 | try testForT(8 * 2, @as(u16, 0xBEEF)); | |
| 404 | try testForT(4 * 2, @as(u32, 0xDEADBEEF)); | |
| 405 | try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF)); | |
| 406 | ||
| 407 | try testForT(8 * 2, @as(f16, 3.1415)); | |
| 408 | try testForT(4 * 2, @as(f32, 3.1415)); | |
| 409 | try testForT(2 * 2, @as(f64, 3.1415)); | |
| 410 | } | |
| 411 | }; | |
| 412 | try S.doTheTest(); | |
| 413 | try comptime S.doTheTest(); | |
| 414 | } | |
| 415 | ||
| 416 | 377 | test "load vector elements via comptime index" { |
| 417 | 378 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 418 | 379 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |