refactoring
This commit is contained in:
parent
e83c490833
commit
40f070c726
@ -183,6 +183,7 @@ mod tests {
|
||||
("sin(x)cos(x)", true),
|
||||
("x/0", true),
|
||||
("(x+1)(x-3)", true),
|
||||
("cos(xsin(x)x)", true),
|
||||
("(2x+1)x", true),
|
||||
("(2x+1)pi", true),
|
||||
("pi(2x+1)", true),
|
||||
@ -223,6 +224,7 @@ mod tests {
|
||||
("pipipipipipi", "π*π*π*π*π*π"),
|
||||
("10pi", "10*π"),
|
||||
("pi10", "π*10"),
|
||||
("10pi10", "10*π*10"),
|
||||
("emax(x)", "e*max(x)"),
|
||||
("pisin(x)", "π*sin(x)"),
|
||||
("e^sin(x)", "e^sin(x)"),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::mem;
|
||||
use std::{intrinsics::assume, mem};
|
||||
|
||||
use crate::parsing::is_variable;
|
||||
|
||||
@ -34,6 +34,16 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// No point in processing everything if there's only 1 character
|
||||
if chars.len() == 1 {
|
||||
return vec![chars[0].to_string()];
|
||||
}
|
||||
|
||||
unsafe {
|
||||
assume(chars.len() > 1);
|
||||
assume(!chars.is_empty());
|
||||
}
|
||||
|
||||
// Resulting split-up data
|
||||
let mut data: Vec<Vec<&char>> = Vec::with_capacity(chars.len());
|
||||
|
||||
@ -47,104 +57,83 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
variable: bool,
|
||||
masked_num: bool,
|
||||
masked_var: bool,
|
||||
exists: bool,
|
||||
}
|
||||
|
||||
impl BoolSlice {
|
||||
#[inline(always)]
|
||||
fn is_variable(&self) -> bool { self.variable && !self.masked_var }
|
||||
|
||||
#[inline(always)]
|
||||
fn is_number(&self) -> bool { self.number && !self.masked_num }
|
||||
}
|
||||
|
||||
let mut prev_char: BoolSlice = BoolSlice {
|
||||
closing_parens: false,
|
||||
number: false,
|
||||
letter: false,
|
||||
variable: false,
|
||||
masked_num: false,
|
||||
masked_var: false,
|
||||
exists: false,
|
||||
};
|
||||
|
||||
for c in chars {
|
||||
// Set data about current character
|
||||
let mut curr_c = {
|
||||
fn from_char(c: &char, prev_masked_num: bool, prev_masked_var: bool) -> Self {
|
||||
let isnumber = c.is_ascii_digit();
|
||||
let isvariable = is_variable(c);
|
||||
BoolSlice {
|
||||
Self {
|
||||
closing_parens: c == &')',
|
||||
number: isnumber,
|
||||
letter: c.is_ascii_alphabetic(),
|
||||
variable: isvariable,
|
||||
masked_num: match isnumber {
|
||||
true => prev_char.masked_num,
|
||||
true => prev_masked_num,
|
||||
false => false,
|
||||
},
|
||||
masked_var: match isvariable {
|
||||
true => prev_char.masked_var,
|
||||
true => prev_masked_var,
|
||||
false => false,
|
||||
},
|
||||
exists: true,
|
||||
}
|
||||
};
|
||||
}
|
||||
fn is_variable(&self) -> bool { self.variable && !self.masked_var }
|
||||
|
||||
// Check if prev_char is valid
|
||||
if prev_char.exists {
|
||||
// If previous char was a masked number, and current char is a number, mask current char's variable status
|
||||
if prev_char.masked_num && curr_c.number {
|
||||
fn is_number(&self) -> bool { self.number && !self.masked_num }
|
||||
}
|
||||
|
||||
// Setup first char here
|
||||
let mut prev_char: BoolSlice = BoolSlice::from_char(&chars[0], false, false);
|
||||
buffer.push(&chars[0]);
|
||||
|
||||
// Iterate through all chars excluding the first one
|
||||
for c in chars.iter().skip(1) {
|
||||
// Set data about current character
|
||||
let mut curr_c = BoolSlice::from_char(c, prev_char.masked_num, prev_char.masked_var);
|
||||
|
||||
// If previous char was a masked number, and current char is a number, mask current char's variable status
|
||||
if prev_char.masked_num && curr_c.number {
|
||||
curr_c.masked_num = true;
|
||||
}
|
||||
|
||||
// If previous char was a masked variable, and current char is a variable, mask current char's variable status
|
||||
if prev_char.masked_var && curr_c.variable {
|
||||
curr_c.masked_var = true;
|
||||
}
|
||||
|
||||
// If letter and not a variable (or a masked variable)
|
||||
if prev_char.letter && !prev_char.is_variable() {
|
||||
// Mask number status if current char is number
|
||||
if curr_c.number {
|
||||
curr_c.masked_num = true;
|
||||
}
|
||||
|
||||
// If previous char was a masked variable, and current char is a variable, mask current char's variable status
|
||||
if prev_char.masked_var && curr_c.variable {
|
||||
// Mask variable status if current char is a variable
|
||||
if curr_c.variable {
|
||||
curr_c.masked_var = true;
|
||||
}
|
||||
|
||||
// If letter and not a variable (or a masked variable)
|
||||
if prev_char.letter && !prev_char.is_variable() {
|
||||
// Mask number status if current char is number
|
||||
if curr_c.number {
|
||||
curr_c.masked_num = true;
|
||||
}
|
||||
|
||||
// Mask variable status if current char is a variable
|
||||
if curr_c.variable {
|
||||
curr_c.masked_var = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut do_split = false;
|
||||
|
||||
if prev_char.closing_parens {
|
||||
// Cases like `)x`, `)2`, and `)(`
|
||||
if (c == &'(')
|
||||
do_split = (c == &'(')
|
||||
| (curr_c.letter && !curr_c.is_variable())
|
||||
| curr_c.is_variable()
|
||||
| curr_c.is_number()
|
||||
{
|
||||
do_split = true;
|
||||
}
|
||||
| curr_c.is_number();
|
||||
} else if c == &'(' {
|
||||
// Cases like `x(` and `2(`
|
||||
if (prev_char.is_variable() | prev_char.is_number()) && !prev_char.letter {
|
||||
do_split = true;
|
||||
}
|
||||
do_split = (prev_char.is_variable() | prev_char.is_number()) && !prev_char.letter;
|
||||
} else if prev_char.is_number() {
|
||||
// Cases like `2x` and `2sin(x)`
|
||||
if curr_c.is_variable() | curr_c.letter {
|
||||
do_split = true;
|
||||
}
|
||||
do_split = curr_c.is_variable() | curr_c.letter;
|
||||
} else if curr_c.is_variable() | curr_c.letter {
|
||||
// Cases like `e2` and `xx`
|
||||
if prev_char.is_number()
|
||||
do_split = prev_char.is_number()
|
||||
| (prev_char.is_variable() && curr_c.is_variable())
|
||||
| prev_char.is_variable()
|
||||
{
|
||||
do_split = true;
|
||||
}
|
||||
} else if (curr_c.is_number() | curr_c.letter | curr_c.is_variable())
|
||||
&& (prev_char.is_number() | prev_char.letter)
|
||||
{
|
||||
@ -157,6 +146,8 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
// Append split
|
||||
if do_split {
|
||||
data.push(Vec::new());
|
||||
|
||||
// Don't deinitialize `buffer`, simply swap data between the new last element of `data` with buffer!
|
||||
unsafe {
|
||||
mem::swap(data.last_mut().unwrap_unchecked(), &mut buffer);
|
||||
}
|
||||
@ -174,13 +165,7 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
data.push(buffer);
|
||||
}
|
||||
|
||||
if data.len() == 1 {
|
||||
if data[0].is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
}
|
||||
|
||||
data.iter()
|
||||
data.into_iter()
|
||||
.map(|e| e.iter().map(|c| *c).collect::<String>())
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
@ -330,6 +315,9 @@ mod tests {
|
||||
("cos(x)sin(x)", vec!["cos(x)", "sin(x)"]),
|
||||
("aaaaaaaaaaa", vec!["aaaaaaaaaaa"]),
|
||||
("emax(x)", vec!["e", "max(x)"]),
|
||||
("x", vec!["x"]),
|
||||
("xxx", vec!["x", "x", "x"]),
|
||||
("sin(cos(x)x)", vec!["sin(cos(x)", "x)"]),
|
||||
]);
|
||||
|
||||
for (key, value) in values {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user