#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; } 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[..m]); for ; m < digs.decimal_point; m++ { append(buf, '0'); } } else { append(buf, '0'); } // fractional part if prec > 0 { append(buf, '.'); for i in 0..prec { c: byte = '0'; if j := digs.decimal_point + i; 0 <= j && j < digs.count { c = digs.digits[j]; } append(buf, c); } } return buf; case 'e', 'E': panic("strconv: e/E float printing is not yet supported"); return buf; // TODO case 'g', 'G': panic("strconv: g/G float printing is not yet supported"); return buf; // TODO } c: [2]byte; c[0] = '%'; c[1] = fmt; append(buf, ..c[..]); return buf; } round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) { if mant == 0 { // If mantissa is zero, the number is zero d.count = 0; return; } /* 10^(dp-nd) > 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; }