Skip to content

Commit

Permalink
Refactor PluralOperands::from_str
Browse files Browse the repository at this point in the history
The implementation is refactored to use `FixedDecimal::from_str`.
At the moment, though, the benchmarks are not happy.

```
operands/create/string  time:   [2.0088 us 2.0092 us 2.0097 us]
                        change: [+220.75% +221.44% +222.11%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) low mild
  3 (3.00%) high mild
  4 (4.00%) high severe
```
  • Loading branch information
filmil committed Oct 1, 2020
1 parent 0e12fd0 commit d0ecb8f
Showing 1 changed file with 9 additions and 61 deletions.
70 changes: 9 additions & 61 deletions components/pluralrules/src/operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use icu_num_util::FixedDecimal;
use std::convert::TryFrom;
use std::io::Error as IOError;
use std::isize;
use std::num::ParseIntError;
use std::str::FromStr;

/// A full plural operands representation of a number. See [CLDR Plural Rules](http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules) for complete operands description.
Expand Down Expand Up @@ -76,17 +75,17 @@ impl PluralOperands {
}
}

#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq)]
pub enum OperandsError {
/// Input to the Operands parsing was empty.
Empty,
/// Input to the Operands parsing was invalid.
Parse(icu_num_util::Error),
/// Any other invalid state.
Invalid,
}

impl From<ParseIntError> for OperandsError {
fn from(_: ParseIntError) -> Self {
Self::Invalid
impl From<icu_num_util::Error> for OperandsError {
fn from(e: icu_num_util::Error) -> Self {
OperandsError::Parse(e)
}
}

Expand All @@ -100,60 +99,9 @@ impl FromStr for PluralOperands {
type Err = OperandsError;

fn from_str(input: &str) -> Result<Self, Self::Err> {
if input.is_empty() {
return Err(OperandsError::Empty);
}

let abs_str = if input.starts_with('-') {
&input[1..]
} else {
&input
};

let (
integer_digits,
num_fraction_digits0,
num_fraction_digits,
fraction_digits0,
fraction_digits,
) = if let Some(sep_idx) = abs_str.find('.') {
let int_str = &abs_str[..sep_idx];
let dec_str = &abs_str[(sep_idx + 1)..];

let integer_digits = u64::from_str(&int_str)?;

let dec_str_no_zeros = dec_str.trim_end_matches('0');

let num_fraction_digits0 = dec_str.len() as usize;
let num_fraction_digits = dec_str_no_zeros.len() as usize;

let fraction_digits0 = u64::from_str(&dec_str)?;
let fraction_digits =
if num_fraction_digits == 0 || num_fraction_digits == num_fraction_digits0 {
fraction_digits0
} else {
u64::from_str(&dec_str_no_zeros)?
};

(
integer_digits,
num_fraction_digits0,
num_fraction_digits,
fraction_digits0,
fraction_digits,
)
} else {
let integer_digits = u64::from_str(&abs_str)?;
(integer_digits, 0, 0, 0, 0)
};

Ok(PluralOperands {
i: integer_digits,
v: num_fraction_digits0,
w: num_fraction_digits,
f: fraction_digits0,
t: fraction_digits,
})
FixedDecimal::from_str(input)
.map(|e| PluralOperands::from(&e))
.map_err(|e| e.into())
}
}

Expand Down

0 comments on commit d0ecb8f

Please sign in to comment.