mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Rewrite std.fmt.parseInt
This commit is contained in:
parent
682fccaaf0
commit
a0a93f2091
@ -996,49 +996,77 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, option
|
||||
return fbs.pos;
|
||||
}
|
||||
|
||||
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
|
||||
if (!T.is_signed) return parseUnsigned(T, buf, radix);
|
||||
if (buf.len == 0) return @as(T, 0);
|
||||
if (buf[0] == '-') {
|
||||
return math.negate(try parseUnsigned(T, buf[1..], radix));
|
||||
} else if (buf[0] == '+') {
|
||||
return parseUnsigned(T, buf[1..], radix);
|
||||
} else {
|
||||
return parseUnsigned(T, buf, radix);
|
||||
}
|
||||
}
|
||||
|
||||
test "parseInt" {
|
||||
std.testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
|
||||
std.testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
|
||||
std.testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
std.testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
std.testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
std.testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
|
||||
std.testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
|
||||
}
|
||||
|
||||
pub const ParseUnsignedError = error{
|
||||
pub const ParseIntError = error{
|
||||
/// The result cannot fit in the type specified
|
||||
Overflow,
|
||||
|
||||
/// The input had a byte that was not a digit
|
||||
/// The input was empty or had a byte that was not a digit
|
||||
InvalidCharacter,
|
||||
};
|
||||
|
||||
pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
|
||||
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {
|
||||
if (buf.len == 0) return error.InvalidCharacter;
|
||||
if (buf[0] == '+') return parseWithSign(T, buf[1..], radix, .Pos);
|
||||
if (buf[0] == '-') return parseWithSign(T, buf[1..], radix, .Neg);
|
||||
return parseWithSign(T, buf, radix, .Pos);
|
||||
}
|
||||
|
||||
test "parseInt" {
|
||||
std.testing.expect((try parseInt(i32, "-10", 10)) == -10);
|
||||
std.testing.expect((try parseInt(i32, "+10", 10)) == 10);
|
||||
std.testing.expect((try parseInt(u32, "+10", 10)) == 10);
|
||||
std.testing.expectError(error.Overflow, parseInt(u32, "-10", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(u32, " 10", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(u32, "10 ", 10));
|
||||
std.testing.expect((try parseInt(u8, "255", 10)) == 255);
|
||||
std.testing.expectError(error.Overflow, parseInt(u8, "256", 10));
|
||||
|
||||
// +0 and -0 should work for unsigned
|
||||
std.testing.expect((try parseInt(u8, "-0", 10)) == 0);
|
||||
std.testing.expect((try parseInt(u8, "+0", 10)) == 0);
|
||||
|
||||
// ensure minInt is parsed correctly
|
||||
std.testing.expect((try parseInt(i8, "-128", 10)) == math.minInt(i8));
|
||||
std.testing.expect((try parseInt(i43, "-4398046511104", 10)) == math.minInt(i43));
|
||||
|
||||
// empty string or bare +- is invalid
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(u32, "", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(i32, "", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(u32, "+", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(i32, "+", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(u32, "-", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseInt(i32, "-", 10));
|
||||
}
|
||||
|
||||
fn parseWithSign(
|
||||
comptime T: type,
|
||||
buf: []const u8,
|
||||
radix: u8,
|
||||
comptime sign: enum { Pos, Neg },
|
||||
) ParseIntError!T {
|
||||
if (buf.len == 0) return error.InvalidCharacter;
|
||||
|
||||
const add = switch (sign) {
|
||||
.Pos => math.add,
|
||||
.Neg => math.sub,
|
||||
};
|
||||
|
||||
var x: T = 0;
|
||||
|
||||
for (buf) |c| {
|
||||
const digit = try charToDigit(c, radix);
|
||||
|
||||
if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
|
||||
x = try math.add(T, x, try math.cast(T, digit));
|
||||
x = try add(T, x, try math.cast(T, digit));
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {
|
||||
return parseWithSign(T, buf, radix, .Pos);
|
||||
}
|
||||
|
||||
test "parseUnsigned" {
|
||||
std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
|
||||
std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
|
||||
@ -1064,6 +1092,13 @@ test "parseUnsigned" {
|
||||
std.testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
|
||||
std.testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
|
||||
std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
|
||||
|
||||
// parseUnsigned does not expect a sign
|
||||
std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "+0", 10));
|
||||
std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "-0", 10));
|
||||
|
||||
// test empty string error
|
||||
std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "", 10));
|
||||
}
|
||||
|
||||
pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user