Commit 5ae838d105

Andrew Kelley <andrew@ziglang.org>
2024-03-12 23:46:14
std: remove one layer of redundant parse_float namespace
there are still more, though. This provides a doctest for the `parseFloat` function.
1 parent c5bd19e
Changed files (2)
lib
std
lib/std/fmt/parse_float/parse_float.zig
@@ -1,66 +0,0 @@
-const std = @import("std");
-const parse = @import("parse.zig");
-const convertFast = @import("convert_fast.zig").convertFast;
-const convertEiselLemire = @import("convert_eisel_lemire.zig").convertEiselLemire;
-const convertSlow = @import("convert_slow.zig").convertSlow;
-const convertHex = @import("convert_hex.zig").convertHex;
-
-pub const ParseFloatError = error{
-    InvalidCharacter,
-};
-
-pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
-    if (@typeInfo(T) != .Float) {
-        @compileError("Cannot parse a float into a non-floating point type.");
-    }
-
-    if (T == f80) {
-        @compileError("TODO support parsing float to f80");
-    }
-
-    if (s.len == 0) {
-        return error.InvalidCharacter;
-    }
-
-    var i: usize = 0;
-    const negative = s[i] == '-';
-    if (s[i] == '-' or s[i] == '+') {
-        i += 1;
-    }
-    if (s.len == i) {
-        return error.InvalidCharacter;
-    }
-
-    const n = parse.parseNumber(T, s[i..], negative) orelse {
-        return parse.parseInfOrNan(T, s[i..], negative) orelse error.InvalidCharacter;
-    };
-
-    if (n.hex) {
-        return convertHex(T, n);
-    }
-
-    if (convertFast(T, n)) |f| {
-        return f;
-    }
-
-    if (T == f16 or T == f32 or T == f64) {
-        // If significant digits were truncated, then we can have rounding error
-        // only if `mantissa + 1` produces a different result. We also avoid
-        // redundantly using the Eisel-Lemire algorithm if it was unable to
-        // correctly round on the first pass.
-        if (convertEiselLemire(T, n.exponent, n.mantissa)) |bf| {
-            if (!n.many_digits) {
-                return bf.toFloat(T, n.negative);
-            }
-            if (convertEiselLemire(T, n.exponent, n.mantissa + 1)) |bf2| {
-                if (bf.eql(bf2)) {
-                    return bf.toFloat(T, n.negative);
-                }
-            }
-        }
-    }
-
-    // Unable to correctly round the float using the Eisel-Lemire algorithm.
-    // Fallback to a slower, but always correct algorithm.
-    return convertSlow(T, s[i..]).toFloat(T, negative);
-}
lib/std/fmt/parse_float.zig
@@ -1,7 +1,4 @@
-pub const parseFloat = @import("parse_float/parse_float.zig").parseFloat;
-pub const ParseFloatError = @import("parse_float/parse_float.zig").ParseFloatError;
-
-const std = @import("std");
+const std = @import("../std.zig");
 const math = std.math;
 const testing = std.testing;
 const expect = testing.expect;
@@ -9,10 +6,75 @@ const expectEqual = testing.expectEqual;
 const expectError = testing.expectError;
 const approxEqAbs = std.math.approxEqAbs;
 const epsilon = 1e-7;
+const parse = @import("parse_float/parse.zig");
+const convertHex = @import("parse_float/convert_hex.zig").convertHex;
+const convertFast = @import("parse_float/convert_fast.zig").convertFast;
+const convertEiselLemire = @import("parse_float/convert_eisel_lemire.zig").convertEiselLemire;
+const convertSlow = @import("parse_float/convert_slow.zig").convertSlow;
+
+pub const ParseFloatError = error{
+    InvalidCharacter,
+};
+
+pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
+    if (@typeInfo(T) != .Float) {
+        @compileError("Cannot parse a float into a non-floating point type.");
+    }
+
+    if (T == f80) {
+        @compileError("TODO support parsing float to f80");
+    }
+
+    if (s.len == 0) {
+        return error.InvalidCharacter;
+    }
+
+    var i: usize = 0;
+    const negative = s[i] == '-';
+    if (s[i] == '-' or s[i] == '+') {
+        i += 1;
+    }
+    if (s.len == i) {
+        return error.InvalidCharacter;
+    }
+
+    const n = parse.parseNumber(T, s[i..], negative) orelse {
+        return parse.parseInfOrNan(T, s[i..], negative) orelse error.InvalidCharacter;
+    };
+
+    if (n.hex) {
+        return convertHex(T, n);
+    }
+
+    if (convertFast(T, n)) |f| {
+        return f;
+    }
+
+    if (T == f16 or T == f32 or T == f64) {
+        // If significant digits were truncated, then we can have rounding error
+        // only if `mantissa + 1` produces a different result. We also avoid
+        // redundantly using the Eisel-Lemire algorithm if it was unable to
+        // correctly round on the first pass.
+        if (convertEiselLemire(T, n.exponent, n.mantissa)) |bf| {
+            if (!n.many_digits) {
+                return bf.toFloat(T, n.negative);
+            }
+            if (convertEiselLemire(T, n.exponent, n.mantissa + 1)) |bf2| {
+                if (bf.eql(bf2)) {
+                    return bf.toFloat(T, n.negative);
+                }
+            }
+        }
+    }
+
+    // Unable to correctly round the float using the Eisel-Lemire algorithm.
+    // Fallback to a slower, but always correct algorithm.
+    return convertSlow(T, s[i..]).toFloat(T, negative);
+}
 
 // See https://github.com/tiehuis/parse-number-fxx-test-data for a wider-selection of test-data.
 
-test "parseFloat" {
+test parseFloat {
     inline for ([_]type{ f16, f32, f64, f128 }) |T| {
         try testing.expectError(error.InvalidCharacter, parseFloat(T, ""));
         try testing.expectError(error.InvalidCharacter, parseFloat(T, "   1"));