cleanup + further optimize split_function_chars
This commit is contained in:
parent
bf58e82c80
commit
79782d84b1
1
TODO.md
1
TODO.md
@ -20,3 +20,4 @@
|
||||
10. Create actual icon(s) for PWA/favicon (using placeholder from eframe_template)
|
||||
11. Fix mobile text input
|
||||
12. Don't use json for text storage
|
||||
13. Write custom plotter
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use exmex::prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FlatExWrapper {
|
||||
pub(crate) struct FlatExWrapper {
|
||||
func: Option<FlatEx<f64>>,
|
||||
}
|
||||
|
||||
@ -172,10 +172,18 @@ fn prettyify_function_str(func: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub const VALID_VARIABLES: [char; 3] = ['x', 'e', 'π'];
|
||||
// pub const VALID_VARIABLES: [char; 3] = ['x', 'e', 'π'];
|
||||
|
||||
/// Case insensitive checks for if `c` is a character used to represent a variable
|
||||
#[inline]
|
||||
pub fn is_variable(c: &char) -> bool { VALID_VARIABLES.contains(&c.to_ascii_lowercase()) }
|
||||
pub const fn is_variable(c: &char) -> bool {
|
||||
match c.to_ascii_lowercase() {
|
||||
'x' => true,
|
||||
'e' => true,
|
||||
'π' => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds asterisks where needed in a function
|
||||
pub fn process_func_str(function_in: &str) -> String {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::{intrinsics::assume, mem};
|
||||
use std::intrinsics::assume;
|
||||
|
||||
use crate::parsing::is_variable;
|
||||
|
||||
@ -28,7 +28,6 @@ pub fn split_function(input: &str) -> Vec<String> {
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
// __REVIEW__
|
||||
pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
if chars.is_empty() {
|
||||
return Vec::new();
|
||||
@ -45,11 +44,12 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
}
|
||||
|
||||
// Resulting split-up data
|
||||
let mut data: Vec<Vec<&char>> = Vec::with_capacity(chars.len());
|
||||
let mut data: Vec<String> = Vec::with_capacity(chars.len());
|
||||
|
||||
// Buffer used to store data ready to be appended
|
||||
let mut buffer: Vec<&char> = Vec::with_capacity(chars.len());
|
||||
// Need to start out with an empty string
|
||||
data.push(String::new());
|
||||
|
||||
/// Used to store info about a character
|
||||
struct BoolSlice {
|
||||
closing_parens: bool,
|
||||
number: bool,
|
||||
@ -60,7 +60,7 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
}
|
||||
|
||||
impl BoolSlice {
|
||||
fn from_char(c: &char, prev_masked_num: bool, prev_masked_var: bool) -> Self {
|
||||
const 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);
|
||||
Self {
|
||||
@ -81,11 +81,42 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
const fn is_variable(&self) -> bool { self.variable && !self.masked_var }
|
||||
|
||||
const fn is_number(&self) -> bool { self.number && !self.masked_num }
|
||||
|
||||
const fn splitable(&self, c: &char, other: &BoolSlice) -> bool {
|
||||
if other.closing_parens {
|
||||
// Cases like `)x`, `)2`, and `)(`
|
||||
return (*c == '(')
|
||||
| (self.letter && !self.is_variable())
|
||||
| self.is_variable() | self.is_number();
|
||||
} else if *c == '(' {
|
||||
// Cases like `x(` and `2(`
|
||||
return (other.is_variable() | other.is_number()) && !other.letter;
|
||||
} else if other.is_number() {
|
||||
// Cases like `2x` and `2sin(x)`
|
||||
return self.is_variable() | self.letter;
|
||||
} else if self.is_variable() | self.letter {
|
||||
// Cases like `e2` and `xx`
|
||||
return other.is_number()
|
||||
| (other.is_variable() && self.is_variable())
|
||||
| other.is_variable();
|
||||
} else if (self.is_number() | self.letter | self.is_variable())
|
||||
&& (other.is_number() | other.letter)
|
||||
{
|
||||
return true;
|
||||
} else if self.is_number() && other.is_variable() {
|
||||
// Cases like `x2`
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup first char here
|
||||
let mut prev_char: BoolSlice = BoolSlice::from_char(&chars[0], false, false);
|
||||
buffer.push(&chars[0]);
|
||||
|
||||
let mut last = unsafe { data.last_mut().unwrap_unchecked() };
|
||||
last.push(chars[0]);
|
||||
|
||||
// Iterate through all chars excluding the first one
|
||||
for c in chars.iter().skip(1) {
|
||||
@ -115,59 +146,19 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut do_split = false;
|
||||
|
||||
if prev_char.closing_parens {
|
||||
// Cases like `)x`, `)2`, and `)(`
|
||||
do_split = (c == &'(')
|
||||
| (curr_c.letter && !curr_c.is_variable())
|
||||
| curr_c.is_variable()
|
||||
| curr_c.is_number();
|
||||
} else if c == &'(' {
|
||||
// Cases like `x(` and `2(`
|
||||
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)`
|
||||
do_split = curr_c.is_variable() | curr_c.letter;
|
||||
} else if curr_c.is_variable() | curr_c.letter {
|
||||
// Cases like `e2` and `xx`
|
||||
do_split = prev_char.is_number()
|
||||
| (prev_char.is_variable() && curr_c.is_variable())
|
||||
| prev_char.is_variable()
|
||||
} else if (curr_c.is_number() | curr_c.letter | curr_c.is_variable())
|
||||
&& (prev_char.is_number() | prev_char.letter)
|
||||
{
|
||||
do_split = true;
|
||||
} else if curr_c.is_number() && prev_char.is_variable() {
|
||||
// Cases like `x2`
|
||||
do_split = true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
if curr_c.splitable(c, &prev_char) {
|
||||
data.push(String::new());
|
||||
last = unsafe { data.last_mut().unwrap_unchecked() };
|
||||
}
|
||||
|
||||
// Add character to buffer
|
||||
buffer.push(c);
|
||||
last.push(*c);
|
||||
|
||||
// Move current character data to `prev_char`
|
||||
prev_char = curr_c;
|
||||
}
|
||||
|
||||
// If there is still data in the buffer, append it
|
||||
if !buffer.is_empty() {
|
||||
data.push(buffer);
|
||||
}
|
||||
|
||||
data.into_iter()
|
||||
.map(|e| e.iter().map(|c| *c).collect::<String>())
|
||||
.collect::<Vec<String>>()
|
||||
data
|
||||
}
|
||||
|
||||
/// Generate a hint based on the input `input`, returns an `Option<String>`
|
||||
|
||||
@ -68,30 +68,30 @@ pub struct FunctionEntry {
|
||||
|
||||
impl const Default for FunctionEntry {
|
||||
/// Creates default FunctionEntry instance (which is empty)
|
||||
fn default() -> FunctionEntry {
|
||||
FunctionEntry {
|
||||
function: BackingFunction::EMPTY,
|
||||
raw_func_str: String::new(),
|
||||
min_x: -1.0,
|
||||
max_x: 1.0,
|
||||
integral: false,
|
||||
derivative: false,
|
||||
nth_derviative: false,
|
||||
back_data: Vec::new(),
|
||||
integral_data: None,
|
||||
derivative_data: Vec::new(),
|
||||
extrema_data: Vec::new(),
|
||||
root_data: Vec::new(),
|
||||
nth_derivative_data: None,
|
||||
autocomplete: AutoComplete::default(),
|
||||
test_result: None,
|
||||
curr_nth: 3,
|
||||
settings_opened: false,
|
||||
}
|
||||
}
|
||||
fn default() -> FunctionEntry { FunctionEntry::EMPTY }
|
||||
}
|
||||
|
||||
impl FunctionEntry {
|
||||
pub const EMPTY: FunctionEntry = FunctionEntry {
|
||||
function: BackingFunction::EMPTY,
|
||||
raw_func_str: String::new(),
|
||||
min_x: -1.0,
|
||||
max_x: 1.0,
|
||||
integral: false,
|
||||
derivative: false,
|
||||
nth_derviative: false,
|
||||
back_data: Vec::new(),
|
||||
integral_data: None,
|
||||
derivative_data: Vec::new(),
|
||||
extrema_data: Vec::new(),
|
||||
root_data: Vec::new(),
|
||||
nth_derivative_data: None,
|
||||
autocomplete: AutoComplete::default(),
|
||||
test_result: None,
|
||||
curr_nth: 3,
|
||||
settings_opened: false,
|
||||
};
|
||||
|
||||
pub fn settings_window(&mut self, ctx: &Context) {
|
||||
let mut invalidate_nth = false;
|
||||
egui::Window::new(format!("Settings: {}", self.raw_func_str))
|
||||
@ -605,7 +605,7 @@ mod tests {
|
||||
fn do_test(sum: Riemann, area_target: f64) {
|
||||
let settings = app_settings_constructor(sum, -1.0, 1.0, 10, 10);
|
||||
|
||||
let mut function = FunctionEntry::default();
|
||||
let mut function = FunctionEntry::EMPTY;
|
||||
function.update_string("x^2");
|
||||
function.integral = true;
|
||||
function.derivative = true;
|
||||
|
||||
@ -14,7 +14,10 @@ pub struct FunctionManager {
|
||||
impl Default for FunctionManager {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
functions: vec![(Uuid::new_v4(), FunctionEntry::default())],
|
||||
functions: vec![(
|
||||
uuid!("684fc8be-4ba0-408d-96ef-480b0642126f"), // Random uuid here to avoid call to `Uuid::new_v4()`
|
||||
FunctionEntry::EMPTY,
|
||||
)],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,10 +199,7 @@ impl FunctionManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_function(&mut self) {
|
||||
self.functions
|
||||
.push((Uuid::new_v4(), FunctionEntry::default()));
|
||||
}
|
||||
pub fn new_function(&mut self) { self.functions.push((Uuid::new_v4(), FunctionEntry::EMPTY)); }
|
||||
|
||||
pub fn any_using_integral(&self) -> bool {
|
||||
self.functions.iter().any(|(_, func)| func.integral)
|
||||
|
||||
@ -9,6 +9,9 @@
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
#[macro_use]
|
||||
extern crate uuid;
|
||||
|
||||
mod consts;
|
||||
mod function_entry;
|
||||
mod function_manager;
|
||||
|
||||
@ -7,6 +7,9 @@
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
#[macro_use]
|
||||
extern crate uuid;
|
||||
|
||||
mod consts;
|
||||
mod function_entry;
|
||||
mod function_manager;
|
||||
|
||||
@ -107,6 +107,7 @@ pub struct MathApp {
|
||||
/// Contains the list of Areas calculated (the vector of f64) and time it took for the last frame (the Duration). Stored in a Tuple.
|
||||
last_info: (Vec<Option<f64>>, Option<Duration>),
|
||||
|
||||
/// Whether or not dark mode is enabled
|
||||
dark_mode: bool,
|
||||
|
||||
/// Stores opened windows/elements for later reference
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user