#import . "decimal.odin"; IntFlag :: enum { Prefix = 1<<0, Plus = 1<<1, Space = 1<<2, } parse_bool :: proc(s: string) -> (result: bool, ok: bool) { match s { case "1", "t", "T", "true", "TRUE", "True": return true, true; case "0", "f", "F", "false", "FALSE", "False": return false, true; } return false, false; } _digit_value :: proc(r: rune) -> (int) { ri := int(r); v: int = 16; match r { case '0'..'9': v = ri-'0'; case 'a'..'z': v = ri-'a'+10; case 'A'..'Z': v = ri-'A'+10; } return v; } parse_i128 :: proc(s: string) -> i128 { neg := false; if len(s) > 1 { match s[0] { case '-': neg = true; s = s[1..]; case '+': s = s[1..]; } } base: i128 = 10; if len(s) > 2 && s[0] == '0' { match s[1] { case 'b': base = 2; s = s[2..]; case 'o': base = 8; s = s[2..]; case 'd': base = 10; s = s[2..]; case 'z': base = 12; s = s[2..]; case 'x': base = 16; s = s[2..]; } } value: i128; for r in s { if r == '_' { continue; } v := i128(_digit_value(r)); if v >= base { break; } value *= base; value += v; } return neg ? -value : value; } parse_u128 :: proc(s: string) -> u128 { neg := false; if len(s) > 1 && s[0] == '+' { s = s[1..]; } base: = u128(10); if len(s) > 2 && s[0] == '0' { match s[1] { case 'b': base = 2; s = s[2..]; case 'o': base = 8; s = s[2..]; case 'd': base = 10; s = s[2..]; case 'z': base = 12; s = s[2..]; case 'x': base = 16; s = s[2..]; } } value: u128; for r in s { if r == '_' { continue; } v := u128(_digit_value(r)); if v >= base { break; } value *= base; value += u128(v); } return neg ? -value : value; } parse_int :: proc(s: string) -> int { return int(parse_i128(s)); } parse_uint :: proc(s: string, base: int) -> uint { return uint(parse_u128(s)); } parse_f64 :: proc(s: string) -> f64 { i := 0; sign: f64 = 1; match s[i] { case '-': i++; sign = -1; case '+': i++; } value: f64 = 0; for ; i < len(s); i++ { r := rune(s[i]); if r == '_' { continue; } v := _digit_value(r); if v >= 10 { break; } value *= 10; value += f64(v); } if s[i] == '.' { pow10: f64 = 10; i++; for ; i < len(s); i++ { r := rune(s[i]); if r == '_' { continue; } v := _digit_value(r); if v >= 10 { break; } value += f64(v)/pow10; pow10 *= 10; } } frac := false; scale: f64 = 1; if s[i] == 'e' || s[i] == 'E' { i++; match s[i] { case '-': i++; frac = true; case '+': i++; } exp: u32 = 0; for ; i < len(s); i++ { r := rune(s[i]); if r == '_' { continue; } d := u32(_digit_value(r)); if d >= 10 { break; } exp = exp * 10 + d; } if exp > 308 { exp = 308; } for exp >= 50 { scale *= 1e50; exp -= 50; } for exp >= 8 { scale *= 1e8; exp -= 8; } for exp > 0 { scale *= 10; exp -= 1; } } return sign * (frac ? (value/scale) : (value*scale)); } append_bool :: proc(buf: []u8, b: bool) -> string { s := b ? "true" : "false"; append(buf, ..[]u8(s)); return string(buf); } append_uint :: proc(buf: []u8, u: u64, base: int) -> string { return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0); } append_int :: proc(buf: []u8, i: i64, base: int) -> string { return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0); } itoa :: proc(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); } append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string { return string(generic_ftoa(buf, f, fmt, prec, bit_size)); } DecimalSlice :: struct { digits: []u8, count: int, decimal_point: int, neg: bool, } Float_Info :: struct { mantbits: uint, expbits: uint, bias: int, } _f16_info := Float_Info{10, 5, -15}; _f32_info := Float_Info{23, 8, -127}; _f64_info := Float_Info{52, 11, -1023}; generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 { bits: u64; flt: ^Float_Info; match bit_size { case 32: bits = u64(transmute(u32, f32(val))); flt = &_f32_info; case 64: bits = transmute(u64, val); flt = &_f64_info; case: panic("strconv: invalid bit_size"); } neg := bits>>(flt.expbits+flt.mantbits) != 0; exp := int(bits>>flt.mantbits) & (1< []u8 { match fmt { case 'f', 'F': append(buf, neg ? '-' : '+'); // integer, padded with zeros when needed if digs.decimal_point > 0 { m := min(digs.count, digs.decimal_point); append(buf, ..digs.digits[0.. 0 { append(buf, '.'); for i in 0.. 2^(exp-mantbits) log2(10) * (dp-nd) > exp-mantbits log(2) >~ 0.332 332*(dp-nd) >= 100*(exp-mantbits) */ minexp := flt.bias+1; if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) { // Number is already its shortest return; } upper_: Decimal; upper: = &upper_; assign(upper, 2*mant - 1); shift(upper, exp - int(flt.mantbits) - 1); mantlo: u64; explo: int; if mant > 1< (unsigned: u128, neg: bool) { neg := false; if is_signed { match bit_size { case 8: i := i8(u); neg = i < 0; if neg { i = -i; } u = u128(i); case 16: i := i16(u); neg = i < 0; if neg { i = -i; } u = u128(i); case 32: i := i32(u); neg = i < 0; if neg { i = -i; } u = u128(i); case 64: i := i64(u); neg = i < 0; if neg { i = -i; } u = u128(i); case 128: i := i128(u); neg = i < 0; if neg { i = -i; } u = u128(i); case: panic("is_integer_negative: Unknown integer size"); } } return u, neg; } append_bits :: proc(buf: []u8, u_: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string { if base < 2 || base > MAX_BASE { panic("strconv: illegal base passed to append_bits"); } a: [129]u8; i := len(a); u, neg := is_integer_negative(u_, is_signed, bit_size); b := u128(base); for u >= b { i--; a[i] = digits[uint(u % b)]; u /= b; } i--; a[i] = digits[uint(u % b)]; if flags&IntFlag.Prefix != 0 { ok := true; match base { case 2: i--; a[i] = 'b'; case 8: i--; a[i] = 'o'; case 10: i--; a[i] = 'd'; case 12: i--; a[i] = 'z'; case 16: i--; a[i] = 'x'; case: ok = false; } if ok { i--; a[i] = '0'; } } if neg { i--; a[i] = '-'; } else if flags&IntFlag.Plus != 0 { i--; a[i] = '+'; } else if flags&IntFlag.Space != 0 { i--; a[i] = ' '; } append(buf, ..a[i..]); return string(buf); }