strconv: vfmt everything

pull/10508/head
Delyan Angelov 2021-06-18 17:59:56 +03:00
parent 5dff8dc097
commit de384f1cc8
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
17 changed files with 1544 additions and 1252 deletions

View File

@ -43,7 +43,6 @@ const (
'vlib/', 'vlib/',
] ]
vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [ vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
'vlib/strconv/' /* prevent conflicts, till the new pure V string interpolation is merged */,
'vlib/term/ui/input.v' /* comment after a struct embed is removed */, 'vlib/term/ui/input.v' /* comment after a struct embed is removed */,
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */, 'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */, 'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */,

View File

@ -414,7 +414,6 @@ Public functions
// atof64 return a f64 from a string doing a parsing operation // atof64 return a f64 from a string doing a parsing operation
pub fn atof64(s string) f64 { pub fn atof64(s string) f64 {
mut pn := PrepNumber{} mut pn := PrepNumber{}
mut res_parsing := 0 mut res_parsing := 0
mut res := Float64u{} mut res := Float64u{}

View File

@ -1,4 +1,5 @@
import strconv import strconv
/********************************************************************** /**********************************************************************
* *
* String to float Test * String to float Test
@ -18,7 +19,7 @@ fn test_atof() {
-0.004, -0.004,
0.0, 0.0,
-0.0, -0.0,
31234567890123 31234567890123,
] ]
// strings // strings
@ -33,28 +34,27 @@ fn test_atof() {
] ]
// check conversion case 1 string <=> string // check conversion case 1 string <=> string
for c,x in src_num { for c, x in src_num {
// slow atof // slow atof
assert strconv.atof64(src_num_str[c]).strlong() == x.strlong() assert strconv.atof64(src_num_str[c]).strlong() == x.strlong()
// quick atof // quick atof
mut s1 := (strconv.atof_quick(src_num_str[c]).str()) mut s1 := (strconv.atof_quick(src_num_str[c]).str())
mut s2 := (x.str()) mut s2 := (x.str())
delta := s1.f64() - s2.f64() delta := s1.f64() - s2.f64()
//println("$s1 $s2 $delta") // println("$s1 $s2 $delta")
assert delta < f64(1e-16) assert delta < f64(1e-16)
// test C.atof // test C.atof
n1 := x.strsci(18) n1 := x.strsci(18)
n2 := f64(C.atof(&char(src_num_str[c].str))).strsci(18) n2 := f64(C.atof(&char(src_num_str[c].str))).strsci(18)
//println("$n1 $n2") // println("$n1 $n2")
assert n1 == n2 assert n1 == n2
} }
// check conversion case 2 string <==> f64 // check conversion case 2 string <==> f64
// we don't test atof_quick beacuse we already know the rounding error // we don't test atof_quick beacuse we already know the rounding error
for c,x in src_num_str { for c, x in src_num_str {
b := src_num[c].strlong() b := src_num[c].strlong()
a1 := strconv.atof64(x).strlong() a1 := strconv.atof64(x).strlong()
assert a1 == b assert a1 == b
@ -62,14 +62,14 @@ fn test_atof() {
// special cases // special cases
mut f1 := f64(0.0) mut f1 := f64(0.0)
mut ptr := unsafe {&u64(&f1)} mut ptr := unsafe { &u64(&f1) }
ptr = unsafe {&u64(&f1)} ptr = unsafe { &u64(&f1) }
// double_plus_zero // double_plus_zero
f1=0.0 f1 = 0.0
assert *ptr == u64(0x0000000000000000) assert *ptr == u64(0x0000000000000000)
// double_minus_zero // double_minus_zero
f1=-0.0 f1 = -0.0
assert *ptr == u64(0x8000000000000000) assert *ptr == u64(0x8000000000000000)
println("DONE!") println('DONE!')
} }

File diff suppressed because one or more lines are too long

View File

@ -69,15 +69,15 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) {
return u64(0), -1 return u64(0), -1
} }
if bit_size == 0 { if bit_size == 0 {
bit_size = int_size bit_size = strconv.int_size
} else if bit_size < 0 || bit_size > 64 { } else if bit_size < 0 || bit_size > 64 {
// return error('parse_uint: bitsize error $s - $bit_size') // return error('parse_uint: bitsize error $s - $bit_size')
return u64(0), -2 return u64(0), -2
} }
// Cutoff is the smallest number such that cutoff*base > maxUint64. // Cutoff is the smallest number such that cutoff*base > maxUint64.
// Use compile-time constants for common cases. // Use compile-time constants for common cases.
cutoff := max_u64 / u64(base) + u64(1) cutoff := strconv.max_u64 / u64(base) + u64(1)
max_val := if bit_size == 64 { max_u64 } else { (u64(1) << u64(bit_size)) - u64(1) } max_val := if bit_size == 64 { strconv.max_u64 } else { (u64(1) << u64(bit_size)) - u64(1) }
mut n := u64(0) mut n := u64(0)
for i in start_index .. s.len { for i in start_index .. s.len {
c := s[i] c := s[i]
@ -144,7 +144,7 @@ pub fn common_parse_int(_s string, base int, _bit_size int, error_on_non_digit b
return i64(0) return i64(0)
} }
if bit_size == 0 { if bit_size == 0 {
bit_size = int_size bit_size = strconv.int_size
} }
// TODO: check should u64(bit_size-1) be size of int (32)? // TODO: check should u64(bit_size-1) be size of int (32)?
cutoff := u64(1) << u64(bit_size - 1) cutoff := u64(1) << u64(bit_size - 1)
@ -156,11 +156,7 @@ pub fn common_parse_int(_s string, base int, _bit_size int, error_on_non_digit b
// return error('parse_int: range error $s0') // return error('parse_int: range error $s0')
return -i64(cutoff) return -i64(cutoff)
} }
return if neg { return if neg { -i64(un) } else { i64(un) }
-i64(un)
} else {
i64(un)
}
} }
// parse_int interprets a string s in the given base (0, 2 to 36) and // parse_int interprets a string s in the given base (0, 2 to 36) and
@ -184,9 +180,8 @@ pub fn atoi(s string) ?int {
if s == '' { if s == '' {
return error('strconv.atoi: parsing "$s": invalid syntax ') return error('strconv.atoi: parsing "$s": invalid syntax ')
} }
if (int_size == 32 && (0 < s.len && if (strconv.int_size == 32 && (0 < s.len && s.len < 10))
s.len < 10)) || || (strconv.int_size == 64 && (0 < s.len && s.len < 19)) {
(int_size == 64 && (0 < s.len && s.len < 19)) {
// Fast path for small integers that fit int type. // Fast path for small integers that fit int type.
mut start_idx := 0 mut start_idx := 0
if s[0] == `-` || s[0] == `+` { if s[0] == `-` || s[0] == `+` {
@ -205,11 +200,7 @@ pub fn atoi(s string) ?int {
} }
n = n * 10 + int(ch) n = n * 10 + int(ch)
} }
return if s[0] == `-` { return if s[0] == `-` { -n } else { n }
-n
} else {
n
}
} }
// Slow path for invalid, big, or underscored integers. // Slow path for invalid, big, or underscored integers.
int64 := parse_int(s, 10, 0) int64 := parse_int(s, 10, 0)
@ -233,8 +224,8 @@ fn underscore_ok(s string) bool {
} }
// Optional base prefix. // Optional base prefix.
mut hex := false mut hex := false
if s.len - i >= 2 && s[i] == `0` && if s.len - i >= 2 && s[i] == `0` && (byte_to_lower(s[i + 1]) == `b`
(byte_to_lower(s[i + 1]) == `b` || byte_to_lower(s[i + 1]) == `o` || byte_to_lower(s[i + 1]) == `x`) { || byte_to_lower(s[i + 1]) == `o` || byte_to_lower(s[i + 1]) == `x`) {
saw = `0` // base prefix counts as a digit for "underscore as digit separator" saw = `0` // base prefix counts as a digit for "underscore as digit separator"
hex = byte_to_lower(s[i + 1]) == `x` hex = byte_to_lower(s[i + 1]) == `x`
i += 2 i += 2
@ -242,8 +233,8 @@ fn underscore_ok(s string) bool {
// Number proper. // Number proper.
for ; i < s.len; i++ { for ; i < s.len; i++ {
// Digits are always okay. // Digits are always okay.
if (`0` <= s[i] && s[i] <= `9`) || if (`0` <= s[i] && s[i] <= `9`) || (hex && `a` <= byte_to_lower(s[i])
(hex && `a` <= byte_to_lower(s[i]) && byte_to_lower(s[i]) <= `f`) { && byte_to_lower(s[i]) <= `f`) {
saw = `0` saw = `0`
continue continue
} }

View File

@ -1,4 +1,5 @@
module strconv module strconv
/*============================================================================= /*=============================================================================
f32 to string f32 to string
@ -20,7 +21,7 @@ https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
=============================================================================*/ =============================================================================*/
// pow of ten table used by n_digit reduction // pow of ten table used by n_digit reduction
const( const (
ten_pow_table_32 = [ ten_pow_table_32 = [
u32(1), u32(1),
u32(10), u32(10),
@ -40,34 +41,34 @@ const(
//============================================================================= //=============================================================================
// Conversion Functions // Conversion Functions
//============================================================================= //=============================================================================
const( const (
mantbits32 = u32(23) mantbits32 = u32(23)
expbits32 = u32(8) expbits32 = u32(8)
bias32 = 127 // f32 exponent bias bias32 = 127 // f32 exponent bias
maxexp32 = 255 maxexp32 = 255
) )
// max 46 char // max 46 char
// -3.40282346638528859811704183484516925440e+38 // -3.40282346638528859811704183484516925440e+38
[direct_array_access] [direct_array_access]
pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string { pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string {
n_digit := i_n_digit + 1 n_digit := i_n_digit + 1
pad_digit := i_pad_digit + 1 pad_digit := i_pad_digit + 1
mut out := d.m mut out := d.m
//mut out_len := decimal_len_32(out) // mut out_len := decimal_len_32(out)
mut out_len := dec_digits(out) mut out_len := dec_digits(out)
out_len_original := out_len out_len_original := out_len
mut fw_zeros := 0 mut fw_zeros := 0
if pad_digit > out_len { if pad_digit > out_len {
fw_zeros = pad_digit -out_len fw_zeros = pad_digit - out_len
} }
mut buf := []byte{len:int(out_len + 5 + 1 +1)} // sign + mant_len + . + e + e_sign + exp_len(2) + \0} mut buf := []byte{len: int(out_len + 5 + 1 + 1)} // sign + mant_len + . + e + e_sign + exp_len(2) + \0}
mut i := 0 mut i := 0
if neg { if neg {
buf[i]=`-` buf[i] = `-`
i++ i++
} }
@ -77,16 +78,16 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
} }
if n_digit < out_len { if n_digit < out_len {
//println("orig: ${out_len_original}") // println("orig: ${out_len_original}")
out += ten_pow_table_32[out_len - n_digit - 1] * 5 // round to up out += strconv.ten_pow_table_32[out_len - n_digit - 1] * 5 // round to up
out /= ten_pow_table_32[out_len - n_digit] out /= strconv.ten_pow_table_32[out_len - n_digit]
out_len = n_digit out_len = n_digit
} }
y := i + out_len y := i + out_len
mut x := 0 mut x := 0
for x < (out_len-disp-1) { for x < (out_len - disp - 1) {
buf[y - x] = `0` + byte(out%10) buf[y - x] = `0` + byte(out % 10)
out /= 10 out /= 10
i++ i++
x++ x++
@ -95,8 +96,8 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
// no decimal digits needed, end here // no decimal digits needed, end here
if i_n_digit == 0 { if i_n_digit == 0 {
unsafe { unsafe {
buf[i]=0 buf[i] = 0
return tos(byteptr(&buf[0]), i) return tos(&byte(&buf[0]), i)
} }
} }
@ -106,8 +107,8 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
i++ i++
} }
if y-x >= 0 { if y - x >= 0 {
buf[y - x] = `0` + byte(out%10) buf[y - x] = `0` + byte(out % 10)
i++ i++
} }
@ -117,42 +118,42 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
fw_zeros-- fw_zeros--
} }
buf[i]=`e` buf[i] = `e`
i++ i++
mut exp := d.e + out_len_original - 1 mut exp := d.e + out_len_original - 1
if exp < 0 { if exp < 0 {
buf[i]=`-` buf[i] = `-`
i++ i++
exp = -exp exp = -exp
} else { } else {
buf[i]=`+` buf[i] = `+`
i++ i++
} }
// Always print two digits to match strconv's formatting. // Always print two digits to match strconv's formatting.
d1 := exp % 10 d1 := exp % 10
d0 := exp / 10 d0 := exp / 10
buf[i]=`0` + byte(d0) buf[i] = `0` + byte(d0)
i++ i++
buf[i]=`0` + byte(d1) buf[i] = `0` + byte(d1)
i++ i++
buf[i]=0 buf[i] = 0
return unsafe { return unsafe {
tos(byteptr(&buf[0]), i) tos(&byte(&buf[0]), i)
} }
} }
fn f32_to_decimal_exact_int(i_mant u32, exp u32) (Dec32,bool) { fn f32_to_decimal_exact_int(i_mant u32, exp u32) (Dec32, bool) {
mut d := Dec32{} mut d := Dec32{}
e := exp - bias32 e := exp - strconv.bias32
if e > mantbits32 { if e > strconv.mantbits32 {
return d, false return d, false
} }
shift := mantbits32 - e shift := strconv.mantbits32 - e
mant := i_mant | 0x0080_0000 // implicit 1 mant := i_mant | 0x0080_0000 // implicit 1
//mant := i_mant | (1 << mantbits32) // implicit 1 // mant := i_mant | (1 << mantbits32) // implicit 1
d.m = mant >> shift d.m = mant >> shift
if (d.m << shift) != mant { if (d.m << shift) != mant {
return d, false return d, false
@ -170,28 +171,28 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
if exp == 0 { if exp == 0 {
// We subtract 2 so that the bounds computation has // We subtract 2 so that the bounds computation has
// 2 additional bits. // 2 additional bits.
e2 = 1 - bias32 - int(mantbits32) - 2 e2 = 1 - strconv.bias32 - int(strconv.mantbits32) - 2
m2 = mant m2 = mant
} else { } else {
e2 = int(exp) - bias32 - int(mantbits32) - 2 e2 = int(exp) - strconv.bias32 - int(strconv.mantbits32) - 2
m2 = (u32(1) << mantbits32) | mant m2 = (u32(1) << strconv.mantbits32) | mant
} }
even := (m2 & 1) == 0 even := (m2 & 1) == 0
accept_bounds := even accept_bounds := even
// Step 2: Determine the interval of valid decimal representations. // Step 2: Determine the interval of valid decimal representations.
mv := u32(4 * m2) mv := u32(4 * m2)
mp := u32(4 * m2 + 2) mp := u32(4 * m2 + 2)
mm_shift := bool_to_u32(mant != 0 || exp <= 1) mm_shift := bool_to_u32(mant != 0 || exp <= 1)
mm := u32(4 * m2 - 1 - mm_shift) mm := u32(4 * m2 - 1 - mm_shift)
mut vr := u32(0) mut vr := u32(0)
mut vp := u32(0) mut vp := u32(0)
mut vm := u32(0) mut vm := u32(0)
mut e10 := 0 mut e10 := 0
mut vm_is_trailing_zeros := false mut vm_is_trailing_zeros := false
mut vr_is_trailing_zeros := false mut vr_is_trailing_zeros := false
mut last_removed_digit := byte(0) mut last_removed_digit := byte(0)
if e2 >= 0 { if e2 >= 0 {
q := log10_pow2(e2) q := log10_pow2(e2)
@ -202,7 +203,7 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
vr = mul_pow5_invdiv_pow2(mv, q, i) vr = mul_pow5_invdiv_pow2(mv, q, i)
vp = mul_pow5_invdiv_pow2(mp, q, i) vp = mul_pow5_invdiv_pow2(mp, q, i)
vm = mul_pow5_invdiv_pow2(mm, q, i) vm = mul_pow5_invdiv_pow2(mm, q, i)
if q != 0 && (vp-1)/10 <= vm/10 { if q != 0 && (vp - 1) / 10 <= vm / 10 {
// We need to know one removed digit even if we are not // We need to know one removed digit even if we are not
// going to loop below. We could use q = X - 1 above, // going to loop below. We could use q = X - 1 above,
// except that would require 33 bits for the result, and // except that would require 33 bits for the result, and
@ -232,7 +233,7 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
vr = mul_pow5_div_pow2(mv, u32(i), j) vr = mul_pow5_div_pow2(mv, u32(i), j)
vp = mul_pow5_div_pow2(mp, u32(i), j) vp = mul_pow5_div_pow2(mp, u32(i), j)
vm = mul_pow5_div_pow2(mm, u32(i), j) vm = mul_pow5_div_pow2(mm, u32(i), j)
if q != 0 && ((vp-1)/10) <= vm/10 { if q != 0 && ((vp - 1) / 10) <= vm / 10 {
j = int(q) - 1 - (pow5_bits(i + 1) - pow5_num_bits_32) j = int(q) - 1 - (pow5_bits(i + 1) - pow5_num_bits_32)
last_removed_digit = byte(mul_pow5_div_pow2(mv, u32(i + 1), j) % 10) last_removed_digit = byte(mul_pow5_div_pow2(mv, u32(i + 1), j) % 10)
} }
@ -258,10 +259,10 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
// Step 4: Find the shortest decimal representation // Step 4: Find the shortest decimal representation
// in the interval of valid representations. // in the interval of valid representations.
mut removed := 0 mut removed := 0
mut out := u32(0) mut out := u32(0)
if vm_is_trailing_zeros || vr_is_trailing_zeros { if vm_is_trailing_zeros || vr_is_trailing_zeros {
// General case, which happens rarely (~4.0%). // General case, which happens rarely (~4.0%).
for vp/10 > vm/10 { for vp / 10 > vm / 10 {
vm_is_trailing_zeros = vm_is_trailing_zeros && (vm % 10) == 0 vm_is_trailing_zeros = vm_is_trailing_zeros && (vm % 10) == 0
vr_is_trailing_zeros = vr_is_trailing_zeros && (last_removed_digit == 0) vr_is_trailing_zeros = vr_is_trailing_zeros && (last_removed_digit == 0)
last_removed_digit = byte(vr % 10) last_removed_digit = byte(vr % 10)
@ -271,7 +272,7 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
removed++ removed++
} }
if vm_is_trailing_zeros { if vm_is_trailing_zeros {
for vm%10 == 0 { for vm % 10 == 0 {
vr_is_trailing_zeros = vr_is_trailing_zeros && (last_removed_digit == 0) vr_is_trailing_zeros = vr_is_trailing_zeros && (last_removed_digit == 0)
last_removed_digit = byte(vr % 10) last_removed_digit = byte(vr % 10)
vr /= 10 vr /= 10
@ -294,7 +295,7 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
// Specialized for the common case (~96.0%). Percentages below // Specialized for the common case (~96.0%). Percentages below
// are relative to this. Loop iterations below (approximately): // are relative to this. Loop iterations below (approximately):
// 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01% // 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01%
for vp/10 > vm/10 { for vp / 10 > vm / 10 {
last_removed_digit = byte(vr % 10) last_removed_digit = byte(vr % 10)
vr /= 10 vr /= 10
vp /= 10 vp /= 10
@ -306,7 +307,10 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
out = vr + bool_to_u32(vr == vm || last_removed_digit >= 5) out = vr + bool_to_u32(vr == vm || last_removed_digit >= 5)
} }
return Dec32{m: out e: e10 + removed} return Dec32{
m: out
e: e10 + removed
}
} }
//============================================================================= //=============================================================================
@ -317,52 +321,52 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
pub fn f32_to_str(f f32, n_digit int) string { pub fn f32_to_str(f f32, n_digit int) string {
mut u1 := Uf32{} mut u1 := Uf32{}
u1.f = f u1.f = f
u := unsafe {u1.u} u := unsafe { u1.u }
neg := (u >> (mantbits32 + expbits32)) != 0 neg := (u >> (strconv.mantbits32 + strconv.expbits32)) != 0
mant := u & ((u32(1) << mantbits32) - u32(1)) mant := u & ((u32(1) << strconv.mantbits32) - u32(1))
exp := (u >> mantbits32) & ((u32(1) << expbits32) - u32(1)) exp := (u >> strconv.mantbits32) & ((u32(1) << strconv.expbits32) - u32(1))
//println("${neg} ${mant} e ${exp-bias32}") // println("${neg} ${mant} e ${exp-bias32}")
// Exit early for easy cases. // Exit early for easy cases.
if (exp == maxexp32) || (exp == 0 && mant == 0) { if (exp == strconv.maxexp32) || (exp == 0 && mant == 0) {
return get_string_special(neg, exp == 0, mant == 0) return get_string_special(neg, exp == 0, mant == 0)
} }
mut d, ok := f32_to_decimal_exact_int(mant, exp) mut d, ok := f32_to_decimal_exact_int(mant, exp)
if !ok { if !ok {
//println("with exp form") // println("with exp form")
d = f32_to_decimal(mant, exp) d = f32_to_decimal(mant, exp)
} }
//println("${d.m} ${d.e}") // println("${d.m} ${d.e}")
return d.get_string_32(neg, n_digit,0) return d.get_string_32(neg, n_digit, 0)
} }
// f32_to_str return a string in scientific notation with max n_digit after the dot // f32_to_str return a string in scientific notation with max n_digit after the dot
pub fn f32_to_str_pad(f f32, n_digit int) string { pub fn f32_to_str_pad(f f32, n_digit int) string {
mut u1 := Uf32{} mut u1 := Uf32{}
u1.f = f u1.f = f
u := unsafe {u1.u} u := unsafe { u1.u }
neg := (u >> (mantbits32 + expbits32)) != 0 neg := (u >> (strconv.mantbits32 + strconv.expbits32)) != 0
mant := u & ((u32(1) << mantbits32) - u32(1)) mant := u & ((u32(1) << strconv.mantbits32) - u32(1))
exp := (u >> mantbits32) & ((u32(1) << expbits32) - u32(1)) exp := (u >> strconv.mantbits32) & ((u32(1) << strconv.expbits32) - u32(1))
//println("${neg} ${mant} e ${exp-bias32}") // println("${neg} ${mant} e ${exp-bias32}")
// Exit early for easy cases. // Exit early for easy cases.
if (exp == maxexp32) || (exp == 0 && mant == 0) { if (exp == strconv.maxexp32) || (exp == 0 && mant == 0) {
return get_string_special(neg, exp == 0, mant == 0) return get_string_special(neg, exp == 0, mant == 0)
} }
mut d, ok := f32_to_decimal_exact_int(mant, exp) mut d, ok := f32_to_decimal_exact_int(mant, exp)
if !ok { if !ok {
//println("with exp form") // println("with exp form")
d = f32_to_decimal(mant, exp) d = f32_to_decimal(mant, exp)
} }
//println("${d.m} ${d.e}") // println("${d.m} ${d.e}")
return d.get_string_32(neg, n_digit, n_digit) return d.get_string_32(neg, n_digit, n_digit)
} }

View File

@ -1,4 +1,5 @@
module strconv module strconv
/*============================================================================= /*=============================================================================
f64 to string f64 to string
@ -20,7 +21,7 @@ https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
=============================================================================*/ =============================================================================*/
// pow of ten table used by n_digit reduction // pow of ten table used by n_digit reduction
const( const (
ten_pow_table_64 = [ ten_pow_table_64 = [
u64(1), u64(1),
u64(10), u64(10),
@ -48,21 +49,21 @@ const(
//============================================================================= //=============================================================================
// Conversion Functions // Conversion Functions
//============================================================================= //=============================================================================
const( const (
mantbits64 = u32(52) mantbits64 = u32(52)
expbits64 = u32(11) expbits64 = u32(11)
bias64 = 1023 // f64 exponent bias bias64 = 1023 // f64 exponent bias
maxexp64 = 2047 maxexp64 = 2047
) )
[direct_array_access] [direct_array_access]
fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
mut n_digit := i_n_digit + 1 mut n_digit := i_n_digit + 1
pad_digit := i_pad_digit + 1 pad_digit := i_pad_digit + 1
mut out := d.m mut out := d.m
mut d_exp := d.e mut d_exp := d.e
// mut out_len := decimal_len_64(out) // mut out_len := decimal_len_64(out)
mut out_len := dec_digits(out) mut out_len := dec_digits(out)
out_len_original := out_len out_len_original := out_len
mut fw_zeros := 0 mut fw_zeros := 0
@ -70,7 +71,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
fw_zeros = pad_digit - out_len fw_zeros = pad_digit - out_len
} }
mut buf := []byte{len:(out_len + 6 + 1 +1 + fw_zeros)} // sign + mant_len + . + e + e_sign + exp_len(2) + \0} mut buf := []byte{len: (out_len + 6 + 1 + 1 + fw_zeros)} // sign + mant_len + . + e + e_sign + exp_len(2) + \0}
mut i := 0 mut i := 0
if neg { if neg {
@ -85,19 +86,19 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
// rounding last used digit // rounding last used digit
if n_digit < out_len { if n_digit < out_len {
//println("out:[$out]") // println("out:[$out]")
out += ten_pow_table_64[out_len - n_digit - 1] * 5 // round to up out += strconv.ten_pow_table_64[out_len - n_digit - 1] * 5 // round to up
out /= ten_pow_table_64[out_len - n_digit] out /= strconv.ten_pow_table_64[out_len - n_digit]
//println("out1:[$out] ${d.m / ten_pow_table_64[out_len - n_digit ]}") // println("out1:[$out] ${d.m / ten_pow_table_64[out_len - n_digit ]}")
if d.m / ten_pow_table_64[out_len - n_digit] < out { if d.m / strconv.ten_pow_table_64[out_len - n_digit] < out {
d_exp++ d_exp++
n_digit++ n_digit++
} }
//println("cmp: ${d.m/ten_pow_table_64[out_len - n_digit ]} ${out/ten_pow_table_64[out_len - n_digit ]}") // println("cmp: ${d.m/ten_pow_table_64[out_len - n_digit ]} ${out/ten_pow_table_64[out_len - n_digit ]}")
out_len = n_digit out_len = n_digit
//println("orig: ${out_len_original} new len: ${out_len} out:[$out]") // println("orig: ${out_len_original} new len: ${out_len} out:[$out]")
} }
y := i + out_len y := i + out_len
@ -112,8 +113,8 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
// no decimal digits needed, end here // no decimal digits needed, end here
if i_n_digit == 0 { if i_n_digit == 0 {
unsafe { unsafe {
buf[i]=0 buf[i] = 0
return tos(byteptr(&buf[0]), i) return tos(&byte(&buf[0]), i)
} }
} }
@ -123,7 +124,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
i++ i++
} }
if y-x >= 0 { if y - x >= 0 {
buf[y - x] = `0` + byte(out % 10) buf[y - x] = `0` + byte(out % 10)
i++ i++
} }
@ -134,16 +135,16 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
fw_zeros-- fw_zeros--
} }
buf[i]=`e` buf[i] = `e`
i++ i++
mut exp := d_exp + out_len_original - 1 mut exp := d_exp + out_len_original - 1
if exp < 0 { if exp < 0 {
buf[i]=`-` buf[i] = `-`
i++ i++
exp = -exp exp = -exp
} else { } else {
buf[i]=`+` buf[i] = `+`
i++ i++
} }
@ -153,29 +154,29 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
d1 := exp % 10 d1 := exp % 10
d0 := exp / 10 d0 := exp / 10
if d0 > 0 { if d0 > 0 {
buf[i]=`0` + byte(d0) buf[i] = `0` + byte(d0)
i++ i++
} }
buf[i]=`0` + byte(d1) buf[i] = `0` + byte(d1)
i++ i++
buf[i]=`0` + byte(d2) buf[i] = `0` + byte(d2)
i++ i++
buf[i]=0 buf[i] = 0
return unsafe { return unsafe {
tos(byteptr(&buf[0]), i) tos(&byte(&buf[0]), i)
} }
} }
fn f64_to_decimal_exact_int(i_mant u64, exp u64) (Dec64, bool) { fn f64_to_decimal_exact_int(i_mant u64, exp u64) (Dec64, bool) {
mut d := Dec64{} mut d := Dec64{}
e := exp - bias64 e := exp - strconv.bias64
if e > mantbits64 { if e > strconv.mantbits64 {
return d, false return d, false
} }
shift := mantbits64 - e shift := strconv.mantbits64 - e
mant := i_mant | u64(0x0010_0000_0000_0000) // implicit 1 mant := i_mant | u64(0x0010_0000_0000_0000) // implicit 1
//mant := i_mant | (1 << mantbits64) // implicit 1 // mant := i_mant | (1 << mantbits64) // implicit 1
d.m = mant >> shift d.m = mant >> shift
if (d.m << shift) != mant { if (d.m << shift) != mant {
return d, false return d, false
@ -194,24 +195,24 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
if exp == 0 { if exp == 0 {
// We subtract 2 so that the bounds computation has // We subtract 2 so that the bounds computation has
// 2 additional bits. // 2 additional bits.
e2 = 1 - bias64 - int(mantbits64) - 2 e2 = 1 - strconv.bias64 - int(strconv.mantbits64) - 2
m2 = mant m2 = mant
} else { } else {
e2 = int(exp) - bias64 - int(mantbits64) - 2 e2 = int(exp) - strconv.bias64 - int(strconv.mantbits64) - 2
m2 = (u64(1) << mantbits64) | mant m2 = (u64(1) << strconv.mantbits64) | mant
} }
even := (m2 & 1) == 0 even := (m2 & 1) == 0
accept_bounds := even accept_bounds := even
// Step 2: Determine the interval of valid decimal representations. // Step 2: Determine the interval of valid decimal representations.
mv := u64(4 * m2) mv := u64(4 * m2)
mm_shift := bool_to_u64(mant != 0 || exp <= 1) mm_shift := bool_to_u64(mant != 0 || exp <= 1)
// Step 3: Convert to a decimal power base uing 128-bit arithmetic. // Step 3: Convert to a decimal power base uing 128-bit arithmetic.
mut vr := u64(0) mut vr := u64(0)
mut vp := u64(0) mut vp := u64(0)
mut vm := u64(0) mut vm := u64(0)
mut e10 := 0 mut e10 := 0
mut vm_is_trailing_zeros := false mut vm_is_trailing_zeros := false
mut vr_is_trailing_zeros := false mut vr_is_trailing_zeros := false
@ -223,8 +224,8 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
i := -e2 + int(q) + k i := -e2 + int(q) + k
mul := pow5_inv_split_64[q] mul := pow5_inv_split_64[q]
vr = mul_shift_64(u64(4) * m2 , mul, i) vr = mul_shift_64(u64(4) * m2, mul, i)
vp = mul_shift_64(u64(4) * m2 + u64(2) , mul, i) vp = mul_shift_64(u64(4) * m2 + u64(2), mul, i)
vm = mul_shift_64(u64(4) * m2 - u64(1) - mm_shift, mul, i) vm = mul_shift_64(u64(4) * m2 - u64(1) - mm_shift, mul, i)
if q <= 21 { if q <= 21 {
// This should use q <= 22, but I think 21 is also safe. // This should use q <= 22, but I think 21 is also safe.
@ -237,7 +238,8 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
// Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q // Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q
// <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q // <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q
// <=> true && pow5Factor64(mm) >= q, since e2 >= q. // <=> true && pow5Factor64(mm) >= q, since e2 >= q.
vm_is_trailing_zeros = multiple_of_power_of_five_64(mv - 1 - mm_shift, q) vm_is_trailing_zeros = multiple_of_power_of_five_64(mv - 1 - mm_shift,
q)
} else if multiple_of_power_of_five_64(mv + 2, q) { } else if multiple_of_power_of_five_64(mv + 2, q) {
vp-- vp--
} }
@ -250,8 +252,8 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
k := pow5_bits(i) - pow5_num_bits_64 k := pow5_bits(i) - pow5_num_bits_64
j := int(q) - k j := int(q) - k
mul := pow5_split_64[i] mul := pow5_split_64[i]
vr = mul_shift_64(u64(4) * m2 , mul, j) vr = mul_shift_64(u64(4) * m2, mul, j)
vp = mul_shift_64(u64(4) * m2 + u64(2) , mul, j) vp = mul_shift_64(u64(4) * m2 + u64(2), mul, j)
vm = mul_shift_64(u64(4) * m2 - u64(1) - mm_shift, mul, j) vm = mul_shift_64(u64(4) * m2 - u64(1) - mm_shift, mul, j)
if q <= 1 { if q <= 1 {
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
@ -276,9 +278,9 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
// Step 4: Find the shortest decimal representation // Step 4: Find the shortest decimal representation
// in the interval of valid representations. // in the interval of valid representations.
mut removed := 0 mut removed := 0
mut last_removed_digit := byte(0) mut last_removed_digit := byte(0)
mut out := u64(0) mut out := u64(0)
// On average, we remove ~2 digits. // On average, we remove ~2 digits.
if vm_is_trailing_zeros || vr_is_trailing_zeros { if vm_is_trailing_zeros || vr_is_trailing_zeros {
// General case, which happens rarely (~0.7%). // General case, which happens rarely (~0.7%).
@ -355,7 +357,10 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
out = vr + bool_to_u64(vr == vm || round_up) out = vr + bool_to_u64(vr == vm || round_up)
} }
return Dec64{m: out, e: e10 + removed} return Dec64{
m: out
e: e10 + removed
}
} }
//============================================================================= //=============================================================================
@ -366,24 +371,24 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
pub fn f64_to_str(f f64, n_digit int) string { pub fn f64_to_str(f f64, n_digit int) string {
mut u1 := Uf64{} mut u1 := Uf64{}
u1.f = f u1.f = f
u := unsafe {u1.u} u := unsafe { u1.u }
neg := (u >> (mantbits64 + expbits64)) != 0 neg := (u >> (strconv.mantbits64 + strconv.expbits64)) != 0
mant := u & ((u64(1) << mantbits64) - u64(1)) mant := u & ((u64(1) << strconv.mantbits64) - u64(1))
exp := (u >> mantbits64) & ((u64(1) << expbits64) - u64(1)) exp := (u >> strconv.mantbits64) & ((u64(1) << strconv.expbits64) - u64(1))
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}") // println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
// Exit early for easy cases. // Exit early for easy cases.
if (exp == maxexp64) || (exp == 0 && mant == 0) { if (exp == strconv.maxexp64) || (exp == 0 && mant == 0) {
return get_string_special(neg, exp == 0, mant == 0) return get_string_special(neg, exp == 0, mant == 0)
} }
mut d, ok := f64_to_decimal_exact_int(mant, exp) mut d, ok := f64_to_decimal_exact_int(mant, exp)
if !ok { if !ok {
//println("to_decimal") // println("to_decimal")
d = f64_to_decimal(mant, exp) d = f64_to_decimal(mant, exp)
} }
//println("${d.m} ${d.e}") // println("${d.m} ${d.e}")
return d.get_string_64(neg, n_digit, 0) return d.get_string_64(neg, n_digit, 0)
} }
@ -391,23 +396,23 @@ pub fn f64_to_str(f f64, n_digit int) string {
pub fn f64_to_str_pad(f f64, n_digit int) string { pub fn f64_to_str_pad(f f64, n_digit int) string {
mut u1 := Uf64{} mut u1 := Uf64{}
u1.f = f u1.f = f
u := unsafe {u1.u} u := unsafe { u1.u }
neg := (u >> (mantbits64 + expbits64)) != 0 neg := (u >> (strconv.mantbits64 + strconv.expbits64)) != 0
mant := u & ((u64(1) << mantbits64) - u64(1)) mant := u & ((u64(1) << strconv.mantbits64) - u64(1))
exp := (u >> mantbits64) & ((u64(1) << expbits64) - u64(1)) exp := (u >> strconv.mantbits64) & ((u64(1) << strconv.expbits64) - u64(1))
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}") // println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
// Exit early for easy cases. // Exit early for easy cases.
if (exp == maxexp64) || (exp == 0 && mant == 0) { if (exp == strconv.maxexp64) || (exp == 0 && mant == 0) {
return get_string_special(neg, exp == 0, mant == 0) return get_string_special(neg, exp == 0, mant == 0)
} }
mut d, ok := f64_to_decimal_exact_int(mant, exp) mut d, ok := f64_to_decimal_exact_int(mant, exp)
if !ok { if !ok {
//println("to_decimal") // println("to_decimal")
d = f64_to_decimal(mant, exp) d = f64_to_decimal(mant, exp)
} }
//println("DEBUG: ${d.m} ${d.e}") // println("DEBUG: ${d.m} ${d.e}")
return d.get_string_64(neg, n_digit, n_digit) return d.get_string_64(neg, n_digit, n_digit)
} }

View File

@ -1,7 +1,6 @@
module strconv module strconv
/* /*
printf/sprintf V implementation printf/sprintf V implementation
Copyright (c) 2020 Dario Deledda. All rights reserved. Copyright (c) 2020 Dario Deledda. All rights reserved.
@ -9,9 +8,7 @@ Use of this source code is governed by an MIT license
that can be found in the LICENSE file. that can be found in the LICENSE file.
This file contains the printf/sprintf functions This file contains the printf/sprintf functions
*/ */
import strings import strings
pub enum Align_text { pub enum Align_text {
@ -21,11 +18,9 @@ pub enum Align_text {
} }
/* /*
Float conversion utility Float conversion utility
*/ */
const( const (
// rounding value // rounding value
dec_round = [ dec_round = [
f64(0.5), f64(0.5),
@ -81,19 +76,17 @@ const(
// max float 1.797693134862315708145274237317043567981e+308 // max float 1.797693134862315708145274237317043567981e+308
/* /*
Single format functions
Single format functions
*/ */
pub struct BF_param { pub struct BF_param {
pub mut: pub mut:
pad_ch byte = byte(` `) // padding char pad_ch byte = byte(` `) // padding char
len0 int = -1 // default len for whole the number or string len0 int = -1 // default len for whole the number or string
len1 int = 6 // number of decimal digits, if needed len1 int = 6 // number of decimal digits, if needed
positive bool = true // mandatory: the sign of the number passed positive bool = true // mandatory: the sign of the number passed
sign_flag bool // flag for print sign as prefix in padding sign_flag bool // flag for print sign as prefix in padding
allign Align_text = .right // alignment of the string allign Align_text = .right // alignment of the string
rm_tail_zero bool // remove the tail zeros from floats rm_tail_zero bool // remove the tail zeros from floats
} }
pub fn format_str(s string, p BF_param) string { pub fn format_str(s string, p BF_param) string {
@ -106,13 +99,13 @@ pub fn format_str(s string, p BF_param) string {
} }
mut res := strings.new_builder(s.len + dif) mut res := strings.new_builder(s.len + dif)
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }

View File

@ -6,6 +6,7 @@ that can be found in the LICENSE file.
This file contains string interpolation V functions This file contains string interpolation V functions
=============================================================================*/ =============================================================================*/
module strconv module strconv
import strings import strings
// strings.Builder version of format_str // strings.Builder version of format_str
@ -21,13 +22,13 @@ pub fn format_str_sb(s string, p BF_param, mut sb strings.Builder) {
} }
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
sb.write_b(p.pad_ch) sb.write_b(p.pad_ch)
} }
} }
sb.write_string(s) sb.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
sb.write_b(p.pad_ch) sb.write_b(p.pad_ch)
} }
} }
@ -60,7 +61,7 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
} }
} }
// write the pad chars // write the pad chars
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
@ -103,10 +104,14 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
// calculate the digit_pairs start index // calculate the digit_pairs start index
d_i = (n - (n1 * 100)) << 1 d_i = (n - (n1 * 100)) << 1
n = n1 n = n1
unsafe{ buf[i] = digit_pairs.str[d_i] } unsafe {
buf[i] = strconv.digit_pairs.str[d_i]
}
i-- i--
d_i++ d_i++
unsafe{ buf[i] = digit_pairs.str[d_i] } unsafe {
buf[i] = strconv.digit_pairs.str[d_i]
}
i-- i--
} }
i++ i++
@ -114,8 +119,7 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
if d_i < 20 { if d_i < 20 {
i++ i++
} }
unsafe{ res.write_ptr(&buf[i],n_char) } unsafe { res.write_ptr(&buf[i], n_char) }
} else { } else {
// we have a zero no need of more code! // we have a zero no need of more code!
res.write_b(`0`) res.write_b(`0`)
@ -123,19 +127,16 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
//=========================================== //===========================================
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
return return
} }
[direct_array_access; manualfree]
[manualfree]
[direct_array_access]
pub fn f64_to_str_lnd1(f f64, dec_digit int) string { pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
unsafe{ unsafe {
// we add the rounding value // we add the rounding value
s := f64_to_str(f + dec_round[dec_digit], 18) s := f64_to_str(f + dec_round[dec_digit], 18)
// check for +inf -inf Nan // check for +inf -inf Nan
@ -144,13 +145,13 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
} }
m_sgn_flag := false m_sgn_flag := false
mut sgn := 1 mut sgn := 1
mut b := [26]byte{} mut b := [26]byte{}
mut d_pos := 1 mut d_pos := 1
mut i := 0 mut i := 0
mut i1 := 0 mut i1 := 0
mut exp := 0 mut exp := 0
mut exp_sgn := 1 mut exp_sgn := 1
mut dot_res_sp := -1 mut dot_res_sp := -1
@ -162,8 +163,7 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
} else if c == `+` { } else if c == `+` {
sgn = 1 sgn = 1
i++ i++
} } else if c >= `0` && c <= `9` {
else if c >= `0` && c <= `9` {
b[i1] = c b[i1] = c
i1++ i1++
i++ i++
@ -171,7 +171,7 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
if sgn > 0 { if sgn > 0 {
d_pos = i d_pos = i
} else { } else {
d_pos = i-1 d_pos = i - 1
} }
i++ i++
} else if c == `e` { } else if c == `e` {
@ -179,7 +179,7 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
break break
} else { } else {
s.free() s.free()
return "[Float conversion error!!]" return '[Float conversion error!!]'
} }
} }
b[i1] = 0 b[i1] = 0
@ -200,11 +200,11 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
} }
// allocate exp+32 chars for the return string // allocate exp+32 chars for the return string
//mut res := []byte{len:exp+32,init:`0`} // mut res := []byte{len:exp+32,init:`0`}
mut res := []byte{len: exp+32, init: 0} mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index mut r_i := 0 // result string buffer index
//println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}") // println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
// s no more needed // s no more needed
s.free() s.free()
@ -239,14 +239,14 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
r_i++ r_i++
exp-- exp--
} }
//println("exp: $exp $r_i $dot_res_sp") // println("exp: $exp $r_i $dot_res_sp")
} else { } else {
mut dot_p := true mut dot_p := true
for exp > 0 { for exp > 0 {
res[r_i] = `0` res[r_i] = `0`
r_i++ r_i++
exp-- exp--
if dot_p { if dot_p {
dot_res_sp = r_i dot_res_sp = r_i
res[r_i] = `.` res[r_i] = `.`
r_i++ r_i++
@ -267,13 +267,13 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
return tmp_res return tmp_res
} }
//println("r_i-d_pos: ${r_i - d_pos}") // println("r_i-d_pos: ${r_i - d_pos}")
if dot_res_sp >= 0 { if dot_res_sp >= 0 {
if (r_i - dot_res_sp) > dec_digit { if (r_i - dot_res_sp) > dec_digit {
r_i = dot_res_sp + dec_digit + 1 r_i = dot_res_sp + dec_digit + 1
} }
res[r_i] = 0 res[r_i] = 0
//println("result: [${tos(&res[0],r_i)}]") // println("result: [${tos(&res[0],r_i)}]")
tmp_res := tos(res.data, r_i).clone() tmp_res := tos(res.data, r_i).clone()
res.free() res.free()
return tmp_res return tmp_res
@ -293,19 +293,18 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
res.free() res.free()
return tmp_res return tmp_res
} }
} }
} }
// strings.Builder version of format_fl // strings.Builder version of format_fl
[manualfree] [manualfree]
pub fn format_fl(f f64, p BF_param) string { pub fn format_fl(f f64, p BF_param) string {
unsafe{ unsafe {
mut s := "" mut s := ''
//mut fs := "1.2343" // mut fs := "1.2343"
mut fs := f64_to_str_lnd1(if f >= 0.0 {f} else {-f}, p.len1) mut fs := f64_to_str_lnd1(if f >= 0.0 { f } else { -f }, p.len1)
//println("Dario") // println("Dario")
//println(fs) // println(fs)
// error!! // error!!
if fs[0] == `[` { if fs[0] == `[` {
@ -318,7 +317,7 @@ pub fn format_fl(f f64, p BF_param) string {
fs = remove_tail_zeros(fs) fs = remove_tail_zeros(fs)
tmp.free() tmp.free()
} }
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len })
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -338,7 +337,7 @@ pub fn format_fl(f f64, p BF_param) string {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
tmp := s tmp := s
s = "+" + fs s = '+' + fs
tmp.free() tmp.free()
} else { } else {
tmp := s tmp := s
@ -347,7 +346,7 @@ pub fn format_fl(f f64, p BF_param) string {
} }
} else { } else {
tmp := s tmp := s
s = "-" + fs s = '-' + fs
tmp.free() tmp.free()
} }
} }
@ -355,18 +354,17 @@ pub fn format_fl(f f64, p BF_param) string {
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
s.free() s.free()
fs.free() fs.free()
tmp_res := res.str() tmp_res := res.str()
@ -377,13 +375,13 @@ pub fn format_fl(f f64, p BF_param) string {
[manualfree] [manualfree]
pub fn format_es(f f64, p BF_param) string { pub fn format_es(f f64, p BF_param) string {
unsafe{ unsafe {
mut s := "" mut s := ''
mut fs := f64_to_str_pad(if f> 0 {f} else {-f},p.len1) mut fs := f64_to_str_pad(if f > 0 { f } else { -f }, p.len1)
if p.rm_tail_zero { if p.rm_tail_zero {
fs = remove_tail_zeros(fs) fs = remove_tail_zeros(fs)
} }
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len })
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -403,7 +401,7 @@ pub fn format_es(f f64, p BF_param) string {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
tmp := s tmp := s
s = "+" + fs s = '+' + fs
tmp.free() tmp.free()
} else { } else {
tmp := s tmp := s
@ -412,20 +410,20 @@ pub fn format_es(f f64, p BF_param) string {
} }
} else { } else {
tmp := s tmp := s
s = "-" + fs s = '-' + fs
tmp.free() tmp.free()
} }
} }
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
@ -439,19 +437,19 @@ pub fn format_es(f f64, p BF_param) string {
[direct_array_access] [direct_array_access]
pub fn remove_tail_zeros(s string) string { pub fn remove_tail_zeros(s string) string {
unsafe{ unsafe {
mut buf := malloc_noscan(s.len + 1) mut buf := malloc_noscan(s.len + 1)
mut i_d := 0 mut i_d := 0
mut i_s := 0 mut i_s := 0
// skip spaces // skip spaces
for i_s < s.len && s[i_s] !in [`-`,`+`] && (s[i_s] > `9` || s[i_s] < `0`) { for i_s < s.len && s[i_s] !in [`-`, `+`] && (s[i_s] > `9` || s[i_s] < `0`) {
buf[i_d] = s[i_s] buf[i_d] = s[i_s]
i_s++ i_s++
i_d++ i_d++
} }
// sign // sign
if i_s < s.len && s[i_s] in [`-`,`+`] { if i_s < s.len && s[i_s] in [`-`, `+`] {
buf[i_d] = s[i_s] buf[i_d] = s[i_s]
i_s++ i_s++
i_d++ i_d++

View File

@ -1,107 +1,107 @@
import strconv import strconv
fn test_format(){ fn test_format() {
mut temp_s := "" mut temp_s := ''
mut tmp_str:= "" mut tmp_str := ''
a0 := u32(10) a0 := u32(10)
b0 := 200 b0 := 200
c0 := byte(12) c0 := byte(12)
s0 := "ciAo" s0 := 'ciAo'
ch0 := `B` ch0 := `B`
f0 := 0.312345 f0 := 0.312345
f1 := 200000.0 f1 := 200000.0
f2 := -1234.300e6 f2 := -1234.300e6
f3 := 1234.300e-6 f3 := 1234.300e-6
sc0 := "ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]" sc0 := 'ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]'
temp_s = strconv.v_sprintf(sc0 ,a0 ,b0 ,c0 ,s0, b0 ,f0, f1, ch0) temp_s = strconv.v_sprintf(sc0, a0, b0, c0, s0, b0, f0, f1, ch0)
tmp_str = "ciao: [10 ] 200 12 [ ciAo] [000000C8] [0.3123 ] [200000.0000 ] [B]" tmp_str = 'ciao: [10 ] 200 12 [ ciAo] [000000C8] [0.3123 ] [200000.0000 ] [B]'
//C.printf(sc0.str,a0 ,b0 ,c0 ,s0.str ,b0 ,f0, f1, ch0) // C.printf(sc0.str,a0 ,b0 ,c0 ,s0.str ,b0 ,f0, f1, ch0)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
a := byte(12) a := byte(12)
b := i16(13) b := i16(13)
c := 14 c := 14
d := i64(15) d := i64(15)
sc1 := "==>%hhd %hd %d %ld" sc1 := '==>%hhd %hd %d %ld'
temp_s = strconv.v_sprintf(sc1, a ,b ,c, d) temp_s = strconv.v_sprintf(sc1, a, b, c, d)
tmp_str = "==>12 13 14 15" tmp_str = '==>12 13 14 15'
//C.printf(sc1.str, a ,b ,c, d) // C.printf(sc1.str, a ,b ,c, d)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
a1 := byte(0xff) a1 := byte(0xff)
b1 := i16(0xffff) b1 := i16(0xffff)
c1 := u32(0xffff_ffff) c1 := u32(0xffff_ffff)
d1 := u64(-1) d1 := u64(-1)
sc2 := "%hhu %hu %u %lu" sc2 := '%hhu %hu %u %lu'
temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1) temp_s = strconv.v_sprintf(sc2, a1, b1, c1, d1)
tmp_str = "255 65535 4294967295 18446744073709551615" tmp_str = '255 65535 4294967295 18446744073709551615'
//C.printf(sc2.str, a1 ,b1 ,c1, d1) // C.printf(sc2.str, a1 ,b1 ,c1, d1)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
sc3 := "%hhx %hx %x %lx" sc3 := '%hhx %hx %x %lx'
temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1) temp_s = strconv.v_sprintf(sc3, a1, b1, c1, d1)
tmp_str = "ff ffff ffffffff ffffffffffffffff" tmp_str = 'ff ffff ffffffff ffffffffffffffff'
//C.printf(sc3.str, a1 ,b1 ,c1, d1) // C.printf(sc3.str, a1 ,b1 ,c1, d1)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]" sc4 := '[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]'
temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3) temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3)
tmp_str = "[3.123e-01 ] [ 2.000e+05] [2.000e+05 ] [2.000E+05 ] [-1.234e+09 ] [1.234e-03 ]" tmp_str = '[3.123e-01 ] [ 2.000e+05] [2.000e+05 ] [2.000E+05 ] [-1.234e+09 ] [1.234e-03 ]'
//C.printf(sc4.str, f0, f1, f1, f1, f2, f3) // C.printf(sc4.str, f0, f1, f1, f1, f2, f3)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
sc5 := "[%.3f] [%0.3f] [%0.3F] [%0.3f] [%0.3F]" sc5 := '[%.3f] [%0.3f] [%0.3F] [%0.3f] [%0.3F]'
temp_s = strconv.v_sprintf(sc5, f0, f1, f1, f2, f3) temp_s = strconv.v_sprintf(sc5, f0, f1, f1, f2, f3)
tmp_str = "[0.312] [200000.000] [200000.000] [-1234300000.000] [0.001]" tmp_str = '[0.312] [200000.000] [200000.000] [-1234300000.000] [0.001]'
//C.printf(sc5.str, f0, f1, f1, f2, f3, f3) // C.printf(sc5.str, f0, f1, f1, f2, f3, f3)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
ml := 3 ml := 3
sc6 := "%.*s [%05hhX]" sc6 := '%.*s [%05hhX]'
temp_s = strconv.v_sprintf(sc6, ml, s0 , a) temp_s = strconv.v_sprintf(sc6, ml, s0, a)
tmp_str = "ciA [0000C]" tmp_str = 'ciA [0000C]'
//C.printf(sc6.str, ml, s0.str, a) // C.printf(sc6.str, ml, s0.str, a)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
a2 := 125 a2 := 125
sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]" sc7 := '[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]'
temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2) temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2)
tmp_str = "[ 7d] [ 7D] [7d ] [7D ] [00000007d] [00000007D]" tmp_str = '[ 7d] [ 7D] [7d ] [7D ] [00000007d] [00000007D]'
//C.printf(sc7.str, a2, a2, a2, a2, a2, a2) // C.printf(sc7.str, a2, a2, a2, a2, a2, a2)
//println("\n$temp_s") // println("\n$temp_s")
assert tmp_str == temp_s assert tmp_str == temp_s
g_test := [ g_test := [
"[ -1e-07][ -1E-07]|", '[ -1e-07][ -1E-07]|',
"[ -1e-06][ -1E-06]|", '[ -1e-06][ -1E-06]|',
"[ -1e-05][ -1E-05]|", '[ -1e-05][ -1E-05]|',
"[ -0.0001][ -0.0001]|", '[ -0.0001][ -0.0001]|',
"[ -0.001][ -0.001]|", '[ -0.001][ -0.001]|',
"[ -0.01][ -0.01]|", '[ -0.01][ -0.01]|',
"[ -0.1][ -0.1]|", '[ -0.1][ -0.1]|',
"[ -1][ -1]|", '[ -1][ -1]|',
"[ -10][ -10]|", '[ -10][ -10]|',
"[ -100][ -100]|", '[ -100][ -100]|',
"[ -1000][ -1000]|", '[ -1000][ -1000]|',
"[ -10000][ -10000]|" '[ -10000][ -10000]|',
] ]
mut ft := -1e-7 mut ft := -1e-7
mut x := 0 mut x := 0
mut cnt:= 0 mut cnt := 0
sc8 := "[%20g][%20G]|" sc8 := '[%20g][%20G]|'
for x < 12 { for x < 12 {
temp_s = strconv.v_sprintf(sc8, ft, ft) temp_s = strconv.v_sprintf(sc8, ft, ft)
//C.printf(sc8.str, ft, ft) // C.printf(sc8.str, ft, ft)
//println("\n$temp_s") // println("\n$temp_s")
assert temp_s == g_test[cnt] assert temp_s == g_test[cnt]
ft = ft * 10.0 ft = ft * 10.0
x++ x++

View File

@ -1,7 +1,6 @@
module strconv module strconv
/* /*
f32/f64 ftoa functions f32/f64 ftoa functions
Copyright (c) 2019-2021 Dario Deledda. All rights reserved. Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
@ -17,12 +16,11 @@ Pages 270282 https://doi.org/10.1145/3192366.3192369
inspired by the Go version here: inspired by the Go version here:
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*/ */
[inline] [inline]
pub fn ftoa_64(f f64) string { pub fn ftoa_64(f f64) string {
return f64_to_str(f,17) return f64_to_str(f, 17)
} }
[inline] [inline]
@ -32,7 +30,7 @@ pub fn ftoa_long_64(f f64) string {
[inline] [inline]
pub fn ftoa_32(f f32) string { pub fn ftoa_32(f f32) string {
return f32_to_str(f,8) return f32_to_str(f, 8)
} }
[inline] [inline]

View File

@ -6,7 +6,7 @@ const base_digits = '0123456789abcdefghijklmnopqrstuvwxyz'
// for digit values > 10, this function uses the small latin leters a-z. // for digit values > 10, this function uses the small latin leters a-z.
[manualfree] [manualfree]
pub fn format_int(n i64, radix int) string { pub fn format_int(n i64, radix int) string {
unsafe{ unsafe {
if radix < 2 || radix > 36 { if radix < 2 || radix > 36 {
panic('invalid radix: $radix . It should be => 2 and <= 36') panic('invalid radix: $radix . It should be => 2 and <= 36')
} }
@ -22,11 +22,11 @@ pub fn format_int(n i64, radix int) string {
mut res := '' mut res := ''
for n_copy != 0 { for n_copy != 0 {
tmp_0 := res tmp_0 := res
tmp_1 := base_digits[n_copy % radix].ascii_str() tmp_1 := strconv.base_digits[n_copy % radix].ascii_str()
res = tmp_1 + res res = tmp_1 + res
tmp_0.free() tmp_0.free()
tmp_1.free() tmp_1.free()
//res = base_digits[n_copy % radix].ascii_str() + res // res = base_digits[n_copy % radix].ascii_str() + res
n_copy /= radix n_copy /= radix
} }
return '$sign$res' return '$sign$res'
@ -37,7 +37,7 @@ pub fn format_int(n i64, radix int) string {
// for digit values > 10, this function uses the small latin leters a-z. // for digit values > 10, this function uses the small latin leters a-z.
[manualfree] [manualfree]
pub fn format_uint(n u64, radix int) string { pub fn format_uint(n u64, radix int) string {
unsafe{ unsafe {
if radix < 2 || radix > 36 { if radix < 2 || radix > 36 {
panic('invalid radix: $radix . It should be => 2 and <= 36') panic('invalid radix: $radix . It should be => 2 and <= 36')
} }
@ -49,11 +49,11 @@ pub fn format_uint(n u64, radix int) string {
uradix := u64(radix) uradix := u64(radix)
for n_copy != 0 { for n_copy != 0 {
tmp_0 := res tmp_0 := res
tmp_1 := base_digits[n_copy % uradix].ascii_str() tmp_1 := strconv.base_digits[n_copy % uradix].ascii_str()
res = tmp_1 + res res = tmp_1 + res
tmp_0.free() tmp_0.free()
tmp_1.free() tmp_1.free()
//res = base_digits[n_copy % uradix].ascii_str() + res // res = base_digits[n_copy % uradix].ascii_str() + res
n_copy /= uradix n_copy /= uradix
} }
return res return res

View File

@ -32,8 +32,7 @@ fn test_format_uint() {
assert strconv.format_int(255, 8) == '377' assert strconv.format_int(255, 8) == '377'
assert strconv.format_int(255, 10) == '255' assert strconv.format_int(255, 10) == '255'
assert strconv.format_int(255, 16) == 'ff' assert strconv.format_int(255, 16) == 'ff'
assert strconv.format_uint(18446744073709551615, 2) == assert strconv.format_uint(18446744073709551615, 2) == '1111111111111111111111111111111111111111111111111111111111111111'
'1111111111111111111111111111111111111111111111111111111111111111'
assert strconv.format_uint(18446744073709551615, 16) == 'ffffffffffffffff' assert strconv.format_uint(18446744073709551615, 16) == 'ffffffffffffffff'
assert strconv.parse_int('baobab', 36, 64) == 683058467 assert strconv.parse_int('baobab', 36, 64) == 683058467
assert strconv.format_uint(683058467, 36) == 'baobab' assert strconv.format_uint(683058467, 36) == 'baobab'

View File

@ -4,8 +4,8 @@ module strconv
pub struct PrepNumber { pub struct PrepNumber {
pub mut: pub mut:
negative bool // 0 if positive number, 1 if negative negative bool // 0 if positive number, 1 if negative
exponent int // power of 10 exponent exponent int // power of 10 exponent
mantissa u64 // integer mantissa mantissa u64 // integer mantissa
} }
// dec32 is a floating decimal type representing m * 10^e. // dec32 is a floating decimal type representing m * 10^e.

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
module strconv module strconv
/* /*
f32/f64 to string utilities f32/f64 to string utilities
Copyright (c) 2019-2021 Dario Deledda. All rights reserved. Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
@ -17,17 +16,13 @@ Pages 270282 https://doi.org/10.1145/3192366.3192369
inspired by the Go version here: inspired by the Go version here:
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*/ */
import math.bits import math.bits
//import math // import math
/* /*
General Utilities General Utilities
*/ */
fn assert1(t bool, msg string) { fn assert1(t bool, msg string) {
if !t { if !t {
@ -61,25 +56,23 @@ fn bool_to_u64(b bool) u64 {
fn get_string_special(neg bool, expZero bool, mantZero bool) string { fn get_string_special(neg bool, expZero bool, mantZero bool) string {
if !mantZero { if !mantZero {
return "nan" return 'nan'
} }
if !expZero { if !expZero {
if neg { if neg {
return "-inf" return '-inf'
} else { } else {
return "+inf" return '+inf'
} }
} }
if neg { if neg {
return "-0e+00" return '-0e+00'
} }
return "0e+00" return '0e+00'
} }
/* /*
32 bit functions
32 bit functions
*/ */
// decimal_len_32 return the number of decimal digits of the input // decimal_len_32 return the number of decimal digits of the input
[deprecated] [deprecated]
@ -87,26 +80,35 @@ pub fn decimal_len_32(u u32) int {
// Function precondition: u is not a 10-digit number. // Function precondition: u is not a 10-digit number.
// (9 digits are sufficient for round-tripping.) // (9 digits are sufficient for round-tripping.)
// This benchmarked faster than the log2 approach used for u64. // This benchmarked faster than the log2 approach used for u64.
assert1(u < 1000000000, "too big") assert1(u < 1000000000, 'too big')
if u >= 100000000 { return 9 } if u >= 100000000 {
else if u >= 10000000 { return 8 } return 9
else if u >= 1000000 { return 7 } } else if u >= 10000000 {
else if u >= 100000 { return 6 } return 8
else if u >= 10000 { return 5 } } else if u >= 1000000 {
else if u >= 1000 { return 4 } return 7
else if u >= 100 { return 3 } } else if u >= 100000 {
else if u >= 10 { return 2 } return 6
} else if u >= 10000 {
return 5
} else if u >= 1000 {
return 4
} else if u >= 100 {
return 3
} else if u >= 10 {
return 2
}
return 1 return 1
} }
fn mul_shift_32(m u32, mul u64, ishift int) u32 { fn mul_shift_32(m u32, mul u64, ishift int) u32 {
// QTODO // QTODO
//assert ishift > 32 // assert ishift > 32
hi, lo := bits.mul_64(u64(m), mul) hi, lo := bits.mul_64(u64(m), mul)
shifted_sum := (lo >> u64(ishift)) + (hi << u64(64-ishift)) shifted_sum := (lo >> u64(ishift)) + (hi << u64(64 - ishift))
assert1(shifted_sum <= 2147483647, "shiftedSum <= math.max_u32") assert1(shifted_sum <= 2147483647, 'shiftedSum <= math.max_u32')
return u32(shifted_sum) return u32(shifted_sum)
} }
@ -120,9 +122,9 @@ fn mul_pow5_div_pow2(m u32, i u32, j int) u32 {
fn pow5_factor_32(i_v u32) u32 { fn pow5_factor_32(i_v u32) u32 {
mut v := i_v mut v := i_v
for n := u32(0); ; n++ { for n := u32(0); true; n++ {
q := v/5 q := v / 5
r := v%5 r := v % 5
if r != 0 { if r != 0 {
return n return n
} }
@ -145,8 +147,8 @@ fn multiple_of_power_of_two_32(v u32, p u32) bool {
fn log10_pow2(e int) u32 { fn log10_pow2(e int) u32 {
// The first value this approximation fails for is 2^1651 // The first value this approximation fails for is 2^1651
// which is just greater than 10^297. // which is just greater than 10^297.
assert1(e >= 0, "e >= 0") assert1(e >= 0, 'e >= 0')
assert1(e <= 1650, "e <= 1650") assert1(e <= 1650, 'e <= 1650')
return (u32(e) * 78913) >> 18 return (u32(e) * 78913) >> 18
} }
@ -154,8 +156,8 @@ fn log10_pow2(e int) u32 {
fn log10_pow5(e int) u32 { fn log10_pow5(e int) u32 {
// The first value this approximation fails for is 5^2621 // The first value this approximation fails for is 5^2621
// which is just greater than 10^1832. // which is just greater than 10^1832.
assert1(e >= 0, "e >= 0") assert1(e >= 0, 'e >= 0')
assert1(e <= 2620, "e <= 2620") assert1(e <= 2620, 'e <= 2620')
return (u32(e) * 732923) >> 20 return (u32(e) * 732923) >> 20
} }
@ -164,18 +166,17 @@ fn pow5_bits(e int) int {
// This approximation works up to the point that the multiplication // This approximation works up to the point that the multiplication
// overflows at e = 3529. If the multiplication were done in 64 bits, // overflows at e = 3529. If the multiplication were done in 64 bits,
// it would fail at 5^4004 which is just greater than 2^9297. // it would fail at 5^4004 which is just greater than 2^9297.
assert1(e >= 0, "e >= 0") assert1(e >= 0, 'e >= 0')
assert1(e <= 3528, "e <= 3528") assert1(e <= 3528, 'e <= 3528')
return int( ((u32(e)*1217359)>>19) + 1) return int(((u32(e) * 1217359) >> 19) + 1)
} }
/* /*
64 bit functions
64 bit functions
*/ */
[deprecated]
// decimal_len_64 return the number of decimal digits of the input // decimal_len_64 return the number of decimal digits of the input
[deprecated]
pub fn decimal_len_64(u u64) int { pub fn decimal_len_64(u u64) int {
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
log2 := 64 - bits.leading_zeros_64(u) - 1 log2 := 64 - bits.leading_zeros_64(u) - 1
@ -190,25 +191,28 @@ fn shift_right_128(v Uint128, shift int) u64 {
// (It is in the range [2, 59].) // (It is in the range [2, 59].)
// Check this here in case a future change requires larger shift // Check this here in case a future change requires larger shift
// values. In this case this function needs to be adjusted. // values. In this case this function needs to be adjusted.
assert1(shift < 64, "shift < 64") assert1(shift < 64, 'shift < 64')
return (v.hi << u64(64 - shift)) | (v.lo >> u32(shift)) return (v.hi << u64(64 - shift)) | (v.lo >> u32(shift))
} }
fn mul_shift_64(m u64, mul Uint128, shift int) u64 { fn mul_shift_64(m u64, mul Uint128, shift int) u64 {
hihi, hilo := bits.mul_64(m, mul.hi) hihi, hilo := bits.mul_64(m, mul.hi)
lohi, _ := bits.mul_64(m, mul.lo) lohi, _ := bits.mul_64(m, mul.lo)
mut sum := Uint128{lo: lohi + hilo,hi: hihi} mut sum := Uint128{
lo: lohi + hilo
hi: hihi
}
if sum.lo < lohi { if sum.lo < lohi {
sum.hi++ // overflow sum.hi++ // overflow
} }
return shift_right_128(sum, shift-64) return shift_right_128(sum, shift - 64)
} }
fn pow5_factor_64(v_i u64) u32 { fn pow5_factor_64(v_i u64) u32 {
mut v := v_i mut v := v_i
for n := u32(0); ; n++ { for n := u32(0); true; n++ {
q := v/5 q := v / 5
r := v%5 r := v % 5
if r != 0 { if r != 0 {
return n return n
} }
@ -226,46 +230,43 @@ fn multiple_of_power_of_two_64(v u64, p u32) bool {
} }
/* /*
f64 to string with string format f64 to string with string format
*/ */
// TODO: Investigate precision issues // TODO: Investigate precision issues
// f32_to_str_l return a string with the f32 converted in a string in decimal notation // f32_to_str_l return a string with the f32 converted in a string in decimal notation
[manualfree] [manualfree]
pub fn f32_to_str_l(f f32) string { pub fn f32_to_str_l(f f32) string {
s := f32_to_str(f,6) s := f32_to_str(f, 6)
res := fxx_to_str_l_parse(s) res := fxx_to_str_l_parse(s)
unsafe{s.free()} unsafe { s.free() }
return res return res
} }
[manualfree] [manualfree]
pub fn f32_to_str_l_no_dot(f f32) string { pub fn f32_to_str_l_no_dot(f f32) string {
s := f32_to_str(f,6) s := f32_to_str(f, 6)
res := fxx_to_str_l_parse_no_dot(s) res := fxx_to_str_l_parse_no_dot(s)
unsafe{s.free()} unsafe { s.free() }
return res return res
} }
[manualfree] [manualfree]
pub fn f64_to_str_l(f f64) string { pub fn f64_to_str_l(f f64) string {
s := f64_to_str(f,18) s := f64_to_str(f, 18)
res := fxx_to_str_l_parse(s) res := fxx_to_str_l_parse(s)
unsafe{s.free()} unsafe { s.free() }
return res return res
} }
[manualfree] [manualfree]
pub fn f64_to_str_l_no_dot(f f64) string { pub fn f64_to_str_l_no_dot(f f64) string {
s := f64_to_str(f,18) s := f64_to_str(f, 18)
res := fxx_to_str_l_parse_no_dot(s) res := fxx_to_str_l_parse_no_dot(s)
unsafe{s.free()} unsafe { s.free() }
return res return res
} }
// f64_to_str_l return a string with the f64 converted in a string in decimal notation // f64_to_str_l return a string with the f64 converted in a string in decimal notation
[manualfree] [manualfree]
pub fn fxx_to_str_l_parse(s string) string { pub fn fxx_to_str_l_parse(s string) string {
@ -275,13 +276,13 @@ pub fn fxx_to_str_l_parse(s string) string {
} }
m_sgn_flag := false m_sgn_flag := false
mut sgn := 1 mut sgn := 1
mut b := [26]byte{} mut b := [26]byte{}
mut d_pos := 1 mut d_pos := 1
mut i := 0 mut i := 0
mut i1 := 0 mut i1 := 0
mut exp := 0 mut exp := 0
mut exp_sgn := 1 mut exp_sgn := 1
// get sign and decimal parts // get sign and decimal parts
for c in s { for c in s {
@ -291,8 +292,7 @@ pub fn fxx_to_str_l_parse(s string) string {
} else if c == `+` { } else if c == `+` {
sgn = 1 sgn = 1
i++ i++
} } else if c >= `0` && c <= `9` {
else if c >= `0` && c <= `9` {
b[i1] = c b[i1] = c
i1++ i1++
i++ i++
@ -300,14 +300,14 @@ pub fn fxx_to_str_l_parse(s string) string {
if sgn > 0 { if sgn > 0 {
d_pos = i d_pos = i
} else { } else {
d_pos = i-1 d_pos = i - 1
} }
i++ i++
} else if c == `e` { } else if c == `e` {
i++ i++
break break
} else { } else {
return "Float conversion error!!" return 'Float conversion error!!'
} }
} }
b[i1] = 0 b[i1] = 0
@ -323,15 +323,15 @@ pub fn fxx_to_str_l_parse(s string) string {
mut c := i mut c := i
for c < s.len { for c < s.len {
exp = exp * 10 + int(s[c]-`0`) exp = exp * 10 + int(s[c] - `0`)
c++ c++
} }
// allocate exp+32 chars for the return string // allocate exp+32 chars for the return string
mut res := []byte{len: exp+32, init: 0} mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index mut r_i := 0 // result string buffer index
//println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}") // println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 { if sgn == 1 {
if m_sgn_flag { if m_sgn_flag {
@ -368,7 +368,7 @@ pub fn fxx_to_str_l_parse(s string) string {
res[r_i] = `0` res[r_i] = `0`
r_i++ r_i++
exp-- exp--
if dot_p { if dot_p {
res[r_i] = `.` res[r_i] = `.`
r_i++ r_i++
dot_p = false dot_p = false
@ -380,14 +380,14 @@ pub fn fxx_to_str_l_parse(s string) string {
i++ i++
} }
} }
/* /*
// remove the dot form the numbers like 2. // remove the dot form the numbers like 2.
if r_i > 1 && res[r_i-1] == `.` { if r_i > 1 && res[r_i-1] == `.` {
r_i-- r_i--
} }
*/ */
res[r_i] = 0 res[r_i] = 0
return unsafe { tos(res.data,r_i) } return unsafe { tos(res.data, r_i) }
} }
// f64_to_str_l return a string with the f64 converted in a string in decimal notation // f64_to_str_l return a string with the f64 converted in a string in decimal notation
@ -399,13 +399,13 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
} }
m_sgn_flag := false m_sgn_flag := false
mut sgn := 1 mut sgn := 1
mut b := [26]byte{} mut b := [26]byte{}
mut d_pos := 1 mut d_pos := 1
mut i := 0 mut i := 0
mut i1 := 0 mut i1 := 0
mut exp := 0 mut exp := 0
mut exp_sgn := 1 mut exp_sgn := 1
// get sign and decimal parts // get sign and decimal parts
for c in s { for c in s {
@ -415,8 +415,7 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
} else if c == `+` { } else if c == `+` {
sgn = 1 sgn = 1
i++ i++
} } else if c >= `0` && c <= `9` {
else if c >= `0` && c <= `9` {
b[i1] = c b[i1] = c
i1++ i1++
i++ i++
@ -424,14 +423,14 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
if sgn > 0 { if sgn > 0 {
d_pos = i d_pos = i
} else { } else {
d_pos = i-1 d_pos = i - 1
} }
i++ i++
} else if c == `e` { } else if c == `e` {
i++ i++
break break
} else { } else {
return "Float conversion error!!" return 'Float conversion error!!'
} }
} }
b[i1] = 0 b[i1] = 0
@ -447,15 +446,15 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
mut c := i mut c := i
for c < s.len { for c < s.len {
exp = exp * 10 + int(s[c]-`0`) exp = exp * 10 + int(s[c] - `0`)
c++ c++
} }
// allocate exp+32 chars for the return string // allocate exp+32 chars for the return string
mut res := []byte{len: exp+32, init: 0} mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index mut r_i := 0 // result string buffer index
//println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}") // println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 { if sgn == 1 {
if m_sgn_flag { if m_sgn_flag {
@ -492,7 +491,7 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
res[r_i] = `0` res[r_i] = `0`
r_i++ r_i++
exp-- exp--
if dot_p { if dot_p {
res[r_i] = `.` res[r_i] = `.`
r_i++ r_i++
dot_p = false dot_p = false
@ -506,12 +505,12 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
} }
// remove the dot form the numbers like 2. // remove the dot form the numbers like 2.
if r_i > 1 && res[r_i-1] == `.` { if r_i > 1 && res[r_i - 1] == `.` {
r_i-- r_i--
} }
res[r_i] = 0 res[r_i] = 0
return unsafe { tos(res.data,r_i) } return unsafe { tos(res.data, r_i) }
} }
// dec_digits return the number of decimal digit of an u64 // dec_digits return the number of decimal digit of an u64
@ -543,7 +542,7 @@ pub fn dec_digits(n u64) int {
return 7 return 7
} }
} else { } else {
if n <= 99_999_999 { //8 if n <= 99_999_999 { // 8
return 8 return 8
} else { } else {
if n <= 999_999_999 { // 9 if n <= 999_999_999 { // 9
@ -580,7 +579,7 @@ pub fn dec_digits(n u64) int {
return 17 return 17
} }
} else { } else {
if n <= 999_999_999_999_999_999 { //8 if n <= 999_999_999_999_999_999 { // 8
return 18 return 18
} else { } else {
if n <= 9_999_999_999_999_999_999 { // 9 if n <= 9_999_999_999_999_999_999 { // 9

View File

@ -6,6 +6,7 @@ that can be found in the LICENSE file.
This file contains string interpolation V functions This file contains string interpolation V functions
=============================================================================*/ =============================================================================*/
module strconv module strconv
import strings import strings
enum Char_parse_state { enum Char_parse_state {
@ -15,42 +16,40 @@ enum Char_parse_state {
pad_ch pad_ch
len_set_start len_set_start
len_set_in len_set_in
check_type check_type
check_float check_float
check_float_in check_float_in
reset_params reset_params
} }
pub fn v_printf(str string, pt ... voidptr) { pub fn v_printf(str string, pt ...voidptr) {
print(v_sprintf(str, pt)) print(v_sprintf(str, pt))
} }
pub fn v_sprintf(str string, pt ... voidptr) string{ pub fn v_sprintf(str string, pt ...voidptr) string {
mut res := strings.new_builder(pt.len * 16) mut res := strings.new_builder(pt.len * 16)
mut i := 0 // main string index mut i := 0 // main string index
mut p_index := 0 // parameter index mut p_index := 0 // parameter index
mut sign := false // sign flag mut sign := false // sign flag
mut allign := Align_text.right mut allign := Align_text.right
mut len0 := -1 // forced length, if -1 free length mut len0 := -1 // forced length, if -1 free length
mut len1 := -1 // decimal part for floats mut len1 := -1 // decimal part for floats
def_len1 := 6 // default value for len1 def_len1 := 6 // default value for len1
mut pad_ch := byte(` `) // pad char mut pad_ch := byte(` `) // pad char
// prefix chars for Length field // prefix chars for Length field
mut ch1 := `0` // +1 char if present else `0` mut ch1 := `0` // +1 char if present else `0`
mut ch2 := `0` // +2 char if present else `0` mut ch2 := `0` // +2 char if present else `0`
mut status := Char_parse_state.norm_char mut status := Char_parse_state.norm_char
for i < str.len { for i < str.len {
if status == .reset_params { if status == .reset_params {
sign = false sign = false
allign = .right allign = .right
len0 = -1 len0 = -1
len1 = -1 len1 = -1
pad_ch = ` ` pad_ch = ` `
status = .norm_char status = .norm_char
ch1 = `0` ch1 = `0`
ch2 = `0` ch2 = `0`
@ -72,7 +71,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
// single char, manage it here // single char, manage it here
if ch == `c` && status == .field_char { if ch == `c` && status == .field_char {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
d1 := unsafe {*(&byte(pt[p_index]))} d1 := unsafe { *(&byte(pt[p_index])) }
res.write_b(d1) res.write_b(d1)
status = .reset_params status = .reset_params
p_index++ p_index++
@ -83,8 +82,8 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
// pointer, manage it here // pointer, manage it here
if ch == `p` && status == .field_char { if ch == `p` && status == .field_char {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
res.write_string("0x") res.write_string('0x')
res.write_string(ptr_str(unsafe {pt[p_index]})) res.write_string(ptr_str(unsafe { pt[p_index] }))
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -95,9 +94,9 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
mut fc_ch1 := `0` mut fc_ch1 := `0`
mut fc_ch2 := `0` mut fc_ch2 := `0`
if (i + 1) < str.len { if (i + 1) < str.len {
fc_ch1 = str[i+1] fc_ch1 = str[i + 1]
if (i + 2) < str.len { if (i + 2) < str.len {
fc_ch2 = str[i+2] fc_ch2 = str[i + 2]
} }
} }
if ch == `+` { if ch == `+` {
@ -108,13 +107,13 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
allign = .left allign = .left
i++ i++
continue continue
} else if ch in [`0`,` `] { } else if ch in [`0`, ` `] {
if allign == .right { if allign == .right {
pad_ch = ch pad_ch = ch
} }
i++ i++
continue continue
} else if ch == `'` { } else if ch == `\'` {
i++ i++
continue continue
} else if ch == `.` && fc_ch1 >= `1` && fc_ch1 <= `9` { } else if ch == `.` && fc_ch1 >= `1` && fc_ch1 <= `9` {
@ -125,10 +124,10 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
// manage "%.*s" precision field // manage "%.*s" precision field
else if ch == `.` && fc_ch1 == `*` && fc_ch2 == `s` { else if ch == `.` && fc_ch1 == `*` && fc_ch2 == `s` {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
len := unsafe {*(&int(pt[p_index]))} len := unsafe { *(&int(pt[p_index])) }
p_index++ p_index++
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
mut s := unsafe {*(&string(pt[p_index]))} mut s := unsafe { *(&string(pt[p_index])) }
s = s[..len] s = s[..len]
p_index++ p_index++
res.write_string(s) res.write_string(s)
@ -195,7 +194,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
} }
if status == .check_type { if status == .check_type {
if ch == `l` { if ch == `l` {
if ch1 == `0` { if ch1 == `0` {
ch1 = `l` ch1 = `l`
@ -206,8 +204,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
i++ i++
continue continue
} }
} } else if ch == `h` {
else if ch == `h` {
if ch1 == `0` { if ch1 == `0` {
ch1 = `h` ch1 = `h`
i++ i++
@ -218,24 +215,23 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
continue continue
} }
} }
// signed integer // signed integer
else if ch in [`d`,`i`] { else if ch in [`d`, `i`] {
mut d1 := u64(0) mut d1 := u64(0)
mut positive := true mut positive := true
//println("$ch1 $ch2") // println("$ch1 $ch2")
match ch1 { match ch1 {
// h for 16 bit int // h for 16 bit int
// hh fot 8 bit int // hh fot 8 bit int
`h` { `h` {
if ch2 == `h` { if ch2 == `h` {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&i8(pt[p_index]))} x := unsafe { *(&i8(pt[p_index])) }
positive = if x >= 0 { true } else { false } positive = if x >= 0 { true } else { false }
d1 = if positive { u64(x) } else { u64(-x) } d1 = if positive { u64(x) } else { u64(-x) }
} else { } else {
x := unsafe {*(&i16(pt[p_index]))} x := unsafe { *(&i16(pt[p_index])) }
positive = if x >= 0 { true } else { false } positive = if x >= 0 { true } else { false }
d1 = if positive { u64(x) } else { u64(-x) } d1 = if positive { u64(x) } else { u64(-x) }
} }
@ -258,20 +254,26 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
} }
*/ */
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&i64(pt[p_index]))} x := unsafe { *(&i64(pt[p_index])) }
positive = if x >= 0 { true } else { false } positive = if x >= 0 { true } else { false }
d1 = if positive { u64(x) } else { u64(-x) } d1 = if positive { u64(x) } else { u64(-x) }
} }
// default int // default int
else { else {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&int(pt[p_index]))} x := unsafe { *(&int(pt[p_index])) }
positive = if x >= 0 { true } else { false } positive = if x >= 0 { true } else { false }
d1 = if positive { u64(x) } else { u64(-x) } d1 = if positive { u64(x) } else { u64(-x) }
} }
} }
res.write_string(format_dec_old(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign})) res.write_string(format_dec_old(d1,
pad_ch: pad_ch
len0: len0
len1: 0
positive: positive
sign_flag: sign
allign: allign
))
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -279,7 +281,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
ch2 = `0` ch2 = `0`
continue continue
} }
// unsigned integer // unsigned integer
else if ch == `u` { else if ch == `u` {
mut d1 := u64(0) mut d1 := u64(0)
@ -290,9 +291,9 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
// hh fot 8 bit unsigned int // hh fot 8 bit unsigned int
`h` { `h` {
if ch2 == `h` { if ch2 == `h` {
d1 = u64(unsafe {*(&byte(pt[p_index]))}) d1 = u64(unsafe { *(&byte(pt[p_index])) })
} else { } else {
d1 = u64(unsafe {*(&u16(pt[p_index]))}) d1 = u64(unsafe { *(&u16(pt[p_index])) })
} }
} }
// l u64 // l u64
@ -306,34 +307,40 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
d1 = u64(*(&u64(pt[p_index]))) d1 = u64(*(&u64(pt[p_index])))
} }
*/ */
d1 = u64(unsafe {*(&u64(pt[p_index]))}) d1 = u64(unsafe { *(&u64(pt[p_index])) })
} }
// default int // default int
else { else {
d1 = u64(unsafe {*(&u32(pt[p_index]))}) d1 = u64(unsafe { *(&u32(pt[p_index])) })
} }
} }
res.write_string(format_dec_old(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign})) res.write_string(format_dec_old(d1,
pad_ch: pad_ch
len0: len0
len1: 0
positive: positive
sign_flag: sign
allign: allign
))
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
continue continue
} }
// hex // hex
else if ch in [`x`, `X`] { else if ch in [`x`, `X`] {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
mut s := "" mut s := ''
match ch1 { match ch1 {
// h for 16 bit int // h for 16 bit int
// hh fot 8 bit int // hh fot 8 bit int
`h` { `h` {
if ch2 == `h` { if ch2 == `h` {
x := unsafe {*(&i8(pt[p_index]))} x := unsafe { *(&i8(pt[p_index])) }
s = x.hex() s = x.hex()
} else { } else {
x := unsafe {*(&i16(pt[p_index]))} x := unsafe { *(&i16(pt[p_index])) }
s = x.hex() s = x.hex()
} }
} }
@ -350,11 +357,11 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
s = x.hex() s = x.hex()
} }
*/ */
x := unsafe {*(&i64(pt[p_index]))} x := unsafe { *(&i64(pt[p_index])) }
s = x.hex() s = x.hex()
} }
else { else {
x := unsafe {*(&int(pt[p_index]))} x := unsafe { *(&int(pt[p_index])) }
s = x.hex() s = x.hex()
} }
} }
@ -363,7 +370,14 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
s = s.to_upper() s = s.to_upper()
} }
res.write_string(format_str(s,{pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign})) res.write_string(format_str(s,
pad_ch: pad_ch
len0: len0
len1: 0
positive: true
sign_flag: false
allign: allign
))
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -373,55 +387,89 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
// float and double // float and double
if ch in [`f`, `F`] { if ch in [`f`, `F`] {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))} x := unsafe { *(&f64(pt[p_index])) }
positive := x >= f64(0.0) positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 } len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_fl_old(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign}) s := format_fl_old(f64(x),
res.write_string(if ch == `F` {s.to_upper()} else {s}) pad_ch: pad_ch
len0: len0
len1: len1
positive: positive
sign_flag: sign
allign: allign
)
res.write_string(if ch == `F` { s.to_upper() } else { s })
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
continue continue
} } else if ch in [`e`, `E`] {
else if ch in [`e`, `E`] {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))} x := unsafe { *(&f64(pt[p_index])) }
positive := x >= f64(0.0) positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 } len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_es_old(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign}) s := format_es_old(f64(x),
res.write_string(if ch == `E` {s.to_upper()} else {s}) pad_ch: pad_ch
len0: len0
len1: len1
positive: positive
sign_flag: sign
allign: allign
)
res.write_string(if ch == `E` { s.to_upper() } else { s })
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
continue continue
} } else if ch in [`g`, `G`] {
else if ch in [`g`, `G`] {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))} x := unsafe { *(&f64(pt[p_index])) }
positive := x >= f64(0.0) positive := x >= f64(0.0)
mut s := "" mut s := ''
tx := fabs(x) tx := fabs(x)
if tx < 999_999.0 && tx >= 0.00001 { if tx < 999_999.0 && tx >= 0.00001 {
//println("Here g format_fl [$tx]") // println("Here g format_fl [$tx]")
len1 = if len1 >= 0 { len1+1 } else { def_len1 } len1 = if len1 >= 0 { len1 + 1 } else { def_len1 }
s = format_fl_old(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true}) s = format_fl_old(x,
pad_ch: pad_ch
len0: len0
len1: len1
positive: positive
sign_flag: sign
allign: allign
rm_tail_zero: true
)
} else { } else {
len1 = if len1 >= 0 { len1+1 } else { def_len1 } len1 = if len1 >= 0 { len1 + 1 } else { def_len1 }
s = format_es_old(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true}) s = format_es_old(x,
pad_ch: pad_ch
len0: len0
len1: len1
positive: positive
sign_flag: sign
allign: allign
rm_tail_zero: true
)
} }
res.write_string(if ch == `G` {s.to_upper()} else {s}) res.write_string(if ch == `G` { s.to_upper() } else { s })
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
continue continue
} }
// string // string
else if ch == `s` { else if ch == `s` {
v_sprintf_panic(p_index, pt.len) v_sprintf_panic(p_index, pt.len)
s1 := unsafe{*(&string(pt[p_index]))} s1 := unsafe { *(&string(pt[p_index])) }
pad_ch = ` ` pad_ch = ` `
res.write_string(format_str(s1, {pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign})) res.write_string(format_str(s1,
pad_ch: pad_ch
len0: len0
len1: 0
positive: true
sign_flag: false
allign: allign
))
status = .reset_params status = .reset_params
p_index++ p_index++
i++ i++
@ -435,7 +483,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
} }
if p_index != pt.len { if p_index != pt.len {
panic('${p_index} % conversion specifiers, but given ${pt.len} args') panic('$p_index % conversion specifiers, but given $pt.len args')
} }
return res.str() return res.str()
@ -444,7 +492,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
[inline] [inline]
fn v_sprintf_panic(idx int, len int) { fn v_sprintf_panic(idx int, len int) {
if idx >= len { if idx >= len {
panic('${idx+1} % conversion specifiers, but given only ${len} args') panic('${idx + 1} % conversion specifiers, but given only $len args')
} }
} }
@ -458,12 +506,12 @@ fn fabs(x f64) f64 {
// strings.Builder version of format_fl // strings.Builder version of format_fl
[manualfree] [manualfree]
pub fn format_fl_old(f f64, p BF_param) string { pub fn format_fl_old(f f64, p BF_param) string {
unsafe{ unsafe {
mut s := "" mut s := ''
//mut fs := "1.2343" // mut fs := "1.2343"
mut fs := f64_to_str_lnd1(if f >= 0.0 {f} else {-f}, p.len1) mut fs := f64_to_str_lnd1(if f >= 0.0 { f } else { -f }, p.len1)
//println("Dario") // println("Dario")
//println(fs) // println(fs)
// error!! // error!!
if fs[0] == `[` { if fs[0] == `[` {
@ -476,7 +524,7 @@ pub fn format_fl_old(f f64, p BF_param) string {
fs = remove_tail_zeros_old(fs) fs = remove_tail_zeros_old(fs)
tmp.free() tmp.free()
} }
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len })
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -496,7 +544,7 @@ pub fn format_fl_old(f f64, p BF_param) string {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
tmp := s tmp := s
s = "+" + fs s = '+' + fs
tmp.free() tmp.free()
} else { } else {
tmp := s tmp := s
@ -505,7 +553,7 @@ pub fn format_fl_old(f f64, p BF_param) string {
} }
} else { } else {
tmp := s tmp := s
s = "-" + fs s = '-' + fs
tmp.free() tmp.free()
} }
} }
@ -513,18 +561,17 @@ pub fn format_fl_old(f f64, p BF_param) string {
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
s.free() s.free()
fs.free() fs.free()
tmp_res := res.str() tmp_res := res.str()
@ -535,13 +582,13 @@ pub fn format_fl_old(f f64, p BF_param) string {
[manualfree] [manualfree]
pub fn format_es_old(f f64, p BF_param) string { pub fn format_es_old(f f64, p BF_param) string {
unsafe{ unsafe {
mut s := "" mut s := ''
mut fs := f64_to_str_pad(if f> 0 {f} else {-f},p.len1) mut fs := f64_to_str_pad(if f > 0 { f } else { -f }, p.len1)
if p.rm_tail_zero { if p.rm_tail_zero {
fs = remove_tail_zeros_old(fs) fs = remove_tail_zeros_old(fs)
} }
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) mut res := strings.new_builder(if p.len0 > fs.len { p.len0 } else { fs.len })
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -561,7 +608,7 @@ pub fn format_es_old(f f64, p BF_param) string {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
tmp := s tmp := s
s = "+" + fs s = '+' + fs
tmp.free() tmp.free()
} else { } else {
tmp := s tmp := s
@ -570,20 +617,20 @@ pub fn format_es_old(f f64, p BF_param) string {
} }
} else { } else {
tmp := s tmp := s
s = "-" + fs s = '-' + fs
tmp.free() tmp.free()
} }
} }
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
@ -598,16 +645,15 @@ pub fn format_es_old(f f64, p BF_param) string {
pub fn remove_tail_zeros_old(s string) string { pub fn remove_tail_zeros_old(s string) string {
mut i := 0 mut i := 0
mut last_zero_start := -1 mut last_zero_start := -1
mut dot_pos := -1 mut dot_pos := -1
mut in_decimal := false mut in_decimal := false
mut prev_ch := byte(0) mut prev_ch := byte(0)
for i < s.len { for i < s.len {
ch := unsafe {s.str[i]} ch := unsafe { s.str[i] }
if ch == `.` { if ch == `.` {
in_decimal = true in_decimal = true
dot_pos = i dot_pos = i
} } else if in_decimal {
else if in_decimal {
if ch == `0` && prev_ch != `0` { if ch == `0` && prev_ch != `0` {
last_zero_start = i last_zero_start = i
} else if ch >= `1` && ch <= `9` { } else if ch >= `1` && ch <= `9` {
@ -620,25 +666,25 @@ pub fn remove_tail_zeros_old(s string) string {
i++ i++
} }
mut tmp := "" mut tmp := ''
if last_zero_start > 0 { if last_zero_start > 0 {
if last_zero_start == dot_pos+1 { if last_zero_start == dot_pos + 1 {
tmp = s[..dot_pos] + s[i..] tmp = s[..dot_pos] + s[i..]
}else { } else {
tmp = s[..last_zero_start] + s[i..] tmp = s[..last_zero_start] + s[i..]
} }
} else { } else {
tmp = s tmp = s
} }
if unsafe {tmp.str[tmp.len-1]} == `.` { if unsafe { tmp.str[tmp.len - 1] } == `.` {
return tmp[..tmp.len-1] return tmp[..tmp.len - 1]
} }
return tmp return tmp
} }
// max int64 9223372036854775807 // max int64 9223372036854775807
pub fn format_dec_old(d u64, p BF_param) string { pub fn format_dec_old(d u64, p BF_param) string {
mut s := "" mut s := ''
mut res := strings.new_builder(20) mut res := strings.new_builder(20)
mut sign_len_diff := 0 mut sign_len_diff := 0
if p.pad_ch == `0` { if p.pad_ch == `0` {
@ -655,24 +701,24 @@ pub fn format_dec_old(d u64, p BF_param) string {
} else { } else {
if p.positive { if p.positive {
if p.sign_flag { if p.sign_flag {
s = "+" + d.str() s = '+' + d.str()
} else { } else {
s = d.str() s = d.str()
} }
} else { } else {
s = "-" + d.str() s = '-' + d.str()
} }
} }
dif := p.len0 - s.len + sign_len_diff dif := p.len0 - s.len + sign_len_diff
if p.allign == .right { if p.allign == .right {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }
res.write_string(s) res.write_string(s)
if p.allign == .left { if p.allign == .left {
for i1 :=0; i1 < dif; i1++ { for i1 := 0; i1 < dif; i1++ {
res.write_b(p.pad_ch) res.write_b(p.pad_ch)
} }
} }