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)
|
10. Create actual icon(s) for PWA/favicon (using placeholder from eframe_template)
|
||||||
11. Fix mobile text input
|
11. Fix mobile text input
|
||||||
12. Don't use json for text storage
|
12. Don't use json for text storage
|
||||||
|
13. Write custom plotter
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use exmex::prelude::*;
|
use exmex::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FlatExWrapper {
|
pub(crate) struct FlatExWrapper {
|
||||||
func: Option<FlatEx<f64>>,
|
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]
|
#[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
|
/// Adds asterisks where needed in a function
|
||||||
pub fn process_func_str(function_in: &str) -> String {
|
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;
|
use crate::parsing::is_variable;
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ pub fn split_function(input: &str) -> Vec<String> {
|
|||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
// __REVIEW__
|
|
||||||
pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
||||||
if chars.is_empty() {
|
if chars.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
@ -45,11 +44,12 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resulting split-up data
|
// 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
|
// Need to start out with an empty string
|
||||||
let mut buffer: Vec<&char> = Vec::with_capacity(chars.len());
|
data.push(String::new());
|
||||||
|
|
||||||
|
/// Used to store info about a character
|
||||||
struct BoolSlice {
|
struct BoolSlice {
|
||||||
closing_parens: bool,
|
closing_parens: bool,
|
||||||
number: bool,
|
number: bool,
|
||||||
@ -60,7 +60,7 @@ pub fn split_function_chars(chars: &[char]) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BoolSlice {
|
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 isnumber = c.is_ascii_digit();
|
||||||
let isvariable = is_variable(c);
|
let isvariable = is_variable(c);
|
||||||
Self {
|
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_variable(&self) -> bool { self.variable && !self.masked_var }
|
||||||
|
|
||||||
const fn is_number(&self) -> bool { self.number && !self.masked_num }
|
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
|
// Setup first char here
|
||||||
let mut prev_char: BoolSlice = BoolSlice::from_char(&chars[0], false, false);
|
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
|
// Iterate through all chars excluding the first one
|
||||||
for c in chars.iter().skip(1) {
|
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
|
// Append split
|
||||||
if do_split {
|
if curr_c.splitable(c, &prev_char) {
|
||||||
data.push(Vec::new());
|
data.push(String::new());
|
||||||
|
last = unsafe { data.last_mut().unwrap_unchecked() };
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add character to buffer
|
last.push(*c);
|
||||||
buffer.push(c);
|
|
||||||
|
|
||||||
// Move current character data to `prev_char`
|
// Move current character data to `prev_char`
|
||||||
prev_char = curr_c;
|
prev_char = curr_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is still data in the buffer, append it
|
data
|
||||||
if !buffer.is_empty() {
|
|
||||||
data.push(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.into_iter()
|
|
||||||
.map(|e| e.iter().map(|c| *c).collect::<String>())
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a hint based on the input `input`, returns an `Option<String>`
|
/// Generate a hint based on the input `input`, returns an `Option<String>`
|
||||||
|
|||||||
@ -68,30 +68,30 @@ pub struct FunctionEntry {
|
|||||||
|
|
||||||
impl const Default for FunctionEntry {
|
impl const Default for FunctionEntry {
|
||||||
/// Creates default FunctionEntry instance (which is empty)
|
/// Creates default FunctionEntry instance (which is empty)
|
||||||
fn default() -> FunctionEntry {
|
fn default() -> FunctionEntry { FunctionEntry::EMPTY }
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionEntry {
|
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) {
|
pub fn settings_window(&mut self, ctx: &Context) {
|
||||||
let mut invalidate_nth = false;
|
let mut invalidate_nth = false;
|
||||||
egui::Window::new(format!("Settings: {}", self.raw_func_str))
|
egui::Window::new(format!("Settings: {}", self.raw_func_str))
|
||||||
@ -605,7 +605,7 @@ mod tests {
|
|||||||
fn do_test(sum: Riemann, area_target: f64) {
|
fn do_test(sum: Riemann, area_target: f64) {
|
||||||
let settings = app_settings_constructor(sum, -1.0, 1.0, 10, 10);
|
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.update_string("x^2");
|
||||||
function.integral = true;
|
function.integral = true;
|
||||||
function.derivative = true;
|
function.derivative = true;
|
||||||
|
|||||||
@ -14,7 +14,10 @@ pub struct FunctionManager {
|
|||||||
impl Default for FunctionManager {
|
impl Default for FunctionManager {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
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) {
|
pub fn new_function(&mut self) { self.functions.push((Uuid::new_v4(), FunctionEntry::EMPTY)); }
|
||||||
self.functions
|
|
||||||
.push((Uuid::new_v4(), FunctionEntry::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn any_using_integral(&self) -> bool {
|
pub fn any_using_integral(&self) -> bool {
|
||||||
self.functions.iter().any(|(_, func)| func.integral)
|
self.functions.iter().any(|(_, func)| func.integral)
|
||||||
|
|||||||
@ -9,6 +9,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate uuid;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
mod function_entry;
|
mod function_entry;
|
||||||
mod function_manager;
|
mod function_manager;
|
||||||
|
|||||||
@ -7,6 +7,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate uuid;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
mod function_entry;
|
mod function_entry;
|
||||||
mod function_manager;
|
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.
|
/// 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>),
|
last_info: (Vec<Option<f64>>, Option<Duration>),
|
||||||
|
|
||||||
|
/// Whether or not dark mode is enabled
|
||||||
dark_mode: bool,
|
dark_mode: bool,
|
||||||
|
|
||||||
/// Stores opened windows/elements for later reference
|
/// Stores opened windows/elements for later reference
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user