| ... | @@ -242,12 +242,69 @@ pub fn floatExponentBits(comptime T: type) comptime_int { | ... | @@ -242,12 +242,69 @@ pub fn floatExponentBits(comptime T: type) comptime_int { |
| 242 | }; | 242 | }; |
| 243 | } | 243 | } |
| 244 | | 244 | |
| 245 | pub fn min(x: var, y: var) @typeOf(x + y) { | 245 | /// Given two types, returns the smallest one which is capable of holding the |
| 246 | return if (x < y) x else y; | 246 | /// full range of the minimum value. |
| | 247 | pub fn Min(comptime A: type, comptime B: type) type { |
| | 248 | return switch (@typeInfo(A)) { |
| | 249 | .Int => |a_info| switch (@typeInfo(B)) { |
| | 250 | .Int => |b_info| blk: { |
| | 251 | if (a_info.is_signed == b_info.is_signed) { |
| | 252 | break :blk if (a_info.bits < b_info.bits) A else B; |
| | 253 | } else if (a_info.is_signed) { |
| | 254 | break :blk A; |
| | 255 | } else { |
| | 256 | break :blk B; |
| | 257 | } |
| | 258 | }, |
| | 259 | .ComptimeInt => A, |
| | 260 | else => @compileError("unsupported type: " ++ @typeName(B)), |
| | 261 | }, |
| | 262 | .Float => |a_info| if (a_info.bits < @typeInfo(B).Float.bits) A else B, |
| | 263 | .ComptimeInt => B, |
| | 264 | .ComptimeFloat => B, |
| | 265 | else => @compileError("unsupported type: " ++ @typeName(A)), |
| | 266 | }; |
| | 267 | } |
| | 268 | |
| | 269 | /// Returns the smaller number. When one of the parameter's type's full range fits in the other, |
| | 270 | /// the return type is the smaller type. |
| | 271 | pub fn min(x: var, y: var) Min(@typeOf(x), @typeOf(y)) { |
| | 272 | const Result = Min(@typeOf(x), @typeOf(y)); |
| | 273 | if (x < y) { |
| | 274 | // TODO Zig should allow this as an implicit cast because x is immutable and in this |
| | 275 | // scope it is known to fit in the return type. |
| | 276 | switch (@typeInfo(Result)) { |
| | 277 | .Int => return @intCast(Result, x), |
| | 278 | .Float => return @floatCast(Result, x), |
| | 279 | else => return x, |
| | 280 | } |
| | 281 | } else { |
| | 282 | // TODO Zig should allow this as an implicit cast because y is immutable and in this |
| | 283 | // scope it is known to fit in the return type. |
| | 284 | switch (@typeInfo(Result)) { |
| | 285 | .Int => return @intCast(Result, y), |
| | 286 | .Float => return @floatCast(Result, y), |
| | 287 | else => return y, |
| | 288 | } |
| | 289 | } |
| 247 | } | 290 | } |
| 248 | | 291 | |
| 249 | test "math.min" { | 292 | test "math.min" { |
| 250 | testing.expect(min(i32(-1), i32(2)) == -1); | 293 | testing.expect(min(i32(-1), i32(2)) == -1); |
| | 294 | { |
| | 295 | var a: u16 = 999; |
| | 296 | var b: u32 = 10; |
| | 297 | var result = min(a, b); |
| | 298 | testing.expect(@typeOf(result) == u16); |
| | 299 | testing.expect(result == 10); |
| | 300 | } |
| | 301 | { |
| | 302 | var a: f64 = 10.34; |
| | 303 | var b: f32 = 999.12; |
| | 304 | var result = min(a, b); |
| | 305 | testing.expect(@typeOf(result) == f32); |
| | 306 | testing.expect(result == 10.34); |
| | 307 | } |
| 251 | } | 308 | } |
| 252 | | 309 | |
| 253 | pub fn max(x: var, y: var) @typeOf(x + y) { | 310 | pub fn max(x: var, y: var) @typeOf(x + y) { |