-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
numbers.rs
117 lines (105 loc) · 2.96 KB
/
numbers.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/// Parse a string as an int.
///
/// This is around 2x faster than using `str::parse::<i64>()`
pub fn int_parse_str(s: &str) -> Option<i64> {
int_parse_bytes(s.as_bytes())
}
/// Parse bytes as an int.
pub fn int_parse_bytes(s: &[u8]) -> Option<i64> {
let (neg, first_digit, digits) = match s {
[b'-', first, digits @ ..] => (true, first, digits),
[b'+', first, digits @ ..] | [first, digits @ ..] => (false, first, digits),
_ => return None,
};
let mut result = match first_digit {
b'0' => 0,
b'1'..=b'9' => (first_digit & 0x0f) as i64,
_ => return None,
};
for digit in digits {
result = result.checked_mul(10)?;
match digit {
b'0' => {}
b'1'..=b'9' => result = result.checked_add((digit & 0x0f) as i64)?,
_ => return None,
}
}
if neg {
Some(-result)
} else {
Some(result)
}
}
#[derive(Debug)]
pub enum IntFloat {
Int(i64),
Float(f64),
Err,
}
impl IntFloat {
pub fn is_err(&self) -> bool {
matches!(self, IntFloat::Err)
}
}
/// Parse a string as a float.
///
/// This is around 2x faster than using `str::parse::<f64>()`
pub fn float_parse_str(s: &str) -> IntFloat {
float_parse_bytes(s.as_bytes())
}
/// Parse bytes as an float.
pub fn float_parse_bytes(s: &[u8]) -> IntFloat {
let (neg, first_digit, digits) = match s {
[b'-', first, digits @ ..] => (true, first, digits),
[b'+', first, digits @ ..] | [first, digits @ ..] => (false, first, digits),
_ => return IntFloat::Err,
};
let mut int_part = match first_digit {
b'0' => 0,
b'1'..=b'9' => (first_digit & 0x0f) as i64,
_ => return IntFloat::Err,
};
let mut found_dot = false;
let mut bytes = digits.iter().copied();
for digit in bytes.by_ref() {
match digit {
b'0'..=b'9' => {
int_part = match int_part.checked_mul(10) {
Some(i) => i,
None => return IntFloat::Err,
};
int_part = match int_part.checked_add((digit & 0x0f) as i64) {
Some(i) => i,
None => return IntFloat::Err,
};
}
b'.' => {
found_dot = true;
break;
}
_ => return IntFloat::Err,
}
}
if found_dot {
let mut result = int_part as f64;
let mut div = 10_f64;
for digit in bytes {
match digit {
b'0'..=b'9' => {
result += (digit & 0x0f) as f64 / div;
div *= 10_f64;
}
_ => return IntFloat::Err,
}
}
if neg {
IntFloat::Float(-result)
} else {
IntFloat::Float(result)
}
} else if neg {
IntFloat::Int(-int_part)
} else {
IntFloat::Int(int_part)
}
}