#import . "decimal.odin"; #import "math.odin"; Int_Flag :: 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 := cast(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_i64 :: proc(s: string, base: int) -> i64 { result: i64; for r in s { v := _digit_value(r); if v >= base { break; } result *= cast(i64)base; result += cast(i64)v; } return result; } parse_u64 :: proc(s: string, base: int) -> u64 { result: u64; for r in s { v := _digit_value(r); if v >= base { break; } result *= cast(u64)base; result += cast(u64)v; } return result; } parse_int :: proc(s: string, base: int) -> int { return cast(int)parse_i64(s, base); } parse_uint :: proc(s: string, base: int) -> uint { return cast(uint)parse_u64(s, base); } append_bool :: proc(buf: []byte, b: bool) -> string { s := b ? "true" : "false"; append(buf, ..cast([]byte)s); return cast(string)buf; } append_uint :: proc(buf: []byte, u: u64, base: int) -> string { return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0); } append_int :: proc(buf: []byte, i: i64, base: int) -> string { return append_bits(buf, cast(u64)i, base, true, 8*size_of(int), digits, 0); } itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, cast(i64)i, 10); } append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size); } Decimal_Slice :: struct { digits: []byte, count: int, decimal_point: int, neg: bool, } Float_Info :: struct { mantbits: uint, expbits: uint, bias: int, } f32_info := Float_Info{23, 8, -127}; f64_info := Float_Info{52, 11, -1023}; generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte { bits: u64; flt: ^Float_Info; match bit_size { case 32: bits = cast(u64)transmute(u32)cast(f32)val; flt = ^f32_info; case 64: bits = transmute(u64)val; flt = ^f64_info; default: panic("strconv: invalid bit_size"); } neg := bits>>(flt.expbits+flt.mantbits) != 0; exp := cast(int)(bits>>flt.mantbits) & (1< []byte { 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 - cast(int)flt.mantbits) { // Number is already its shortest return; } upper_: Decimal; upper: = ^upper_; assign(upper, 2*mant - 1); shift(upper, exp - cast(int)flt.mantbits - 1); mantlo: u64; explo: int; if mant > 1< (unsigned: u64, neg: bool) { neg := false; if is_signed { match bit_size { case 8: i := cast(i8)u; neg = i < 0; if neg { i = -i; } u = cast(u64)i; case 16: i := cast(i16)u; neg = i < 0; if neg { i = -i; } u = cast(u64)i; case 32: i := cast(i32)u; neg = i < 0; if neg { i = -i; } u = cast(u64)i; case 64: i := cast(i64)u; neg = i < 0; if neg { i = -i; } u = cast(u64)i; default: panic("is_integer_negative: Unknown integer size"); } } return u, neg; } append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string { is_pow2 :: proc(x: i64) -> bool { if (x <= 0) { return false; } return x&(x-1) == 0; } if base < 2 || base > MAX_BASE { panic("strconv: illegal base passed to append_bits"); } a: [65]byte; i := len(a); neg: bool; u, neg = is_integer_negative(u, is_signed, bit_size); for b := cast(u64)base; u >= b; { i--; q := u / b; a[i] = digits[cast(uint)(u-q*b)]; u = q; } i--; a[i] = digits[cast(uint)u]; if flags&Int_Flag.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'; default: ok = false; } if ok { i--; a[i] = '0'; } } if neg { i--; a[i] = '-'; } else if flags&Int_Flag.PLUS != 0 { i--; a[i] = '+'; } else if flags&Int_Flag.SPACE != 0 { i--; a[i] = ' '; } append(buf, ..a[i..]); return cast(string)buf; }