#import . "decimal.odin"; #import "math.odin"; #import format "fmt.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; } format_bool :: proc(buf: []byte, b: bool) -> string { s := b ? "true" : "false"; len := copy(buf, cast([]byte)s); return cast(string)buf[:len]; } format_uint :: proc(buf: []byte, u: u64, base: int) -> string { using Int_Flag; return format_bits(buf, u, base, false, digits, 0); } format_int :: proc(buf: []byte, i: i64, base: int) -> string { return format_bits(buf, cast(u64)i, base, i < 0, digits, 0); } itoa :: proc(buf: []byte, i: int) -> string { return format_int(buf, cast(i64)i, 10); } format_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 { d: []byte, ndu: int, dp: 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': add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ...byte) { for b in bytes { if dst.count <= w^ { break; } dst[w^] = b; w^++; } } dst := buf[:]; w := 0; if neg { add_bytes(^dst, ^w, '-'); } else { add_bytes(^dst, ^w, '+'); } // integer, padded with zeros when needed if digs.dp > 0 { m := min(digs.ndu, digs.dp); add_bytes(^dst, ^w, ...digs.d[:m]); for ; m < digs.dp; m++ { add_bytes(^dst, ^w, '0'); } } else { add_bytes(^dst, ^w, '0'); } // fractional part if prec > 0 { add_bytes(^dst, ^w, '.'); 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.dp-d.ndu) >= 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< 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 format_bits"); } a: [65]byte; i := a.count; if neg { u = -u; } if is_pow2(cast(i64)base) { b := cast(u64)base; m := cast(uint)b - 1; for u >= b { i--; a[i] = digits[cast(uint)u & m]; u >>= b; } i--; a[i] = digits[cast(uint)u]; } else { b := cast(u64)base; for 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 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] = ' '; } len := copy(buf, ...a[i:]); return cast(string)buf[:len]; }