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}