Commit 0f32de77c9

Adam Goertz <adambgoertz@gmail.com>
2020-10-28 03:55:12
impl lossyCast #5080
1 parent e1d8073
Changed files (1)
lib
lib/std/math.zig
@@ -1070,16 +1070,44 @@ test "std.math.log2_int_ceil" {
     testing.expect(log2_int_ceil(u32, 10) == 4);
 }
 
+///Cast a value to a different type. If the value doesn't fit in, or can't be perfectly represented by,
+///the new type, it will be converted to the closest possible representation.
 pub fn lossyCast(comptime T: type, value: anytype) T {
-    switch (@typeInfo(@TypeOf(value))) {
-        .Int => return @intToFloat(T, value),
-        .Float => return @floatCast(T, value),
-        .ComptimeInt => return @as(T, value),
-        .ComptimeFloat => return @as(T, value),
-        else => @compileError("bad type"),
+    switch(@typeInfo(T)) {
+        .Float => {
+            switch (@typeInfo(@TypeOf(value))) {
+                .Int => return @intToFloat(T, value),
+                .Float => return @floatCast(T, value),
+                .ComptimeInt => return @as(T, value),
+                .ComptimeFloat => return @as(T, value),
+                else => @compileError("bad type"),
+            }
+        },
+        .Int => {
+            switch(@typeInfo(@TypeOf(value))) {
+                .Int, .ComptimeInt => {
+                    if (value > maxInt(T)) { return @as(T, maxInt(T)); }
+                    else if (value < minInt(T)) { return @as(T, minInt(T)); }
+                    else { return @intCast(T, value); }
+                },
+                .Float, .ComptimeFloat => {
+                    if (value > maxInt(T)) { return @as(T, maxInt(T)); }
+                    else if (value < minInt(T)) { return @as(T, minInt(T)); }
+                    else { return @floatToInt(T, value); }
+                },
+                else => @compileError("bad type"),
+            }
+        },
+        else => @compileError("bad result type"),
     }
 }
 
+test "math.lossyCast" {
+    testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
+    testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
+    testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));
+}
+
 test "math.f64_min" {
     const f64_min_u64 = 0x0010000000000000;
     const fmin: f64 = f64_min;