Rework RocDec.toString internals

This commit is contained in:
Jared Ramirez 2021-06-06 15:38:49 -07:00
parent 060e977cca
commit ea893b3481

View file

@ -102,6 +102,7 @@ pub const RocDec = struct {
return dec; return dec;
} }
// TODO: Replace this with https://github.com/rtfeldman/roc/pull/1365/files#r643580738
fn isDigit(c: u8) bool { fn isDigit(c: u8) bool {
return switch (c) { return switch (c) {
'0'...'9' => true, '0'...'9' => true,
@ -110,16 +111,33 @@ pub const RocDec = struct {
} }
pub fn toStr(self: RocDec) ?RocStr { pub fn toStr(self: RocDec) ?RocStr {
var num_bytes: [max_digits]u8 = undefined; var digit_bytes: [max_digits]u8 = undefined;
var num_digits = std.fmt.formatIntBuf(num_bytes[0..], self.num, 10, false, .{}); var num_digits_formatted = std.fmt.formatIntBuf(digit_bytes[0..], self.num, 10, false, .{});
var before_num_digits = num_digits - decimal_places; var before_digits_num_raw: usize = undefined;
var before_digits_num: usize = undefined;
var before_digits_slice: []const u8 = undefined;
if (num_digits_formatted > decimal_places) {
before_digits_num_raw = num_digits_formatted - decimal_places;
if (before_digits_num_raw == 1 and digit_bytes[0] == '-') {
before_digits_num = 2;
before_digits_slice = "-0"[0..];
} else {
before_digits_num = before_digits_num_raw;
before_digits_slice = digit_bytes[0..before_digits_num_raw];
}
} else {
before_digits_num_raw = 0;
before_digits_num = 1;
before_digits_slice = "0"[0..];
}
var index = decimal_places - 1; var index = decimal_places - 1;
var trim_index: ?usize = null; var trim_index: ?usize = null;
var is_consecutive_zero = true; var is_consecutive_zero = true;
while (index != 0) { while (index != 0) {
var digit = num_bytes[before_num_digits + index]; var digit = digit_bytes[before_digits_num_raw + index];
if (digit == '0' and is_consecutive_zero) { if (digit == '0' and is_consecutive_zero) {
trim_index = index; trim_index = index;
} else { } else {
@ -127,38 +145,19 @@ pub const RocDec = struct {
} }
index -= 1; index -= 1;
} }
var after_num_digits = if (trim_index) |i| i else decimal_places;
const should_add_prefix_zero = before_num_digits == 0 or (before_num_digits == 1 and num_bytes[0] == '-'); var after_digits_num = if (trim_index) |i| i else decimal_places;
const prefix_zero_len: usize = if (should_add_prefix_zero) 1 else 0; var after_digits_slice: []const u8 = undefined;
const dot_len: usize = 1; after_digits_slice = digit_bytes[before_digits_num_raw..(before_digits_num_raw + after_digits_num)];
var str_len = prefix_zero_len + before_num_digits + dot_len + after_num_digits;
// [max_digits + 2] here to account for '.' and '-' // `+ 1` in here to account for the '.'
// `before_digits_num` already includes the '-'
var str_len: usize = before_digits_num + 1 + after_digits_num;
// TODO: Ideally we'd use [str_len]u8 here, but Zig gives an error if we do that.
// [max_digits + 2]u8 here to account for '.' and '-', aka the max possible length of the string
var str_bytes: [max_digits + 2]u8 = undefined; var str_bytes: [max_digits + 2]u8 = undefined;
_ = std.fmt.bufPrint(str_bytes[0 .. str_len + 1], "{s}.{s}", .{ before_digits_slice, after_digits_slice }) catch unreachable;
var str_bytes_index: usize = 0;
var bytes_index: usize = 0;
if (should_add_prefix_zero) {
if (num_bytes[bytes_index] == '-') {
str_bytes[str_bytes_index] = '-';
str_bytes_index += 1;
bytes_index += 1;
}
str_bytes[str_bytes_index] = '0';
str_bytes_index += 1;
}
while (bytes_index < str_len) {
if (bytes_index == before_num_digits) {
str_bytes[str_bytes_index] = '.';
str_bytes_index += 1;
}
str_bytes[str_bytes_index] = num_bytes[bytes_index];
str_bytes_index += 1;
bytes_index += 1;
}
return RocStr.init(&str_bytes, str_len); return RocStr.init(&str_bytes, str_len);
} }
@ -536,6 +535,14 @@ test "toStr: -0.45" {
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice()); try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
} }
// test "toStr: 0.00045" {
// var dec: RocDec = .{ .num = 000450000000000000 };
// var res_roc_str = dec.toStr();
// const res_slice: []const u8 = "0.00045"[0..];
// try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
// }
test "toStr: -111.123456789" { test "toStr: -111.123456789" {
var dec: RocDec = .{ .num = -111123456789000000000 }; var dec: RocDec = .{ .num = -111123456789000000000 };
var res_roc_str = dec.toStr(); var res_roc_str = dec.toStr();