master
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const assert = std.debug.assert;
5const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;
7
8test "@max" {
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12
13 const S = struct {
14 fn doTheTest() !void {
15 var x: i32 = 10;
16 var y: f32 = 0.68;
17 var nan: f32 = std.math.nan(f32);
18 _ = .{ &x, &y, &nan };
19 try expect(@as(i32, 10) == @max(@as(i32, -3), x));
20 try expect(@as(f32, 3.2) == @max(@as(f32, 3.2), y));
21 try expect(y == @max(nan, y));
22 try expect(y == @max(y, nan));
23 }
24 };
25 try S.doTheTest();
26 try comptime S.doTheTest();
27}
28
29test "@max on vectors" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
36
37 const S = struct {
38 fn doTheTest() !void {
39 var a: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
40 var b: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
41 const x = @max(a, b);
42 _ = .{ &a, &b };
43 try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 2147483647, 2147483647, 30, 40 }));
44
45 var c: @Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 };
46 var d: @Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 };
47 const y = @max(c, d);
48 _ = .{ &c, &d };
49 try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ 0, 0.42, -0.64, 7.8 }));
50
51 var e: @Vector(2, f32) = [2]f32{ 0, std.math.nan(f32) };
52 var f: @Vector(2, f32) = [2]f32{ std.math.nan(f32), 0 };
53 const z = @max(e, f);
54 _ = .{ &e, &f };
55 try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 }));
56 }
57 };
58 try S.doTheTest();
59 try comptime S.doTheTest();
60}
61
62test "@min" {
63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
66
67 const S = struct {
68 fn doTheTest() !void {
69 var x: i32 = 10;
70 var y: f32 = 0.68;
71 var nan: f32 = std.math.nan(f32);
72 _ = .{ &x, &y, &nan };
73 try expect(@as(i32, -3) == @min(@as(i32, -3), x));
74 try expect(@as(f32, 0.68) == @min(@as(f32, 3.2), y));
75 try expect(y == @min(nan, y));
76 try expect(y == @min(y, nan));
77 }
78 };
79 try S.doTheTest();
80 try comptime S.doTheTest();
81}
82
83test "@min for vectors" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
90
91 const S = struct {
92 fn doTheTest() !void {
93 var a: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
94 var b: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
95 _ = .{ &a, &b };
96 const x = @min(a, b);
97 try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 1, -2, 3, 4 }));
98
99 var c: @Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 };
100 var d: @Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 };
101 _ = .{ &c, &d };
102 const y = @min(c, d);
103 try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ -0.23, 0.4, -2.4, 0.9 }));
104
105 var e: @Vector(2, f32) = [2]f32{ 0, std.math.nan(f32) };
106 var f: @Vector(2, f32) = [2]f32{ std.math.nan(f32), 0 };
107 _ = .{ &e, &f };
108 const z = @max(e, f);
109 try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 }));
110 }
111 };
112 try S.doTheTest();
113 try comptime S.doTheTest();
114}
115
116test "@min/max for floats" {
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_spirv) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
121 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
122
123 const S = struct {
124 fn doTheTest(comptime T: type) !void {
125 var x: T = -3.14;
126 var y: T = 5.27;
127 _ = .{ &x, &y };
128 try expectEqual(x, @min(x, y));
129 try expectEqual(x, @min(y, x));
130 try expectEqual(y, @max(x, y));
131 try expectEqual(y, @max(y, x));
132
133 if (T != comptime_float) {
134 var nan: T = std.math.nan(T);
135 _ = &nan;
136 try expectEqual(y, @max(nan, y));
137 try expectEqual(y, @max(y, nan));
138 }
139 }
140 };
141
142 inline for (.{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
143 if (T == c_longdouble and builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21090
144
145 try S.doTheTest(T);
146 try comptime S.doTheTest(T);
147 }
148 try comptime S.doTheTest(comptime_float);
149}
150
151test "@min/@max on lazy values" {
152 const A = extern struct { u8_4: [4]u8 };
153 const B = extern struct { u8_16: [16]u8 };
154 const size = @max(@sizeOf(A), @sizeOf(B));
155 try expect(size == @sizeOf(B));
156}
157
158test "@min/@max more than two arguments" {
159 const x: u32 = 30;
160 const y: u32 = 10;
161 const z: u32 = 20;
162 try expectEqual(@as(u32, 10), @min(x, y, z));
163 try expectEqual(@as(u32, 30), @max(x, y, z));
164}
165
166test "@min/@max more than two vector arguments" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
172
173 const x: @Vector(2, u32) = .{ 3, 2 };
174 const y: @Vector(2, u32) = .{ 4, 1 };
175 const z: @Vector(2, u32) = .{ 5, 0 };
176 try expectEqual(@Vector(2, u32){ 3, 0 }, @min(x, y, z));
177 try expectEqual(@Vector(2, u32){ 5, 2 }, @max(x, y, z));
178}
179
180test "@min/@max notices bounds" {
181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
183
184 var x: u16 = 20;
185 const y = 30;
186 var z: u32 = 100;
187 _ = .{ &x, &z };
188 const min = @min(x, y, z);
189 const max = @max(x, y, z);
190 try expectEqual(x, min);
191 try expectEqual(u5, @TypeOf(min));
192 try expectEqual(z, max);
193 try expectEqual(u32, @TypeOf(max));
194}
195
196test "@min/@max notices vector bounds" {
197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
198 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
202
203 var x: @Vector(2, u16) = .{ 140, 40 };
204 const y: @Vector(2, u64) = .{ 5, 100 };
205 var z: @Vector(2, u32) = .{ 10, 300 };
206 _ = .{ &x, &z };
207 const min = @min(x, y, z);
208 const max = @max(x, y, z);
209 try expectEqual(@Vector(2, u32){ 5, 40 }, min);
210 try expectEqual(@Vector(2, u7), @TypeOf(min));
211 try expectEqual(@Vector(2, u32){ 140, 300 }, max);
212 try expectEqual(@Vector(2, u32), @TypeOf(max));
213}
214
215test "@min/@max on comptime_int" {
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
218
219 const min = @min(1, 2, -2, -1);
220 const max = @max(1, 2, -2, -1);
221
222 try expectEqual(comptime_int, @TypeOf(min));
223 try expectEqual(comptime_int, @TypeOf(max));
224 try expectEqual(-2, min);
225 try expectEqual(2, max);
226}
227
228test "@min/@max notices bounds from types" {
229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
231
232 var x: u16 = 123;
233 var y: u32 = 456;
234 var z: u8 = 10;
235 _ = .{ &x, &y, &z };
236
237 const min = @min(x, y, z);
238 const max = @max(x, y, z);
239
240 comptime assert(@TypeOf(min) == u8);
241 comptime assert(@TypeOf(max) == u32);
242
243 try expectEqual(z, min);
244 try expectEqual(y, max);
245}
246
247test "@min/@max notices bounds from vector types" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
249 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
253
254 var x: @Vector(2, u16) = .{ 30, 67 };
255 var y: @Vector(2, u32) = .{ 20, 500 };
256 var z: @Vector(2, u8) = .{ 60, 15 };
257 _ = .{ &x, &y, &z };
258
259 const min = @min(x, y, z);
260 const max = @max(x, y, z);
261
262 comptime assert(@TypeOf(min) == @Vector(2, u8));
263 comptime assert(@TypeOf(max) == @Vector(2, u32));
264
265 try expectEqual(@Vector(2, u8){ 20, 15 }, min);
266 try expectEqual(@Vector(2, u32){ 60, 500 }, max);
267}
268
269test "@min/@max notices bounds from types when comptime-known value is undef" {
270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
273
274 var x: u32 = 1_000_000;
275 _ = &x;
276 const y: u16 = undefined;
277 // y is comptime-known, but is undef, so bounds cannot be refined using its value
278
279 const min = @min(x, y);
280 const max = @max(x, y);
281
282 comptime assert(@TypeOf(min) == u16);
283 comptime assert(@TypeOf(max) == u32);
284
285 // Cannot assert values as one was undefined
286}
287
288test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {
289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
290 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
293 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
294
295 var x: @Vector(2, u32) = .{ 1_000_000, 12345 };
296 _ = &x;
297 const y: @Vector(2, u16) = .{ 10, undefined };
298 // y is comptime-known, but an element is undef, so bounds cannot be refined using its value
299
300 const min = @min(x, y);
301 const max = @max(x, y);
302
303 comptime assert(@TypeOf(min) == @Vector(2, u16));
304 comptime assert(@TypeOf(max) == @Vector(2, u32));
305
306 try expectEqual(@as(u16, 10), min[0]);
307 try expectEqual(@as(u32, 1_000_000), max[0]);
308 // Cannot assert values at index 1 as one was undefined
309}
310
311test "@min/@max of signed and unsigned runtime integers" {
312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
313
314 var x: i32 = -1;
315 var y: u31 = 1;
316 _ = .{ &x, &y };
317
318 const min = @min(x, y);
319 const max = @max(x, y);
320
321 comptime assert(@TypeOf(min) == i32);
322 comptime assert(@TypeOf(max) == u31);
323
324 try expectEqual(x, @min(x, y));
325 try expectEqual(y, @max(x, y));
326}
327
328test "@min resulting in u0" {
329 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
331
332 const S = struct {
333 fn min(a: u0, b: u8) u8 {
334 return @min(a, b);
335 }
336 };
337 const x = S.min(0, 1);
338 try expect(x == 0);
339}
340
341test "@min/@max with runtime signed and unsigned integers of same size" {
342 const S = struct {
343 fn min(a: i32, b: u32) i32 {
344 return @min(a, b);
345 }
346 fn max(a: i32, b: u32) u32 {
347 return @max(a, b);
348 }
349 };
350
351 const min = S.min(std.math.minInt(i32), std.math.maxInt(u32));
352 try expect(min == std.math.minInt(i32));
353
354 const max = S.max(std.math.minInt(i32), std.math.maxInt(u32));
355 try expect(max == std.math.maxInt(u32));
356}
357
358test "@min/@max with runtime vectors of signed and unsigned integers of same size" {
359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
364
365 const S = struct {
366 fn min(a: @Vector(2, i32), b: @Vector(2, u32)) @Vector(2, i32) {
367 return @min(a, b);
368 }
369 fn max(a: @Vector(2, i32), b: @Vector(2, u32)) @Vector(2, u32) {
370 return @max(a, b);
371 }
372 };
373
374 const a: @Vector(2, i32) = .{ std.math.minInt(i32), std.math.maxInt(i32) };
375 const b: @Vector(2, u32) = .{ std.math.maxInt(u32), std.math.minInt(u32) };
376
377 try expectEqual(@Vector(2, i32){ std.math.minInt(i32), std.math.minInt(u32) }, S.min(a, b));
378 try expectEqual(@Vector(2, u32){ std.math.maxInt(u32), std.math.maxInt(i32) }, S.max(a, b));
379}