From 815c8536f4e9e50e3ae58b191bd6d4bcd09f8796 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Thu, 12 Feb 2026 02:24:59 -0800 Subject: [PATCH] add parseDigits --- src/lib.zig | 1 + src/parseDigits.zig | 39 +++++++++++++++++++++++++++++++++++++++ src/parse_int.zig | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/parseDigits.zig diff --git a/src/lib.zig b/src/lib.zig index b1e19c6f381c3441384bbd28a0b54c6aa8850466..e4947bf716741ad2e75a25da45974ecd85ac6252 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -118,3 +118,4 @@ pub usingnamespace @import("./compareFnBasic.zig"); pub usingnamespace @import("./compareFnField.zig"); pub usingnamespace @import("./compareFnRange.zig"); pub usingnamespace @import("./asciiLower.zig"); +pub usingnamespace @import("./parseDigits.zig"); diff --git a/src/parseDigits.zig b/src/parseDigits.zig new file mode 100644 index 0000000000000000000000000000000000000000..fe6d8613d7c45d7602d180a5a8889e747ca6b79e --- /dev/null +++ b/src/parseDigits.zig @@ -0,0 +1,39 @@ +const std = @import("std"); +const string = []const u8; +const extras = @import("./lib.zig"); + +/// Simple number parser with no extra detection or handling. Alphabet is [0-9][a-z] with respect to base. +/// Partially motivated by https://codeberg.org/ziglang/zig/issues/30881 + https://github.com/ziglang/zig/issues/24687 +pub fn parseDigits(comptime T: type, buf: []const u8, base: u8) !T { + std.debug.assert(base > 0); + std.debug.assert(base <= 36); + if (buf.len == 0) return error.InvalidCharacter; + + var result: T = 0; + for (0..buf.len) |i| { + const c = buf[buf.len - 1 - i]; + const d = switch (c) { + '0'...'9' => |a| a - '0', + 'a'...'z' => |a| a - 'a' + 10, + 'A'...'Z' => |a| a - 'A' + 10, + else => return error.InvalidCharacter, + }; + if (d == 0) continue; + if (d >= base) return error.Overflow; + const _x = if (i == 0) 1 else std.math.powi(T, @intCast(base), @intCast(i)) catch return error.Overflow; + const _y = try std.math.mul(T, @intCast(d), _x); + const _z = try std.math.add(T, result, _y); + result = _z; + } + return result; +} + +test { + try std.testing.expect(try parseDigits(u8, "10", 10) == 10); +} +test { + try std.testing.expect(try parseDigits(u8, "20", 16) == 32); +} +test { + try std.testing.expect(try parseDigits(u8, "EF", 16) == 239); +} diff --git a/src/parse_int.zig b/src/parse_int.zig index a601095adf97c1f012f55d799c1de58ecc3f7dbe..c848f75ac3b38567657349db20cd952bc2fab130 100644 --- a/src/parse_int.zig +++ b/src/parse_int.zig @@ -4,7 +4,7 @@ const extras = @import("./lib.zig"); pub fn parse_int(comptime T: type, s: ?string, b: u8, d: T) T { if (s == null) return d; - return std.fmt.parseInt(T, s.?, b) catch d; + return extras.parseDigits(T, s.?, b) catch d; } test { -- 2.54.0