ona/source/coral/utf8.zig

109 lines
2.3 KiB
Zig
Raw Normal View History

2023-05-23 02:08:34 +02:00
const io = @import("./io.zig");
2023-04-19 01:25:35 +02:00
const math = @import("./math.zig");
2023-06-03 16:04:42 +02:00
pub const DecimalFormat = struct {
2023-07-10 02:10:56 +02:00
delimiter: []const io.Byte,
positive_prefix: enum {none, plus, space},
pub fn parse(self: DecimalFormat, utf8: []const io.Byte, comptime Decimal: type) ?Decimal {
if (utf8.len == 0) {
return null;
}
switch (@typeInfo(Decimal)) {
.Int => |int| {
var has_sign = switch (utf8[0]) {
'-', '+', ' ' => true,
else => false,
};
var result = @as(Decimal, 0);
for (@intFromBool(has_sign) .. utf8.len) |index| {
const radix = 10;
const code = utf8[index];
switch (code) {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
result = try math.checked_add(
try math.checked_mul(result, radix),
try math.checked_sub(code, '0'));
},
2023-06-03 16:04:42 +02:00
2023-07-10 02:10:56 +02:00
else => {
if (self.delimiter.len == 0 or !io.equals(self.delimiter, utf8[index ..])) {
return null;
}
},
}
}
2023-06-03 16:04:42 +02:00
2023-07-10 02:10:56 +02:00
switch (int.signedness) {
.signed => {
return result * @as(Decimal, if (has_sign and utf8[0] == '-') -1 else 1);
2023-06-03 16:04:42 +02:00
},
2023-07-10 02:10:56 +02:00
.unsigned => {
if (has_sign and utf8[0] == '-') {
return null;
2023-06-03 16:04:42 +02:00
}
2023-07-10 02:10:56 +02:00
return result;
2023-06-03 16:04:42 +02:00
},
}
2023-07-10 02:10:56 +02:00
},
2023-04-19 01:25:35 +02:00
2023-07-10 02:10:56 +02:00
.Float => {
var has_sign = switch (utf8[0]) {
'-', '+', ' ' => true,
else => false,
};
2023-05-23 02:08:34 +02:00
2023-07-10 02:10:56 +02:00
// "-"
if (has_sign and utf8.len == 1) {
return null;
}
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
const sign_offset = @intFromBool(has_sign);
var has_decimal = utf8[sign_offset] == '.';
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
// "-."
if (has_decimal and (utf8.len == 2)) {
return null;
}
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
var result = @as(Decimal, 0);
var factor = @as(Decimal, if (has_sign and utf8[0] == '-') -1 else 1);
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
for (utf8[sign_offset + @intFromBool(has_decimal) .. utf8.len]) |code| {
switch (code) {
'.' => {
if (has_decimal) {
return null;
2023-06-03 16:04:42 +02:00
}
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
has_decimal = true;
2023-06-03 16:04:42 +02:00
},
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
if (has_decimal) {
factor /= 10.0;
2023-06-03 16:04:42 +02:00
}
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
result = ((result * 10.0) + @as(Decimal, @floatFromInt(code - '0')));
},
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
else => return null,
2023-06-03 16:04:42 +02:00
}
2023-06-02 23:43:53 +02:00
}
2023-05-23 02:08:34 +02:00
2023-07-10 02:10:56 +02:00
return result * factor;
},
2023-05-23 02:08:34 +02:00
2023-07-10 02:10:56 +02:00
else => @compileError("`" ++ @typeName(Decimal) ++ "` cannot be formatted as a decimal string"),
}
2023-05-23 02:08:34 +02:00
}
2023-07-10 02:10:56 +02:00
};
2023-05-23 02:08:34 +02:00