Skip to content

Commit

Permalink
std::conv: minor improvements and optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
mertcandav committed Jul 29, 2024
1 parent 6f35c28 commit 4e91197
Show file tree
Hide file tree
Showing 5 changed files with 794 additions and 3,054 deletions.
48 changes: 26 additions & 22 deletions std/conv/atof.jule
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@
// ====================================================

use math for std::math
use nosafe for std::internal::nosafe

const optimize = true

// Returns the length of the common
// prefix of s and prefix, with the character case of s ignored.
// The prefix argument must be all lower-case.
fn commonPrefixLenIgnoreCase(s: str, prefix: str): int {
fn commonPrefixLenIgnoreCase(&s: []byte, prefix: str): int {
let mut n = len(prefix)
if n > len(s) {
n = len(s)
Expand All @@ -65,8 +66,8 @@ fn commonPrefixLenIgnoreCase(s: str, prefix: str): int {
// and NaN. The result is ok if a prefix of s contains one
// of these representations and n is the length of that prefix.
// The character case is ignored.
fn special(mut s: str): (f: f64, n: int, ok: bool) {
if s == "" {
fn special(s: []byte): (f: f64, n: int, ok: bool) {
if len(s) == 0 {
ret 0, 0, false
}
let mut sign = 1
Expand All @@ -77,7 +78,11 @@ fn special(mut s: str): (f: f64, n: int, ok: bool) {
sign = -1
}
nsign = 1
s = s[1:]
unsafe {
// Break immutabilty, do not change content, just slicing.
let mut sp = &s
*sp = (*sp)[1:]
}
fall
| 'i' | 'I':
let mut caseN = commonPrefixLenIgnoreCase(s, "infinity")
Expand All @@ -100,7 +105,7 @@ fn special(mut s: str): (f: f64, n: int, ok: bool) {
// Reads a decimal or hexadecimal mantissa and exponent from a float
// string representation in s; the number may be followed by other characters.
// Reports the number of bytes consumed (i), and whether the number is valid (ok).
fn readFloat(s: str): (mantissa: u64, exp: int, neg: bool, trunc: bool, hex: bool, i: int, ok: bool) {
fn readFloat(&s: str): (mantissa: u64, exp: int, neg: bool, trunc: bool, hex: bool, i: int, ok: bool) {
// optional sign
if i >= len(s) {
ret
Expand Down Expand Up @@ -230,7 +235,7 @@ loop_end:
static powtab = [1, 3, 6, 9, 13, 16, 19, 23, 26]

impl decimal {
fn set(mut self, s: str): (ok: bool) {
fn set(mut self, s: []byte): (ok: bool) {
let mut i = 0
self.neg = false
self.trunc = false
Expand Down Expand Up @@ -548,7 +553,7 @@ fn atof32exact(mantissa: u64, mut exp: int, mut neg: bool): (f: f32, ok: bool) {
// and returns it as a f64.
// The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative).
// If trunc is true, trailing non-zero bits have been omitted from the mantissa.
fn atofHex(s: str, &flt: floatInfo, mut mantissa: u64, mut exp: int, neg: bool, trunc: bool): (f64, ConvError) {
fn atofHex(&flt: floatInfo, mut mantissa: u64, mut exp: int, neg: bool, trunc: bool): (f64, ConvError) {
let maxExp = int(1 << flt.expbits) + flt.bias - 2
let minExp = flt.bias + 1
exp += int(flt.mantbits) // mantissa now implicitly divided by 2^mantbits.
Expand Down Expand Up @@ -613,9 +618,9 @@ fn atofHex(s: str, &flt: floatInfo, mut mantissa: u64, mut exp: int, neg: bool,
ret math::F64FromBits(bits), err
}

fn atof32(s: str): (f: f32, n: int, err: ConvError) {
fn atof32(&s: str): (f: f32, n: int, err: ConvError) {
{
let (val, _n, ok) = special(s)
let (val, _n, ok) = special(nosafe::Stobs(s))
if ok {
ret f32(val), _n, ConvError.Ok
}
Expand All @@ -629,7 +634,7 @@ fn atof32(s: str): (f: f32, n: int, err: ConvError) {

if hex {
let mut ff: f64 = 0
ff, err = atofHex(s[:n], f32info, mantissa, exp, neg, trunc)
ff, err = atofHex(f32info, mantissa, exp, neg, trunc)
ret f32(ff), n, err
}

Expand Down Expand Up @@ -660,7 +665,7 @@ fn atof32(s: str): (f: f32, n: int, err: ConvError) {

// Slow fallback.
let mut d = decimal{}
if !d.set(s[:n]) {
if !d.set(nosafe::Stobs(s)[:n]) {
ret 0, n, ConvError.InvalidSyntax
}
let (b, ovf) = d.floatBits(f32info)
Expand All @@ -671,9 +676,9 @@ fn atof32(s: str): (f: f32, n: int, err: ConvError) {
ret f, n, err
}

fn atof64(s: str): (f: f64, n: int, err: ConvError) {
fn atof64(&s: str): (f: f64, n: int, err: ConvError) {
{
let (val, _n, ok) = special(s)
let (val, _n, ok) = special(nosafe::Stobs(s))
if ok {
ret val, _n, ConvError.Ok
}
Expand All @@ -686,7 +691,7 @@ fn atof64(s: str): (f: f64, n: int, err: ConvError) {
}

if hex {
f, err = atofHex(s[:n], f64info, mantissa, exp, neg, trunc)
f, err = atofHex(f64info, mantissa, exp, neg, trunc)
ret f, n, err
}

Expand Down Expand Up @@ -717,7 +722,7 @@ fn atof64(s: str): (f: f64, n: int, err: ConvError) {

// Slow fallback.
let mut d = decimal{}
if !d.set(s[:n]) {
if !d.set(nosafe::Stobs(s)[:n]) {
ret 0, n, ConvError.InvalidSyntax
}
let (b, ovf) = d.floatBits(f64info)
Expand All @@ -728,19 +733,18 @@ fn atof64(s: str): (f: f64, n: int, err: ConvError) {
ret f, n, err
}

fn parseFloatPrefix(s: str, bit_size: int): (f64, int, ConvError) {
if bit_size == 32 {
fn parseFloatPrefix(&s: str, bitSize: int): (f64, int, ConvError) {
if bitSize == 32 {
let (f, n, err) = atof32(s)
ret f64(f), n, err
}

let (f, n, err) = atof64(s)
ret f, n, err
}

// Converts the string s to a floating-point number
// with the precision specified by bit_size: 32 for f32, or 64 for f64.
// When bit_size=32, the result still has type f64, but it will be
// with the precision specified by bitSize: 32 for f32, or 64 for f64.
// When bitSize=32, the result still has type f64, but it will be
// convertible to f32 without changing its value.
//
// Accepts decimal and hexadecimal floating-point numbers
Expand All @@ -762,8 +766,8 @@ fn parseFloatPrefix(s: str, bit_size: int): (f64, int, ConvError) {
//
// Recognizes the string "NaN", and the (possibly signed) strings "inf" and "infinity"
// as their respective special floating point values. It ignores case when matching.
fn ParseFloat(s: str, bit_size: int)!: f64 {
let (f, n, err) = parseFloatPrefix(s, bit_size)
fn ParseFloat(s: str, bitSize: int)!: f64 {
let (f, n, err) = parseFloatPrefix(s, bitSize)
if n != len(s) && (err == ConvError.Ok || err != ConvError.InvalidSyntax) {
error(ConvError.InvalidSyntax)
}
Expand Down
2 changes: 1 addition & 1 deletion std/conv/atoi.jule
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn lower(c: byte): byte {
ret c | ('x' - 'X')
}

fn parseUint(mut s: str, mut base: int, mut bitSize: int): (u64, ConvError) {
fn parseUint(mut &s: str, mut base: int, mut bitSize: int): (u64, ConvError) {
if s == "" {
ret 0, ConvError.InvalidSyntax
}
Expand Down
Loading

0 comments on commit 4e91197

Please sign in to comment.