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;
}
// TODO: Replace this with https://github.com/rtfeldman/roc/pull/1365/files#r643580738
fn isDigit(c: u8) bool {
return switch (c) {
'0'...'9' => true,
@ -110,16 +111,33 @@ pub const RocDec = struct {
}
pub fn toStr(self: RocDec) ?RocStr {
var num_bytes: [max_digits]u8 = undefined;
var num_digits = std.fmt.formatIntBuf(num_bytes[0..], self.num, 10, false, .{});
var digit_bytes: [max_digits]u8 = undefined;
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 trim_index: ?usize = null;
var is_consecutive_zero = true;
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) {
trim_index = index;
} else {
@ -127,38 +145,19 @@ pub const RocDec = struct {
}
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] == '-');
const prefix_zero_len: usize = if (should_add_prefix_zero) 1 else 0;
const dot_len: usize = 1;
var str_len = prefix_zero_len + before_num_digits + dot_len + after_num_digits;
var after_digits_num = if (trim_index) |i| i else decimal_places;
var after_digits_slice: []const u8 = undefined;
after_digits_slice = digit_bytes[before_digits_num_raw..(before_digits_num_raw + after_digits_num)];
// [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_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;
}
_ = std.fmt.bufPrint(str_bytes[0 .. str_len + 1], "{s}.{s}", .{ before_digits_slice, after_digits_slice }) catch unreachable;
return RocStr.init(&str_bytes, str_len);
}
@ -536,6 +535,14 @@ test "toStr: -0.45" {
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" {
var dec: RocDec = .{ .num = -111123456789000000000 };
var res_roc_str = dec.toStr();