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