mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-21 05:43:10 -07:00
Remake code in Rust
Implement the `CalculatorHistory` and `CalculatorManager` classes in Rust. * **CalculatorHistory.rs** - Implement the `CalculatorHistory` class in Rust. - Define the `HISTORYITEMVECTOR` and `HISTORYITEM` structs in Rust. - Implement methods for adding, removing, and retrieving history items. * **CalculatorManager.rs** - Implement the `CalculatorManager` class in Rust. - Define the `CalculatorMode`, `CalculatorPrecision`, and `MemoryCommand` enums in Rust. - Implement methods for managing calculator modes, memory operations, and history items. * **calc.rs** - Implement the `CCalcEngine` class in Rust. - Define constants and initialize various calculator settings. - Implement methods for handling calculator operations, memory management, and display updates.
This commit is contained in:
parent
1bc8b780c8
commit
f161afd968
26 changed files with 5702 additions and 0 deletions
270
src/CalcManager/CEngine/CalcInput.rs
Normal file
270
src/CalcManager/CEngine/CalcInput.rs
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
const MAX_STRLEN: usize = 84;
|
||||||
|
const C_NUM_MAX_DIGITS: usize = MAX_STRLEN;
|
||||||
|
const C_EXP_MAX_DIGITS: usize = 4;
|
||||||
|
|
||||||
|
pub struct CalcNumSec {
|
||||||
|
value: String,
|
||||||
|
is_negative: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalcNumSec {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
value: String::new(),
|
||||||
|
is_negative: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.value.clear();
|
||||||
|
self.is_negative = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.value.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative(&self) -> bool {
|
||||||
|
self.is_negative
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_negative(&mut self, is_negative: bool) {
|
||||||
|
self.is_negative = is_negative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CalcInput {
|
||||||
|
base: CalcNumSec,
|
||||||
|
exponent: CalcNumSec,
|
||||||
|
has_exponent: bool,
|
||||||
|
has_decimal: bool,
|
||||||
|
dec_pt_index: usize,
|
||||||
|
dec_symbol: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalcInput {
|
||||||
|
pub fn new(dec_symbol: char) -> Self {
|
||||||
|
Self {
|
||||||
|
base: CalcNumSec::new(),
|
||||||
|
exponent: CalcNumSec::new(),
|
||||||
|
has_exponent: false,
|
||||||
|
has_decimal: false,
|
||||||
|
dec_pt_index: 0,
|
||||||
|
dec_symbol,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.base.clear();
|
||||||
|
self.exponent.clear();
|
||||||
|
self.has_exponent = false;
|
||||||
|
self.has_decimal = false;
|
||||||
|
self.dec_pt_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_toggle_sign(&mut self, is_integer_mode: bool, max_num_str: &str) -> bool {
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.set_negative(false);
|
||||||
|
self.exponent.set_negative(false);
|
||||||
|
} else if self.has_exponent {
|
||||||
|
self.exponent.set_negative(!self.exponent.is_negative());
|
||||||
|
} else {
|
||||||
|
if is_integer_mode && self.base.is_negative() {
|
||||||
|
if self.base.value.len() >= max_num_str.len() && self.base.value.chars().last() > max_num_str.chars().last() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.base.set_negative(!self.base.is_negative());
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_add_digit(&mut self, value: u32, radix: u32, is_integer_mode: bool, max_num_str: &str, word_bit_width: i32, max_digits: usize) -> bool {
|
||||||
|
let ch_digit = if value < 10 {
|
||||||
|
(b'0' + value as u8) as char
|
||||||
|
} else {
|
||||||
|
(b'A' + value as u8 - 10) as char
|
||||||
|
};
|
||||||
|
|
||||||
|
let (p_num_sec, max_count) = if self.has_exponent {
|
||||||
|
(&mut self.exponent, C_EXP_MAX_DIGITS)
|
||||||
|
} else {
|
||||||
|
let mut max_count = max_digits;
|
||||||
|
if self.has_decimal {
|
||||||
|
max_count += 1;
|
||||||
|
}
|
||||||
|
if !self.base.is_empty() && self.base.value.starts_with('0') {
|
||||||
|
max_count += 1;
|
||||||
|
}
|
||||||
|
(&mut self.base, max_count)
|
||||||
|
};
|
||||||
|
|
||||||
|
if p_num_sec.is_empty() && value == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if p_num_sec.value.len() < max_count {
|
||||||
|
p_num_sec.value.push(ch_digit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_integer_mode && p_num_sec.value.len() == max_count && !self.has_exponent {
|
||||||
|
let allow_extra_digit = match radix {
|
||||||
|
8 => match word_bit_width % 3 {
|
||||||
|
1 => p_num_sec.value.starts_with('1'),
|
||||||
|
2 => p_num_sec.value.starts_with(|c| c <= '3'),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
10 => {
|
||||||
|
if p_num_sec.value.len() < max_num_str.len() {
|
||||||
|
match p_num_sec.value.cmp(&max_num_str[..p_num_sec.value.len()]) {
|
||||||
|
Ordering::Less => true,
|
||||||
|
Ordering::Equal => {
|
||||||
|
let last_char = max_num_str.chars().nth(p_num_sec.value.len()).unwrap();
|
||||||
|
ch_digit <= last_char || (p_num_sec.is_negative() && ch_digit <= last_char + 1)
|
||||||
|
}
|
||||||
|
Ordering::Greater => false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if allow_extra_digit {
|
||||||
|
p_num_sec.value.push(ch_digit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_add_decimal_pt(&mut self) -> bool {
|
||||||
|
if self.has_decimal || self.has_exponent {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.value.push('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dec_pt_index = self.base.value.len();
|
||||||
|
self.base.value.push(self.dec_symbol);
|
||||||
|
self.has_decimal = true;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_decimal_pt(&self) -> bool {
|
||||||
|
self.has_decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_begin_exponent(&mut self) -> bool {
|
||||||
|
self.try_add_decimal_pt();
|
||||||
|
|
||||||
|
if self.has_exponent {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.has_exponent = true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backspace(&mut self) {
|
||||||
|
if self.has_exponent {
|
||||||
|
if !self.exponent.is_empty() {
|
||||||
|
self.exponent.value.pop();
|
||||||
|
if self.exponent.is_empty() {
|
||||||
|
self.exponent.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.has_exponent = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !self.base.is_empty() {
|
||||||
|
self.base.value.pop();
|
||||||
|
if self.base.value == "0" {
|
||||||
|
self.base.value.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.value.len() <= self.dec_pt_index {
|
||||||
|
self.has_decimal = false;
|
||||||
|
self.dec_pt_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_decimal_symbol(&mut self, dec_symbol: char) {
|
||||||
|
if self.dec_symbol != dec_symbol {
|
||||||
|
self.dec_symbol = dec_symbol;
|
||||||
|
|
||||||
|
if self.has_decimal {
|
||||||
|
self.base.value.replace_range(self.dec_pt_index..=self.dec_pt_index, &dec_symbol.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.base.is_empty() && !self.has_exponent && self.exponent.is_empty() && !self.has_decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self, radix: u32) -> String {
|
||||||
|
if self.base.value.len() > MAX_STRLEN || (self.has_exponent && self.exponent.value.len() > MAX_STRLEN) {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
if self.base.is_negative() {
|
||||||
|
result.push('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
result.push('0');
|
||||||
|
} else {
|
||||||
|
result.push_str(&self.base.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.has_exponent {
|
||||||
|
if !self.has_decimal {
|
||||||
|
result.push(self.dec_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(if radix == 10 { 'e' } else { '^' });
|
||||||
|
result.push(if self.exponent.is_negative() { '-' } else { '+' });
|
||||||
|
|
||||||
|
if self.exponent.is_empty() {
|
||||||
|
result.push('0');
|
||||||
|
} else {
|
||||||
|
result.push_str(&self.exponent.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.len() > C_NUM_MAX_DIGITS * 2 + 4 {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_rational(&self, radix: u32, precision: i32) -> Rational {
|
||||||
|
let rat = string_to_rat(self.base.is_negative(), &self.base.value, self.exponent.is_negative(), &self.exponent.value, radix, precision);
|
||||||
|
if rat.is_none() {
|
||||||
|
return Rational::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = Rational::from_rat(rat.unwrap());
|
||||||
|
destroy_rat(rat.unwrap());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
292
src/CalcManager/CEngine/History.rs
Normal file
292
src/CalcManager/CEngine/History.rs
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::calc_engine::CCalcEngine;
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_history::IHistoryDisplay;
|
||||||
|
use crate::calc_utils::Rational;
|
||||||
|
|
||||||
|
const MAXPRECDEPTH: usize = 25;
|
||||||
|
|
||||||
|
pub struct CHistoryCollector {
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
i_cur_line_hist_start: i32,
|
||||||
|
last_op_start_index: i32,
|
||||||
|
last_bin_op_start_index: i32,
|
||||||
|
operand_indices: [i32; MAXPRECDEPTH],
|
||||||
|
cur_operand_index: i32,
|
||||||
|
b_last_opnd_brace: bool,
|
||||||
|
decimal_symbol: char,
|
||||||
|
sp_tokens: Option<Arc<Mutex<VecDeque<(String, i32)>>>>,
|
||||||
|
sp_commands: Option<Arc<Mutex<VecDeque<Arc<dyn IExpressionCommand>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CHistoryCollector {
|
||||||
|
pub fn new(
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
decimal_symbol: char,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
p_history_display,
|
||||||
|
p_calc_display,
|
||||||
|
i_cur_line_hist_start: -1,
|
||||||
|
last_op_start_index: -1,
|
||||||
|
last_bin_op_start_index: -1,
|
||||||
|
operand_indices: [-1; MAXPRECDEPTH],
|
||||||
|
cur_operand_index: 0,
|
||||||
|
b_last_opnd_brace: false,
|
||||||
|
decimal_symbol,
|
||||||
|
sp_tokens: None,
|
||||||
|
sp_commands: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_opnd_to_history(&mut self, num_str: &str, rat: &Rational, f_repetition: bool) {
|
||||||
|
let i_command_end = self.add_command(self.get_operand_commands_from_string(num_str, rat));
|
||||||
|
self.last_op_start_index = self.ich_add_sz_to_equation_sz(num_str, i_command_end);
|
||||||
|
|
||||||
|
if f_repetition {
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
self.b_last_opnd_brace = false;
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_last_opnd_from_history(&mut self) {
|
||||||
|
self.truncate_equation_sz_from_ich(self.last_op_start_index);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_bin_op_to_history(&mut self, n_op_code: i32, is_integer_mode: bool, f_no_repetition: bool) {
|
||||||
|
let i_command_end = self.add_command(Arc::new(CBinaryCommand::new(n_op_code)));
|
||||||
|
self.last_bin_op_start_index = self.ich_add_sz_to_equation_sz(" ", -1);
|
||||||
|
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_binary_string(n_op_code, is_integer_mode), i_command_end);
|
||||||
|
self.ich_add_sz_to_equation_sz(" ", -1);
|
||||||
|
|
||||||
|
if f_no_repetition {
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_last_bin_op(&mut self, n_op_code: i32, f_prec_inv_to_higher: bool, is_integer_mode: bool) {
|
||||||
|
self.truncate_equation_sz_from_ich(self.last_bin_op_start_index);
|
||||||
|
if f_prec_inv_to_higher {
|
||||||
|
self.enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
self.add_bin_op_to_history(n_op_code, is_integer_mode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_last_opnd_start(&mut self, ich_opnd_start: i32) {
|
||||||
|
let ich = if ich_opnd_start == -1 {
|
||||||
|
self.last_op_start_index
|
||||||
|
} else {
|
||||||
|
ich_opnd_start
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.cur_operand_index < self.operand_indices.len() as i32 {
|
||||||
|
self.operand_indices[self.cur_operand_index as usize] = ich;
|
||||||
|
self.cur_operand_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_last_opnd_start(&mut self) {
|
||||||
|
if self.cur_operand_index > 0 {
|
||||||
|
self.cur_operand_index -= 1;
|
||||||
|
self.last_op_start_index = self.operand_indices[self.cur_operand_index as usize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_open_brace_to_history(&mut self) {
|
||||||
|
self.add_command(Arc::new(CParentheses::new(IDC_OPENP)));
|
||||||
|
let ich_opnd_start = self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_OPENP), -1);
|
||||||
|
self.push_last_opnd_start(ich_opnd_start);
|
||||||
|
|
||||||
|
self.set_expression_display();
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_close_brace_to_history(&mut self) {
|
||||||
|
self.add_command(Arc::new(CParentheses::new(IDC_CLOSEP)));
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_CLOSEP), -1);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.pop_last_opnd_start();
|
||||||
|
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
self.b_last_opnd_brace = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enclose_prec_inversion_brackets(&mut self) {
|
||||||
|
let ich_start = if self.cur_operand_index > 0 {
|
||||||
|
self.operand_indices[self.cur_operand_index as usize - 1]
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
self.insert_sz_in_equation_sz(&CCalcEngine::op_code_to_string(IDC_OPENP), -1, ich_start);
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_CLOSEP), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f_opnd_added_to_history(&self) -> bool {
|
||||||
|
self.last_op_start_index != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complete_history_line(&mut self, num_str: &str) {
|
||||||
|
if let Some(p_history_display) = &self.p_history_display {
|
||||||
|
let added_item_index = p_history_display.add_to_history(
|
||||||
|
self.sp_tokens.clone().unwrap(),
|
||||||
|
self.sp_commands.clone().unwrap(),
|
||||||
|
num_str,
|
||||||
|
);
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.on_history_item_added(added_item_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sp_tokens = None;
|
||||||
|
self.sp_commands = None;
|
||||||
|
self.i_cur_line_hist_start = -1;
|
||||||
|
self.reinit_history();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complete_equation(&mut self, num_str: &str) {
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_EQU), -1);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.complete_history_line(num_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_history_line(&mut self, err_str: &str) {
|
||||||
|
if err_str.is_empty() {
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.set_expression_display(
|
||||||
|
Arc::new(Mutex::new(VecDeque::new())),
|
||||||
|
Arc::new(Mutex::new(VecDeque::new())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.i_cur_line_hist_start = -1;
|
||||||
|
self.reinit_history();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ich_add_sz_to_equation_sz(&mut self, str: &str, i_command_index: i32) -> i32 {
|
||||||
|
if self.sp_tokens.is_none() {
|
||||||
|
self.sp_tokens = Some(Arc::new(Mutex::new(VecDeque::new())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_tokens.push_back((str.to_string(), i_command_index));
|
||||||
|
(sp_tokens.len() - 1) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_sz_in_equation_sz(&mut self, str: &str, i_command_index: i32, ich: i32) {
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_tokens.insert(ich as usize, (str.to_string(), i_command_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate_equation_sz_from_ich(&mut self, ich: i32) {
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
let mut sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
|
||||||
|
let mut min_idx = -1;
|
||||||
|
let n_tokens = sp_tokens.len();
|
||||||
|
|
||||||
|
for i in ich as usize..n_tokens {
|
||||||
|
let cur_token_id = sp_tokens[i].1;
|
||||||
|
if cur_token_id != -1 {
|
||||||
|
if min_idx == -1 || cur_token_id < min_idx {
|
||||||
|
min_idx = cur_token_id;
|
||||||
|
sp_commands.truncate(min_idx as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_tokens.truncate(ich as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_expression_display(&self) {
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.set_expression_display(
|
||||||
|
self.sp_tokens.clone().unwrap(),
|
||||||
|
self.sp_commands.clone().unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_command(&mut self, sp_command: Arc<dyn IExpressionCommand>) -> i32 {
|
||||||
|
if self.sp_commands.is_none() {
|
||||||
|
self.sp_commands = Some(Arc::new(Mutex::new(VecDeque::new())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_commands.push_back(sp_command);
|
||||||
|
(sp_commands.len() - 1) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_history_expression(&mut self, radix: u32, precision: i32) {
|
||||||
|
if self.sp_tokens.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
let sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
|
||||||
|
for token in sp_tokens.iter_mut() {
|
||||||
|
let command_position = token.1;
|
||||||
|
if command_position != -1 {
|
||||||
|
let exp_command = &sp_commands[command_position as usize];
|
||||||
|
if exp_command.get_command_type() == CommandType::OperandCommand {
|
||||||
|
let opnd_command = exp_command.as_any().downcast_ref::<COpndCommand>().unwrap();
|
||||||
|
token.0 = opnd_command.get_string(radix, precision);
|
||||||
|
opnd_command.set_commands(self.get_operand_commands_from_string(&token.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_decimal_symbol(&mut self, decimal_symbol: char) {
|
||||||
|
self.decimal_symbol = decimal_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_operand_commands_from_string(&self, num_str: &str) -> Arc<dyn IExpressionCommand> {
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
let f_negative = num_str.starts_with('-');
|
||||||
|
|
||||||
|
for ch in num_str.chars().skip(if f_negative { 1 } else { 0 }) {
|
||||||
|
match ch {
|
||||||
|
ch if ch == self.decimal_symbol => commands.push(IDC_PNT),
|
||||||
|
'e' => commands.push(IDC_EXP),
|
||||||
|
'-' => commands.push(IDC_SIGN),
|
||||||
|
'+' => {}
|
||||||
|
ch => {
|
||||||
|
let num = ch as i32 - '0' as i32;
|
||||||
|
commands.push(num + IDC_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f_negative {
|
||||||
|
commands.push(IDC_SIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::new(COpndCommand::new(commands, f_negative, num_str.contains(self.decimal_symbol), num_str.contains('e')))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reinit_history(&mut self) {
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
self.cur_operand_index = 0;
|
||||||
|
self.b_last_opnd_brace = false;
|
||||||
|
if let Some(sp_tokens) = &self.sp_tokens {
|
||||||
|
sp_tokens.lock().unwrap().clear();
|
||||||
|
}
|
||||||
|
if let Some(sp_commands) = &self.sp_commands {
|
||||||
|
sp_commands.lock().unwrap().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
src/CalcManager/CEngine/Number.rs
Normal file
79
src/CalcManager/CEngine/Number.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
pub struct Number {
|
||||||
|
sign: i32,
|
||||||
|
exp: i32,
|
||||||
|
mantissa: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Number {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
sign: 1,
|
||||||
|
exp: 0,
|
||||||
|
mantissa: vec![0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_values(sign: i32, exp: i32, mantissa: Vec<u32>) -> Self {
|
||||||
|
Self { sign, exp, mantissa }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pnumber(p: &PNUMBER) -> Self {
|
||||||
|
let mut mantissa = Vec::with_capacity(p.cdigit as usize);
|
||||||
|
mantissa.extend_from_slice(&p.mant[..p.cdigit as usize]);
|
||||||
|
Self {
|
||||||
|
sign: p.sign,
|
||||||
|
exp: p.exp,
|
||||||
|
mantissa,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pnumber(&self) -> PNUMBER {
|
||||||
|
let mut ret = PNUMBER::new(self.mantissa.len() + 1);
|
||||||
|
ret.sign = self.sign;
|
||||||
|
ret.exp = self.exp;
|
||||||
|
ret.cdigit = self.mantissa.len() as i32;
|
||||||
|
ret.mant[..self.mantissa.len()].copy_from_slice(&self.mantissa);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(&self) -> i32 {
|
||||||
|
self.sign
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exp(&self) -> i32 {
|
||||||
|
self.exp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mantissa(&self) -> &Vec<u32> {
|
||||||
|
&self.mantissa
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_zero(&self) -> bool {
|
||||||
|
self.mantissa.iter().all(|&x| x == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Number {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.sign == other.sign && self.exp == other.exp && self.mantissa == other.mantissa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Number {}
|
||||||
|
|
||||||
|
impl PartialOrd for Number {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Number {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.sign
|
||||||
|
.cmp(&other.sign)
|
||||||
|
.then_with(|| self.exp.cmp(&other.exp))
|
||||||
|
.then_with(|| self.mantissa.cmp(&other.mantissa))
|
||||||
|
}
|
||||||
|
}
|
378
src/CalcManager/CEngine/Rational.rs
Normal file
378
src/CalcManager/CEngine/Rational.rs
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
pub struct Rational {
|
||||||
|
p: Number,
|
||||||
|
q: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rational {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::new(),
|
||||||
|
q: Number::with_values(1, 0, vec![1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_number(n: &Number) -> Self {
|
||||||
|
let mut q_exp = 0;
|
||||||
|
if n.exp() < 0 {
|
||||||
|
q_exp -= n.exp();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
p: Number::with_values(n.sign(), 0, n.mantissa().clone()),
|
||||||
|
q: Number::with_values(1, q_exp, vec![1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_values(p: Number, q: Number) -> Self {
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_i32(i: i32) -> Self {
|
||||||
|
let prat = i32torat(i);
|
||||||
|
let p = Number::from_pnumber(&prat.pp);
|
||||||
|
let q = Number::from_pnumber(&prat.pq);
|
||||||
|
destroyrat(prat);
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u32(ui: u32) -> Self {
|
||||||
|
let prat = ui32torat(ui);
|
||||||
|
let p = Number::from_pnumber(&prat.pp);
|
||||||
|
let q = Number::from_pnumber(&prat.pq);
|
||||||
|
destroyrat(prat);
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u64(ui: u64) -> Self {
|
||||||
|
let hi = (ui >> 32) as u32;
|
||||||
|
let lo = ui as u32;
|
||||||
|
let temp = Rational::from_u32(hi) << 32 | Rational::from_u32(lo);
|
||||||
|
Self {
|
||||||
|
p: temp.p,
|
||||||
|
q: temp.q,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_prat(prat: &PRAT) -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::from_pnumber(&prat.pp),
|
||||||
|
q: Number::from_pnumber(&prat.pq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_prat(&self) -> PRAT {
|
||||||
|
let mut ret = PRAT::new();
|
||||||
|
ret.pp = self.p.to_pnumber();
|
||||||
|
ret.pq = self.q.to_pnumber();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn p(&self) -> &Number {
|
||||||
|
&self.p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn q(&self) -> &Number {
|
||||||
|
&self.q
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negate(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::with_values(-self.p.sign(), self.p.exp(), self.p.mantissa().clone()),
|
||||||
|
q: self.q.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
addrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
subrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
mulrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
divrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rem_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
remrat(&mut lhs_rat, &rhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shl_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
lshrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shr_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
rshrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
andrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
orrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xor_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
xorrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self, radix: u32, fmt: NumberFormat, precision: i32) -> String {
|
||||||
|
let rat = self.to_prat();
|
||||||
|
let result = rat_to_string(&rat, fmt, radix, precision);
|
||||||
|
destroyrat(rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_u64(&self) -> u64 {
|
||||||
|
let rat = self.to_prat();
|
||||||
|
let result = rat_to_u64(&rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Rational {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = other.to_prat();
|
||||||
|
let result = rat_equ(&lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Rational {}
|
||||||
|
|
||||||
|
impl PartialOrd for Rational {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Rational {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
let lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = other.to_prat();
|
||||||
|
let result = rat_cmp(&lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::AddAssign for Rational {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.add_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::SubAssign for Rational {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.sub_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::MulAssign for Rational {
|
||||||
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
|
self.mul_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DivAssign for Rational {
|
||||||
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
|
self.div_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::RemAssign for Rational {
|
||||||
|
fn rem_assign(&mut self, rhs: Self) {
|
||||||
|
self.rem_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::ShlAssign for Rational {
|
||||||
|
fn shl_assign(&mut self, rhs: Self) {
|
||||||
|
self.shl_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::ShrAssign for Rational {
|
||||||
|
fn shr_assign(&mut self, rhs: Self) {
|
||||||
|
self.shr_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitAndAssign for Rational {
|
||||||
|
fn bitand_assign(&mut self, rhs: Self) {
|
||||||
|
self.and_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOrAssign for Rational {
|
||||||
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
|
self.or_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitXorAssign for Rational {
|
||||||
|
fn bitxor_assign(&mut self, rhs: Self) {
|
||||||
|
self.xor_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
self.negate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.add_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.sub_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.mul_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Div for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.div_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Rem for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn rem(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.rem_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Shl for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn shl(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.shl_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Shr for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn shr(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.shr_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitAnd for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitand(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.and_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOr for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.or_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitXor for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitxor(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.xor_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
234
src/CalcManager/CEngine/calc.rs
Normal file
234
src/CalcManager/CEngine/calc.rs
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::calc_input::CalcInput;
|
||||||
|
use crate::calc_utils::{Rational, RationalMath};
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_history::CHistoryCollector;
|
||||||
|
use crate::calc_resource::IResourceProvider;
|
||||||
|
|
||||||
|
const DEFAULT_MAX_DIGITS: i32 = 32;
|
||||||
|
const DEFAULT_PRECISION: i32 = 32;
|
||||||
|
const DEFAULT_RADIX: i32 = 10;
|
||||||
|
|
||||||
|
const DEFAULT_DEC_SEPARATOR: char = '.';
|
||||||
|
const DEFAULT_GRP_SEPARATOR: char = ',';
|
||||||
|
const DEFAULT_GRP_STR: &str = "3;0";
|
||||||
|
const DEFAULT_NUMBER_STR: &str = "0";
|
||||||
|
|
||||||
|
pub struct CCalcEngine {
|
||||||
|
f_precedence: bool,
|
||||||
|
f_integer_mode: bool,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
resource_provider: Arc<dyn IResourceProvider>,
|
||||||
|
n_op_code: i32,
|
||||||
|
n_prev_op_code: i32,
|
||||||
|
b_change_op: bool,
|
||||||
|
b_record: bool,
|
||||||
|
b_set_calc_state: bool,
|
||||||
|
input: CalcInput,
|
||||||
|
n_fe: NumberFormat,
|
||||||
|
memory_value: Rational,
|
||||||
|
hold_val: Rational,
|
||||||
|
current_val: Rational,
|
||||||
|
last_val: Rational,
|
||||||
|
paren_vals: Vec<Rational>,
|
||||||
|
precedence_vals: Vec<Rational>,
|
||||||
|
b_error: bool,
|
||||||
|
b_inv: bool,
|
||||||
|
b_no_prev_equ: bool,
|
||||||
|
radix: i32,
|
||||||
|
precision: i32,
|
||||||
|
c_int_digits_sav: i32,
|
||||||
|
dec_grouping: Vec<i32>,
|
||||||
|
number_string: String,
|
||||||
|
n_temp_com: i32,
|
||||||
|
open_paren_count: usize,
|
||||||
|
n_op: Vec<i32>,
|
||||||
|
n_prec_op: Vec<i32>,
|
||||||
|
precedence_op_count: usize,
|
||||||
|
n_last_com: i32,
|
||||||
|
angletype: AngleType,
|
||||||
|
numwidth: NUM_WIDTH,
|
||||||
|
dw_word_bit_width: i32,
|
||||||
|
history_collector: CHistoryCollector,
|
||||||
|
group_separator: char,
|
||||||
|
chop_numbers: Vec<Rational>,
|
||||||
|
max_decimal_value_strings: Vec<String>,
|
||||||
|
decimal_separator: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CCalcEngine {
|
||||||
|
pub fn new(
|
||||||
|
f_precedence: bool,
|
||||||
|
f_integer_mode: bool,
|
||||||
|
resource_provider: Arc<dyn IResourceProvider>,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut engine = CCalcEngine {
|
||||||
|
f_precedence,
|
||||||
|
f_integer_mode,
|
||||||
|
p_calc_display: p_calc_display.clone(),
|
||||||
|
resource_provider: resource_provider.clone(),
|
||||||
|
n_op_code: 0,
|
||||||
|
n_prev_op_code: 0,
|
||||||
|
b_change_op: false,
|
||||||
|
b_record: false,
|
||||||
|
b_set_calc_state: false,
|
||||||
|
input: CalcInput::new(DEFAULT_DEC_SEPARATOR),
|
||||||
|
n_fe: NumberFormat::Float,
|
||||||
|
memory_value: Rational::default(),
|
||||||
|
hold_val: Rational::default(),
|
||||||
|
current_val: Rational::default(),
|
||||||
|
last_val: Rational::default(),
|
||||||
|
paren_vals: vec![Rational::default(); MAXPRECDEPTH],
|
||||||
|
precedence_vals: vec![Rational::default(); MAXPRECDEPTH],
|
||||||
|
b_error: false,
|
||||||
|
b_inv: false,
|
||||||
|
b_no_prev_equ: true,
|
||||||
|
radix: DEFAULT_RADIX,
|
||||||
|
precision: DEFAULT_PRECISION,
|
||||||
|
c_int_digits_sav: DEFAULT_MAX_DIGITS,
|
||||||
|
dec_grouping: vec![],
|
||||||
|
number_string: DEFAULT_NUMBER_STR.to_string(),
|
||||||
|
n_temp_com: 0,
|
||||||
|
open_paren_count: 0,
|
||||||
|
n_op: vec![0; MAXPRECDEPTH],
|
||||||
|
n_prec_op: vec![0; MAXPRECDEPTH],
|
||||||
|
precedence_op_count: 0,
|
||||||
|
n_last_com: 0,
|
||||||
|
angletype: AngleType::Degrees,
|
||||||
|
numwidth: NUM_WIDTH::QWORD_WIDTH,
|
||||||
|
dw_word_bit_width: 0,
|
||||||
|
history_collector: CHistoryCollector::new(p_calc_display, p_history_display, DEFAULT_DEC_SEPARATOR),
|
||||||
|
group_separator: DEFAULT_GRP_SEPARATOR,
|
||||||
|
chop_numbers: vec![Rational::default(); NUM_WIDTH_LENGTH],
|
||||||
|
max_decimal_value_strings: vec![String::new(); NUM_WIDTH_LENGTH],
|
||||||
|
decimal_separator: DEFAULT_DEC_SEPARATOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
engine.init_chop_numbers();
|
||||||
|
engine.dw_word_bit_width = engine.dw_word_bit_width_from_num_width(engine.numwidth);
|
||||||
|
engine.max_trigonometric_num = RationalMath::pow(10, 100);
|
||||||
|
engine.set_radix_type_and_num_width(RadixType::Decimal, engine.numwidth);
|
||||||
|
engine.settings_changed();
|
||||||
|
engine.display_num();
|
||||||
|
|
||||||
|
engine
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_chop_numbers(&mut self) {
|
||||||
|
self.chop_numbers[0] = Rational::from_rat(rat_qword);
|
||||||
|
self.chop_numbers[1] = Rational::from_rat(rat_dword);
|
||||||
|
self.chop_numbers[2] = Rational::from_rat(rat_word);
|
||||||
|
self.chop_numbers[3] = Rational::from_rat(rat_byte);
|
||||||
|
|
||||||
|
for i in 0..self.chop_numbers.len() {
|
||||||
|
let max_val = self.chop_numbers[i] / 2;
|
||||||
|
let max_val = RationalMath::integer(max_val);
|
||||||
|
self.max_decimal_value_strings[i] = max_val.to_string(10, NumberFormat::Float, self.precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_chop_number(&self) -> Rational {
|
||||||
|
self.chop_numbers[self.numwidth as usize].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_max_decimal_value_string(&self) -> String {
|
||||||
|
self.max_decimal_value_strings[self.numwidth as usize].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn persisted_mem_object(&self) -> Rational {
|
||||||
|
self.memory_value.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_persisted_mem_object(&mut self, mem_object: Rational) {
|
||||||
|
self.memory_value = mem_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn settings_changed(&mut self) {
|
||||||
|
let last_dec = self.decimal_separator;
|
||||||
|
let dec_str = self.resource_provider.get_cengine_string("sDecimal");
|
||||||
|
self.decimal_separator = if dec_str.is_empty() {
|
||||||
|
DEFAULT_DEC_SEPARATOR
|
||||||
|
} else {
|
||||||
|
dec_str.chars().next().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_sep = self.group_separator;
|
||||||
|
let sep_str = self.resource_provider.get_cengine_string("sThousand");
|
||||||
|
self.group_separator = if sep_str.is_empty() {
|
||||||
|
DEFAULT_GRP_SEPARATOR
|
||||||
|
} else {
|
||||||
|
sep_str.chars().next().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_dec_grouping = self.dec_grouping.clone();
|
||||||
|
let grp_str = self.resource_provider.get_cengine_string("sGrouping");
|
||||||
|
self.dec_grouping = if grp_str.is_empty() {
|
||||||
|
digit_grouping_string_to_grouping_vector(DEFAULT_GRP_STR)
|
||||||
|
} else {
|
||||||
|
digit_grouping_string_to_grouping_vector(&grp_str)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut num_changed = false;
|
||||||
|
|
||||||
|
if self.dec_grouping != last_dec_grouping || self.group_separator != last_sep {
|
||||||
|
num_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.decimal_separator != last_dec {
|
||||||
|
self.input.set_decimal_symbol(self.decimal_separator);
|
||||||
|
self.history_collector.set_decimal_symbol(self.decimal_separator);
|
||||||
|
s_engine_strings.insert(SIDS_DECIMAL_SEPARATOR.to_string(), self.decimal_separator.to_string());
|
||||||
|
num_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if num_changed {
|
||||||
|
self.display_num();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decimal_separator(&self) -> char {
|
||||||
|
self.decimal_separator
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_collector_commands_snapshot(&self) -> Vec<Arc<dyn IExpressionCommand>> {
|
||||||
|
let mut commands = self.history_collector.get_commands();
|
||||||
|
if !self.history_collector.f_opnd_added_to_history() && self.b_record {
|
||||||
|
commands.push(self.history_collector.get_operand_commands_from_string(&self.number_string, &self.current_val));
|
||||||
|
}
|
||||||
|
commands
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initial_one_time_only_setup(resource_provider: Arc<dyn IResourceProvider>) {
|
||||||
|
Self::load_engine_strings(resource_provider);
|
||||||
|
Self::change_base_constants(DEFAULT_RADIX, DEFAULT_MAX_DIGITS, DEFAULT_PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_engine_strings(resource_provider: Arc<dyn IResourceProvider>) {
|
||||||
|
for sid in G_SIDS.iter() {
|
||||||
|
let loc_string = resource_provider.get_cengine_string(sid);
|
||||||
|
if !loc_string.is_empty() {
|
||||||
|
s_engine_strings.insert(sid.to_string(), loc_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_base_constants(radix: i32, max_int_digits: i32, precision: i32) {
|
||||||
|
// Implementation of ChangeBaseConstants
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_num(&self) {
|
||||||
|
// Implementation of DisplayNum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_radix_type_and_num_width(&mut self, radix_type: RadixType, num_width: NUM_WIDTH) {
|
||||||
|
// Implementation of SetRadixTypeAndNumWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dw_word_bit_width_from_num_width(&self, num_width: NUM_WIDTH) -> i32 {
|
||||||
|
// Implementation of DwWordBitWidthFromNumWidth
|
||||||
|
}
|
||||||
|
}
|
774
src/CalcManager/CEngine/scicomm.rs
Normal file
774
src/CalcManager/CEngine/scicomm.rs
Normal file
|
@ -0,0 +1,774 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ENGINE_STRINGS: Mutex<HashMap<&'static str, String>> = Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_engine_strings(resource_provider: &dyn ResourceProvider) {
|
||||||
|
let sids = vec![
|
||||||
|
"SIDS_SIND", "SIDS_ASIND", "SIDS_SINR", "SIDS_ASINR", "SIDS_SING", "SIDS_ASING",
|
||||||
|
"SIDS_COSD", "SIDS_ACOSD", "SIDS_COSR", "SIDS_ACOSR", "SIDS_COSG", "SIDS_ACOSG",
|
||||||
|
"SIDS_TAND", "SIDS_ATAND", "SIDS_TANR", "SIDS_ATANR", "SIDS_TANG", "SIDS_ATANG",
|
||||||
|
"SIDS_SQR", "SIDS_CUBE", "SIDS_FACT", "SIDS_RECIPROC", "SIDS_DEGREES", "SIDS_NEGATE",
|
||||||
|
"SIDS_TWOPOWX", "SIDS_LOGBASEY", "SIDS_ABS", "SIDS_CEIL", "SIDS_FLOOR", "SIDS_NAND",
|
||||||
|
"SIDS_NOR", "SIDS_RSH", "SIDS_ROR", "SIDS_ROL", "SIDS_CUBEROOT", "SIDS_MOD",
|
||||||
|
"SIDS_PROGRAMMER_MOD", "SIDS_FRAC", "SIDS_ASINH", "SIDS_ACOSH", "SIDS_ATANH",
|
||||||
|
"SIDS_SECH", "SIDS_ASECH", "SIDS_CSCH", "SIDS_ACSCH", "SIDS_COTH", "SIDS_ACOTH",
|
||||||
|
"SIDS_POWE"
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut engine_strings = ENGINE_STRINGS.lock().unwrap();
|
||||||
|
for sid in sids {
|
||||||
|
if let Some(loc_string) = resource_provider.get_cengine_string(sid) {
|
||||||
|
engine_strings.insert(sid, loc_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial_one_time_only_setup(resource_provider: &dyn ResourceProvider) {
|
||||||
|
load_engine_strings(resource_provider);
|
||||||
|
change_base_constants(DEFAULT_RADIX, DEFAULT_MAX_DIGITS, DEFAULT_PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error_command(idc: OpCode) {
|
||||||
|
if !is_gui_setting_op_code(idc) {
|
||||||
|
// We would have saved the prev command. Need to forget this state
|
||||||
|
TEMP_COM.store(LAST_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_max_digits_reached(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.max_digits_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_temporary_values(calc_display: &dyn CalcDisplay) {
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
INPUT.lock().unwrap().clear();
|
||||||
|
RECORD.store(true, Ordering::SeqCst);
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
display_num(calc_display);
|
||||||
|
ERROR.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_display(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.set_expression_display(vec![], vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command(calc_display: &dyn CalcDisplay, resource_provider: &dyn ResourceProvider, w_param: OpCode) {
|
||||||
|
let mut w_param = w_param;
|
||||||
|
if w_param == OpCode::SetResult {
|
||||||
|
w_param = OpCode::Recall;
|
||||||
|
SET_CALC_STATE.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_command_worker(calc_display, resource_provider, w_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command_worker(calc_display: &dyn CalcDisplay, resource_provider: &dyn ResourceProvider, w_param: OpCode) {
|
||||||
|
if !is_gui_setting_op_code(w_param) {
|
||||||
|
LAST_COM.store(TEMP_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
clear_display(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
if w_param == OpCode::Clear {
|
||||||
|
// handle "C" normally
|
||||||
|
} else if w_param == OpCode::Centr {
|
||||||
|
// treat "CE" as "C"
|
||||||
|
w_param = OpCode::Clear;
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
if is_bin_op_code(w_param) || is_unary_op_code(w_param) || is_op_in_range(w_param, OpCode::Fe, OpCode::MMinus)
|
||||||
|
|| is_op_in_range(w_param, OpCode::OpenP, OpCode::CloseP) || is_op_in_range(w_param, OpCode::Hex, OpCode::Bin)
|
||||||
|
|| is_op_in_range(w_param, OpCode::Qword, OpCode::Byte) || is_op_in_range(w_param, OpCode::Deg, OpCode::Grad)
|
||||||
|
|| is_op_in_range(w_param, OpCode::BinEditStart, OpCode::BinEditEnd) || w_param == OpCode::Inv
|
||||||
|
|| (w_param == OpCode::Sign && RADIX.load(Ordering::SeqCst) != 10) || w_param == OpCode::Rand
|
||||||
|
|| w_param == OpCode::Euler {
|
||||||
|
RECORD.store(false, Ordering::SeqCst);
|
||||||
|
CURRENT_VAL.store(INPUT.lock().unwrap().to_rational(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
} else if is_digit_op_code(w_param) || w_param == OpCode::Pnt {
|
||||||
|
RECORD.store(true, Ordering::SeqCst);
|
||||||
|
INPUT.lock().unwrap().clear();
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_digit_op_code(w_param) {
|
||||||
|
let i_value = w_param as u32 - OpCode::Digit0 as u32;
|
||||||
|
|
||||||
|
if i_value >= RADIX.load(Ordering::SeqCst) {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !INPUT.lock().unwrap().try_add_digit(i_value, RADIX.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst), get_max_decimal_value_string(), WORD_BIT_WIDTH.load(Ordering::SeqCst), INT_DIGITS_SAV.load(Ordering::SeqCst)) {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
handle_max_digits_reached(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(w_param) {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
let mut f_prec_inv_to_higher = false;
|
||||||
|
|
||||||
|
OPCODE.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
|
||||||
|
if PRECEDENCE.load(Ordering::SeqCst) && PREV_OPCODE.load(Ordering::SeqCst) != 0 {
|
||||||
|
let n_prev = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(LAST_COM.load(Ordering::SeqCst));
|
||||||
|
let ni = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if nx <= n_prev && ni > n_prev {
|
||||||
|
f_prec_inv_to_higher = true;
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
change_last_bin_op(OPCODE.load(Ordering::SeqCst), f_prec_inv_to_higher, INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
display_announce_binary_operator(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
loop {
|
||||||
|
let nx = precedence_of_op(w_param as i32);
|
||||||
|
let ni = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
|
||||||
|
if nx > ni && PRECEDENCE.load(Ordering::SeqCst) {
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) < MAX_PREC_DEPTH {
|
||||||
|
PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = LAST_VAL.load(Ordering::SeqCst);
|
||||||
|
PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = OPCODE.load(Ordering::SeqCst);
|
||||||
|
push_last_opnd_start();
|
||||||
|
} else {
|
||||||
|
PRECEDENCE_OP_COUNT.store(MAX_PREC_DEPTH - 1, Ordering::SeqCst);
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
if !PRECEDENCE.load(Ordering::SeqCst) {
|
||||||
|
let grouped_string = group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst));
|
||||||
|
complete_equation(grouped_string);
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) != 0 && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_announce_binary_operator(calc_display);
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
OPCODE.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
add_bin_op_to_history(OPCODE.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(true, Ordering::SeqCst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_unary_op_code(w_param) || w_param == OpCode::Degrees {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param != OpCode::Percent {
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
add_unary_op_to_history(w_param as i32, INV.load(Ordering::SeqCst), ANGLE_TYPE.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param == OpCode::Sin || w_param == OpCode::Cos || w_param == OpCode::Tan || w_param == OpCode::Sinh
|
||||||
|
|| w_param == OpCode::Cosh || w_param == OpCode::Tanh || w_param == OpCode::Sec || w_param == OpCode::Csc
|
||||||
|
|| w_param == OpCode::Cot || w_param == OpCode::Sech || w_param == OpCode::Csch || w_param == OpCode::Coth {
|
||||||
|
if is_current_too_big_for_trig() {
|
||||||
|
CURRENT_VAL.store(0, Ordering::SeqCst);
|
||||||
|
display_error(calc_display, CALC_E_DOMAIN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(sci_calc_functions(CURRENT_VAL.load(Ordering::SeqCst), w_param as u32), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
|
||||||
|
if w_param == OpCode::Percent {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if INV.load(Ordering::SeqCst) && (w_param == OpCode::Chop || w_param == OpCode::Sin || w_param == OpCode::Cos
|
||||||
|
|| w_param == OpCode::Tan || w_param == OpCode::Ln || w_param == OpCode::Dms || w_param == OpCode::Degrees
|
||||||
|
|| w_param == OpCode::Sinh || w_param == OpCode::Cosh || w_param == OpCode::Tanh || w_param == OpCode::Sec
|
||||||
|
|| w_param == OpCode::Csc || w_param == OpCode::Cot || w_param == OpCode::Sech || w_param == OpCode::Csch
|
||||||
|
|| w_param == OpCode::Coth) {
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_op_in_range(w_param, OpCode::BinEditStart, OpCode::BinEditEnd) {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
|
||||||
|
if try_toggle_bit(CURRENT_VAL.load(Ordering::SeqCst), w_param as u32 - OpCode::BinEditStart as u32) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match w_param {
|
||||||
|
OpCode::Clear => {
|
||||||
|
if !CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAST_VAL.store(0, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
OPEN_PAREN_COUNT.store(0, Ordering::SeqCst);
|
||||||
|
PRECEDENCE_OP_COUNT.store(0, Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(0, Ordering::SeqCst);
|
||||||
|
LAST_COM.store(0, Ordering::SeqCst);
|
||||||
|
OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
CARRY_BIT.store(0, Ordering::SeqCst);
|
||||||
|
|
||||||
|
calc_display.set_parenthesis_number(0);
|
||||||
|
clear_display(calc_display);
|
||||||
|
|
||||||
|
clear_history_line();
|
||||||
|
clear_temporary_values(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Centr => {
|
||||||
|
clear_temporary_values(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Back => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
INPUT.lock().unwrap().backspace();
|
||||||
|
display_num(calc_display);
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpCode::Equ => {
|
||||||
|
while OPEN_PAREN_COUNT.load(Ordering::SeqCst) > 0 {
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TEMP_COM.store(LAST_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
process_command(calc_display, resource_provider, OpCode::CloseP);
|
||||||
|
LAST_COM.store(TEMP_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_highest_precedence_operation(calc_display);
|
||||||
|
while PRECEDENCE.load(Ordering::SeqCst) && PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) > 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
let ni = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
resolve_highest_precedence_operation(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
let grouped_string = group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst));
|
||||||
|
complete_equation(grouped_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
OpCode::OpenP | OpCode::CloseP => {
|
||||||
|
if (OPEN_PAREN_COUNT.load(Ordering::SeqCst) >= MAX_PREC_DEPTH && w_param == OpCode::OpenP)
|
||||||
|
|| (OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 && w_param != OpCode::OpenP)
|
||||||
|
|| (PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) >= MAX_PREC_DEPTH && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0) {
|
||||||
|
if OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 && w_param != OpCode::OpenP {
|
||||||
|
calc_display.on_no_right_paren_added();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_error_command(w_param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param == OpCode::OpenP {
|
||||||
|
if is_digit_op_code(LAST_COM.load(Ordering::SeqCst)) || is_unary_op_code(LAST_COM.load(Ordering::SeqCst))
|
||||||
|
|| LAST_COM.load(Ordering::SeqCst) == OpCode::Pnt || LAST_COM.load(Ordering::SeqCst) == OpCode::CloseP {
|
||||||
|
process_command(calc_display, resource_provider, OpCode::Mul);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
add_open_brace_to_history();
|
||||||
|
|
||||||
|
PAREN_VALS.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)] = LAST_VAL.load(Ordering::SeqCst);
|
||||||
|
OPCODE.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)] = if CHANGE_OP.load(Ordering::SeqCst) { OPCODE.load(Ordering::SeqCst) } else { 0 };
|
||||||
|
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) < PREC_OP.lock().unwrap().len() {
|
||||||
|
PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
LAST_VAL.store(0, Ordering::SeqCst);
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
TEMP_COM.store(0, Ordering::SeqCst);
|
||||||
|
OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
while PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) > 0 && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
let ni = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_close_brace_to_history();
|
||||||
|
|
||||||
|
OPEN_PAREN_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PAREN_VALS.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
OPCODE.store(OPCODE.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
CHANGE_OP.store(OPCODE.load(Ordering::SeqCst) != 0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
calc_display.set_parenthesis_number(OPEN_PAREN_COUNT.load(Ordering::SeqCst));
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpCode::Hex | OpCode::Dec | OpCode::Oct | OpCode::Bin => {
|
||||||
|
set_radix_type_and_num_width(w_param as i32 - OpCode::Hex as i32, -1);
|
||||||
|
update_history_expression(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
OpCode::Qword | OpCode::Dword | OpCode::Word | OpCode::Byte => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
CURRENT_VAL.store(INPUT.lock().unwrap().to_rational(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
RECORD.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_radix_type_and_num_width(-1, w_param as i32 - OpCode::Qword as i32);
|
||||||
|
}
|
||||||
|
OpCode::Deg | OpCode::Rad | OpCode::Grad => {
|
||||||
|
ANGLE_TYPE.store(w_param as i32 - OpCode::Deg as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
OpCode::Sign => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
if INPUT.lock().unwrap().try_toggle_sign(INTEGER_MODE.load(Ordering::SeqCst), get_max_decimal_value_string()) {
|
||||||
|
display_num(calc_display);
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(-CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
add_unary_op_to_history(OpCode::Sign as i32, INV.load(Ordering::SeqCst), ANGLE_TYPE.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
OpCode::Recall => {
|
||||||
|
if SET_CALC_STATE.load(Ordering::SeqCst) {
|
||||||
|
SET_CALC_STATE.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(*MEMORY_VALUE.lock().unwrap(), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::MPlus => {
|
||||||
|
let result = *MEMORY_VALUE.lock().unwrap() + CURRENT_VAL.load(Ordering::SeqCst);
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = truncate_num_for_int_math(result);
|
||||||
|
}
|
||||||
|
OpCode::MMinus => {
|
||||||
|
let result = *MEMORY_VALUE.lock().unwrap() - CURRENT_VAL.load(Ordering::SeqCst);
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = truncate_num_for_int_math(result);
|
||||||
|
}
|
||||||
|
OpCode::Store | OpCode::MClear => {
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = if w_param == OpCode::Store { truncate_num_for_int_math(CURRENT_VAL.load(Ordering::SeqCst)) } else { 0 };
|
||||||
|
}
|
||||||
|
OpCode::Pi => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
CURRENT_VAL.store(if INV.load(Ordering::SeqCst) { TWO_PI } else { PI }, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Rand => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
let mut str = String::new();
|
||||||
|
write!(str, "{:.precision$}", generate_random_number(), precision = PRECISION.load(Ordering::SeqCst)).unwrap();
|
||||||
|
let rat = string_to_rat(false, &str, false, "", RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst));
|
||||||
|
CURRENT_VAL.store(if let Some(rat) = rat { rat } else { 0 }, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Euler => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
CURRENT_VAL.store(RAT_EXP, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Fe => {
|
||||||
|
let n_fe = if N_FE.load(Ordering::SeqCst) == NumberFormat::Float { NumberFormat::Scientific } else { NumberFormat::Float };
|
||||||
|
N_FE.store(n_fe, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Exp => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) && !INTEGER_MODE.load(Ordering::SeqCst) && INPUT.lock().unwrap().try_begin_exponent() {
|
||||||
|
display_num(calc_display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Pnt => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) && !INTEGER_MODE.load(Ordering::SeqCst) && INPUT.lock().unwrap().try_add_decimal_pt() {
|
||||||
|
display_num(calc_display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Inv => {
|
||||||
|
INV.store(!INV.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_highest_precedence_operation(calc_display: &dyn CalcDisplay) {
|
||||||
|
if OPCODE.load(Ordering::SeqCst) != 0 {
|
||||||
|
if NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
HOLD_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(HOLD_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
add_bin_op_to_history(OPCODE.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_PREV_EQU.store(false, Ordering::SeqCst);
|
||||||
|
} else if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_and_add_last_bin_op_to_history(add_to_history: bool) {
|
||||||
|
if CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
if opnd_added_to_history() {
|
||||||
|
remove_last_opnd_from_history();
|
||||||
|
}
|
||||||
|
} else if opnd_added_to_history() && !ERROR.load(Ordering::SeqCst) {
|
||||||
|
if (is_unary_op_code(LAST_COM.load(Ordering::SeqCst)) || LAST_COM.load(Ordering::SeqCst) == OpCode::Sign as i32 || LAST_COM.load(Ordering::SeqCst) == OpCode::CloseP as i32) && OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 {
|
||||||
|
if add_to_history {
|
||||||
|
complete_history_line(group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remove_last_opnd_from_history();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_primary_display(calc_display: &dyn CalcDisplay, sz_text: &str, is_error: bool) {
|
||||||
|
calc_display.set_primary_display(sz_text, is_error);
|
||||||
|
calc_display.set_is_in_error(is_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_announce_binary_operator(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.binary_operator_received();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precedence_of_op(nop_code: i32) -> i32 {
|
||||||
|
match nop_code {
|
||||||
|
OpCode::Or as i32 | OpCode::Xor as i32 => 0,
|
||||||
|
OpCode::And as i32 | OpCode::Nand as i32 | OpCode::Nor as i32 => 1,
|
||||||
|
OpCode::Add as i32 | OpCode::Sub as i32 => 2,
|
||||||
|
OpCode::Lshf as i32 | OpCode::Rshf as i32 | OpCode::Rshfl as i32 | OpCode::Mod as i32 | OpCode::Div as i32 | OpCode::Mul as i32 => 3,
|
||||||
|
OpCode::Pwr as i32 | OpCode::Root as i32 | OpCode::LogBaseY as i32 => 4,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_gui_setting_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Hex | OpCode::Dec | OpCode::Oct | OpCode::Bin | OpCode::Qword | OpCode::Dword | OpCode::Word | OpCode::Byte | OpCode::Deg | OpCode::Rad | OpCode::Grad | OpCode::Inv | OpCode::Fe | OpCode::MClear | OpCode::Back | OpCode::Exp | OpCode::Store | OpCode::MPlus | OpCode::MMinus)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_bin_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::And | OpCode::Or | OpCode::Xor | OpCode::Nand | OpCode::Nor | OpCode::Add | OpCode::Sub | OpCode::Lshf | OpCode::Rshf | OpCode::Rshfl | OpCode::Mod | OpCode::Div | OpCode::Mul | OpCode::Pwr | OpCode::Root | OpCode::LogBaseY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unary_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Chop | OpCode::Sin | OpCode::Cos | OpCode::Tan | OpCode::Ln | OpCode::Dms | OpCode::Degrees | OpCode::Sinh | OpCode::Cosh | OpCode::Tanh | OpCode::Sec | OpCode::Csc | OpCode::Cot | OpCode::Sech | OpCode::Csch | OpCode::Coth | OpCode::Sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_digit_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Digit0 | OpCode::Digit1 | OpCode::Digit2 | OpCode::Digit3 | OpCode::Digit4 | OpCode::Digit5 | OpCode::Digit6 | OpCode::Digit7 | OpCode::Digit8 | OpCode::Digit9 | OpCode::DigitA | OpCode::DigitB | OpCode::DigitC | OpCode::DigitD | OpCode::DigitE | OpCode::DigitF)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_op_in_range(op_code: OpCode, start: OpCode, end: OpCode) -> bool {
|
||||||
|
(op_code as i32) >= (start as i32) && (op_code as i32) <= (end as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sci_calc_functions(current_val: Rational, w_param: u32) -> Rational {
|
||||||
|
// Implement the scientific calculator functions here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_operation(op_code: i32, lhs: Rational, rhs: Rational) -> Rational {
|
||||||
|
// Implement the operation logic here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
lhs + rhs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_num(calc_display: &dyn CalcDisplay) {
|
||||||
|
// Implement the display logic here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
calc_display.set_primary_display("0", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_and_add_last_bin_op_to_history() {
|
||||||
|
// Implement the logic to check and add the last binary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_opnd_to_history(num_str: String, rat: Rational) {
|
||||||
|
// Implement the logic to add operand to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_last_bin_op(op_code: i32, f_prec_inv_to_higher: bool, is_integer_mode: bool) {
|
||||||
|
// Implement the logic to change the last binary operator
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_digits_per_radix(num_str: String, radix: u32) -> String {
|
||||||
|
// Implement the logic to group digits per radix
|
||||||
|
// This is a placeholder implementation
|
||||||
|
num_str
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_equation(grouped_string: String) {
|
||||||
|
// Implement the logic to complete the equation
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_last_opnd_from_history() {
|
||||||
|
// Implement the logic to remove the last operand from history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_bin_op_to_history(op_code: i32, is_integer_mode: bool) {
|
||||||
|
// Implement the logic to add binary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_unary_op_to_history(op_code: i32, inv: bool, angle_type: i32) {
|
||||||
|
// Implement the logic to add unary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_current_too_big_for_trig() -> bool {
|
||||||
|
// Implement the logic to check if the current value is too big for trigonometric functions
|
||||||
|
// This is a placeholder implementation
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_error(calc_display: &dyn CalcDisplay, error_code: u32) {
|
||||||
|
// Implement the logic to display error
|
||||||
|
// This is a placeholder implementation
|
||||||
|
calc_display.set_primary_display("Error", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_radix_type_and_num_width(radix_type: i32, num_width: i32) {
|
||||||
|
// Implement the logic to set radix type and number width
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_history_expression(radix: u32, precision: u32) {
|
||||||
|
// Implement the logic to update history expression
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_last_opnd_start() {
|
||||||
|
// Implement the logic to push the last operand start
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_last_opnd_start() {
|
||||||
|
// Implement the logic to pop the last operand start
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enclose_prec_inversion_brackets() {
|
||||||
|
// Implement the logic to enclose precedence inversion brackets
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_open_brace_to_history() {
|
||||||
|
// Implement the logic to add open brace to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_close_brace_to_history() {
|
||||||
|
// Implement the logic to add close brace to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate_num_for_int_math(num: Rational) -> Rational {
|
||||||
|
// Implement the logic to truncate number for integer math
|
||||||
|
// This is a placeholder implementation
|
||||||
|
num
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_random_number() -> f64 {
|
||||||
|
// Implement the logic to generate a random number
|
||||||
|
// This is a placeholder implementation
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_to_rat(negative: bool, num_str: &str, exp_negative: bool, exp_str: &str, radix: u32, precision: u32) -> Option<Rational> {
|
||||||
|
// Implement the logic to convert string to rational
|
||||||
|
// This is a placeholder implementation
|
||||||
|
Some(Rational::new(0, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_max_decimal_value_string() -> String {
|
||||||
|
// Implement the logic to get the maximum decimal value string
|
||||||
|
// This is a placeholder implementation
|
||||||
|
"0".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_toggle_bit(current_val: Rational, bit: u32) -> bool {
|
||||||
|
// Implement the logic to try toggling a bit
|
||||||
|
// This is a placeholder implementation
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_history_line() {
|
||||||
|
// Implement the logic to clear the history line
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opnd_added_to_history() -> bool {
|
||||||
|
// Implement the logic to check if operand is added to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_history_line(grouped_string: String) {
|
||||||
|
// Implement the logic to complete the history line
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
203
src/CalcManager/CEngine/scidisp.rs
Normal file
203
src/CalcManager/CEngine/scidisp.rs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ENGINE_STRINGS: Mutex<HashMap<&'static str, String>> = Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_EXPONENT: usize = 4;
|
||||||
|
const MAX_GROUPING_SIZE: u32 = 16;
|
||||||
|
const DEC_PRE_SEP_STR: &str = "[+-]?(\\d*)[";
|
||||||
|
const DEC_POST_SEP_STR: &str = "]?(\\d*)(?:e[+-]?(\\d*))?$";
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
struct LastDisp {
|
||||||
|
value: Rational,
|
||||||
|
precision: i32,
|
||||||
|
radix: u32,
|
||||||
|
nfe: i32,
|
||||||
|
numwidth: NumWidth,
|
||||||
|
int_math: bool,
|
||||||
|
record: bool,
|
||||||
|
use_sep: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut GLD_PREVIOUS: LastDisp = LastDisp {
|
||||||
|
value: Rational::new(0, 1),
|
||||||
|
precision: -1,
|
||||||
|
radix: 0,
|
||||||
|
nfe: -1,
|
||||||
|
numwidth: NumWidth::Qword,
|
||||||
|
int_math: false,
|
||||||
|
record: false,
|
||||||
|
use_sep: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl CCalcEngine {
|
||||||
|
fn truncate_num_for_int_math(&self, rat: Rational) -> Rational {
|
||||||
|
if !self.integer_mode {
|
||||||
|
return rat;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = RationalMath::integer(rat);
|
||||||
|
|
||||||
|
if result < Rational::new(0, 1) {
|
||||||
|
let mut result = -(result) - Rational::new(1, 1);
|
||||||
|
result ^= self.get_chop_number();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result & self.get_chop_number()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_num(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if self.record
|
||||||
|
|| GLD_PREVIOUS.value != self.current_val
|
||||||
|
|| GLD_PREVIOUS.precision != self.precision
|
||||||
|
|| GLD_PREVIOUS.radix != self.radix
|
||||||
|
|| GLD_PREVIOUS.nfe != self.nfe
|
||||||
|
|| !GLD_PREVIOUS.use_sep
|
||||||
|
|| GLD_PREVIOUS.numwidth != self.numwidth
|
||||||
|
|| GLD_PREVIOUS.int_math != self.integer_mode
|
||||||
|
|| GLD_PREVIOUS.record != self.record
|
||||||
|
{
|
||||||
|
GLD_PREVIOUS.precision = self.precision;
|
||||||
|
GLD_PREVIOUS.radix = self.radix;
|
||||||
|
GLD_PREVIOUS.nfe = self.nfe;
|
||||||
|
GLD_PREVIOUS.numwidth = self.numwidth;
|
||||||
|
GLD_PREVIOUS.int_math = self.integer_mode;
|
||||||
|
GLD_PREVIOUS.record = self.record;
|
||||||
|
GLD_PREVIOUS.use_sep = true;
|
||||||
|
|
||||||
|
if self.record {
|
||||||
|
self.number_string = self.input.to_string(self.radix);
|
||||||
|
} else {
|
||||||
|
if self.integer_mode {
|
||||||
|
self.current_val = self.truncate_num_for_int_math(self.current_val);
|
||||||
|
}
|
||||||
|
self.number_string = self.get_string_for_display(self.current_val, self.radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLD_PREVIOUS.value = self.current_val;
|
||||||
|
|
||||||
|
if self.radix == 10 && self.is_number_invalid(&self.number_string, MAX_EXPONENT, self.precision, self.radix) {
|
||||||
|
self.display_error(CALC_E_OVERFLOW);
|
||||||
|
} else {
|
||||||
|
self.set_primary_display(self.group_digits_per_radix(&self.number_string, self.radix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_number_invalid(&self, number_string: &str, max_exp: usize, max_mantissa: i32, radix: u32) -> bool {
|
||||||
|
if radix == 10 {
|
||||||
|
let regex_str = format!("{}{}{}", DEC_PRE_SEP_STR, self.decimal_separator, DEC_POST_SEP_STR);
|
||||||
|
let re = Regex::new(®ex_str).unwrap();
|
||||||
|
if let Some(caps) = re.captures(number_string) {
|
||||||
|
if caps.get(3).map_or(0, |m| m.as_str().len()) > max_exp {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
let exp = caps.get(1).map_or("", |m| m.as_str());
|
||||||
|
let int_itr = exp.chars().skip_while(|&c| c == '0');
|
||||||
|
let i_mantissa = int_itr.clone().count() + caps.get(2).map_or(0, |m| m.as_str().len());
|
||||||
|
if i_mantissa > max_mantissa as usize {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for c in number_string.chars() {
|
||||||
|
if radix == 16 {
|
||||||
|
if !c.is_digit(16) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if c < '0' || c >= (b'0' + radix as u8) as char {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn digit_grouping_string_to_grouping_vector(grouping_string: &str) -> Vec<u32> {
|
||||||
|
let mut grouping = Vec::new();
|
||||||
|
let mut current_group = 0;
|
||||||
|
let mut next = grouping_string;
|
||||||
|
while let Some((group, rest)) = next.split_once(';') {
|
||||||
|
current_group = group.parse().unwrap_or(0);
|
||||||
|
if current_group < MAX_GROUPING_SIZE {
|
||||||
|
grouping.push(current_group);
|
||||||
|
}
|
||||||
|
next = rest;
|
||||||
|
}
|
||||||
|
current_group = next.parse().unwrap_or(0);
|
||||||
|
if current_group < MAX_GROUPING_SIZE {
|
||||||
|
grouping.push(current_group);
|
||||||
|
}
|
||||||
|
grouping
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_digits_per_radix(&self, number_string: &str, radix: u32) -> String {
|
||||||
|
if number_string.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
match radix {
|
||||||
|
10 => self.group_digits(&self.group_separator, &self.dec_grouping, number_string, number_string.starts_with('-')),
|
||||||
|
8 => self.group_digits(" ", &[3, 0], number_string, false),
|
||||||
|
2 | 16 => self.group_digits(" ", &[4, 0], number_string, false),
|
||||||
|
_ => number_string.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_digits(&self, delimiter: &str, grouping: &[u32], display_string: &str, is_num_negative: bool) -> String {
|
||||||
|
if delimiter.is_empty() || grouping.is_empty() {
|
||||||
|
return display_string.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let exp = display_string.find('e');
|
||||||
|
let has_exponent = exp.is_some();
|
||||||
|
|
||||||
|
let dec = display_string.find(self.decimal_separator);
|
||||||
|
let has_decimal = dec.is_some();
|
||||||
|
|
||||||
|
let ritr = if has_decimal {
|
||||||
|
display_string[..dec.unwrap()].chars().rev()
|
||||||
|
} else if has_exponent {
|
||||||
|
display_string[..exp.unwrap()].chars().rev()
|
||||||
|
} else {
|
||||||
|
display_string.chars().rev()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut grouping_size = 0;
|
||||||
|
|
||||||
|
let mut group_itr = grouping.iter();
|
||||||
|
let mut curr_grouping = *group_itr.next().unwrap_or(&0);
|
||||||
|
|
||||||
|
for c in ritr {
|
||||||
|
result.push(c);
|
||||||
|
grouping_size += 1;
|
||||||
|
|
||||||
|
if curr_grouping != 0 && grouping_size % curr_grouping == 0 {
|
||||||
|
result.push_str(delimiter);
|
||||||
|
grouping_size = 0;
|
||||||
|
|
||||||
|
if let Some(&next_group) = group_itr.next() {
|
||||||
|
curr_grouping = next_group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_num_negative {
|
||||||
|
result.push(display_string.chars().next().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
result.chars().rev().collect::<String>() + &display_string[dec.unwrap_or(display_string.len())..]
|
||||||
|
}
|
||||||
|
}
|
255
src/CalcManager/CEngine/scifunc.rs
Normal file
255
src/CalcManager/CEngine/scifunc.rs
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
use crate::calc_engine::CalcEngine;
|
||||||
|
use crate::rational::Rational;
|
||||||
|
use crate::rational_math::{self, RationalMath};
|
||||||
|
use crate::winerror_cross_platform::CALC_E_DOMAIN;
|
||||||
|
use std::ops::Neg;
|
||||||
|
|
||||||
|
impl CalcEngine {
|
||||||
|
pub fn sci_calc_functions(&mut self, rat: Rational, op: u32) -> Rational {
|
||||||
|
let mut result = Rational::default();
|
||||||
|
match op {
|
||||||
|
IDC_CHOP => {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::frac(rat)
|
||||||
|
} else {
|
||||||
|
RationalMath::integer(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
IDC_COM => {
|
||||||
|
if self.radix == 10 && !self.integer_mode {
|
||||||
|
result = -(RationalMath::integer(rat) + 1);
|
||||||
|
} else {
|
||||||
|
result = rat ^ self.get_chop_number();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_ROL | IDC_ROLC => {
|
||||||
|
if self.integer_mode {
|
||||||
|
result = RationalMath::integer(rat);
|
||||||
|
let mut w64_bits = result.to_u64();
|
||||||
|
let msb = (w64_bits >> (self.word_bit_width - 1)) & 1;
|
||||||
|
w64_bits <<= 1;
|
||||||
|
if op == IDC_ROL {
|
||||||
|
w64_bits |= msb;
|
||||||
|
} else {
|
||||||
|
w64_bits |= self.carry_bit;
|
||||||
|
self.carry_bit = msb;
|
||||||
|
}
|
||||||
|
result = Rational::from_u64(w64_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_ROR | IDC_RORC => {
|
||||||
|
if self.integer_mode {
|
||||||
|
result = RationalMath::integer(rat);
|
||||||
|
let mut w64_bits = result.to_u64();
|
||||||
|
let lsb = (w64_bits & 0x01) == 1;
|
||||||
|
w64_bits >>= 1;
|
||||||
|
if op == IDC_ROR {
|
||||||
|
w64_bits |= (lsb as u64) << (self.word_bit_width - 1);
|
||||||
|
} else {
|
||||||
|
w64_bits |= (self.carry_bit as u64) << (self.word_bit_width - 1);
|
||||||
|
self.carry_bit = lsb as u64;
|
||||||
|
}
|
||||||
|
result = Rational::from_u64(w64_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_PERCENT => {
|
||||||
|
if self.op_code == IDC_MUL || self.op_code == IDC_DIV {
|
||||||
|
result = rat / 100;
|
||||||
|
} else {
|
||||||
|
result = rat * (self.last_val / 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_SIN => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::asin(rat, self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::sin(rat, self.angle_type)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_SINH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::asinh(rat)
|
||||||
|
} else {
|
||||||
|
RationalMath::sinh(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_COS => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::acos(rat, self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::cos(rat, self.angle_type)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_COSH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::acosh(rat)
|
||||||
|
} else {
|
||||||
|
RationalMath::cosh(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_TAN => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::atan(rat, self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::tan(rat, self.angle_type)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_TANH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::atanh(rat)
|
||||||
|
} else {
|
||||||
|
RationalMath::tanh(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_SEC => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::acos(RationalMath::invert(rat), self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::cos(rat, self.angle_type))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_CSC => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::asin(RationalMath::invert(rat), self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::sin(rat, self.angle_type))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_COT => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::atan(RationalMath::invert(rat), self.angle_type)
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::tan(rat, self.angle_type))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_SECH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::acosh(RationalMath::invert(rat))
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::cosh(rat))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_CSCH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::asinh(RationalMath::invert(rat))
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::sinh(rat))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_COTH => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::atanh(RationalMath::invert(rat))
|
||||||
|
} else {
|
||||||
|
RationalMath::invert(RationalMath::tanh(rat))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_REC => {
|
||||||
|
result = RationalMath::invert(rat);
|
||||||
|
}
|
||||||
|
IDC_SQR => {
|
||||||
|
result = RationalMath::pow(rat, 2);
|
||||||
|
}
|
||||||
|
IDC_SQRT => {
|
||||||
|
result = RationalMath::root(rat, 2);
|
||||||
|
}
|
||||||
|
IDC_CUBEROOT | IDC_CUB => {
|
||||||
|
result = if op == IDC_CUBEROOT {
|
||||||
|
RationalMath::root(rat, 3)
|
||||||
|
} else {
|
||||||
|
RationalMath::pow(rat, 3)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
IDC_LOG => {
|
||||||
|
result = RationalMath::log10(rat);
|
||||||
|
}
|
||||||
|
IDC_POW10 => {
|
||||||
|
result = RationalMath::pow(10, rat);
|
||||||
|
}
|
||||||
|
IDC_POW2 => {
|
||||||
|
result = RationalMath::pow(2, rat);
|
||||||
|
}
|
||||||
|
IDC_LN => {
|
||||||
|
result = if self.inv {
|
||||||
|
RationalMath::exp(rat)
|
||||||
|
} else {
|
||||||
|
RationalMath::log(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
IDC_FAC => {
|
||||||
|
result = RationalMath::fact(rat);
|
||||||
|
}
|
||||||
|
IDC_DEGREES => {
|
||||||
|
self.process_command(IDC_INV);
|
||||||
|
// This case falls through to IDC_DMS case because in the old Win32 Calc,
|
||||||
|
// the degrees functionality was achieved as 'Inv' of 'dms' operation,
|
||||||
|
// so setting the IDC_INV command first and then performing 'dms' operation as global variables m_bInv, m_bRecord
|
||||||
|
// are set properly through process_command(IDC_INV)
|
||||||
|
result = self.sci_calc_functions(rat, IDC_DMS);
|
||||||
|
}
|
||||||
|
IDC_DMS => {
|
||||||
|
if !self.integer_mode {
|
||||||
|
let shft_rat = if self.inv { 100 } else { 60 };
|
||||||
|
let degree_rat = RationalMath::integer(rat);
|
||||||
|
let mut minute_rat = (rat - degree_rat) * shft_rat;
|
||||||
|
let mut second_rat = minute_rat;
|
||||||
|
minute_rat = RationalMath::integer(minute_rat);
|
||||||
|
second_rat = (second_rat - minute_rat) * shft_rat;
|
||||||
|
let shft_rat = if self.inv { 60 } else { 100 };
|
||||||
|
second_rat /= shft_rat;
|
||||||
|
minute_rat = (minute_rat + second_rat) / shft_rat;
|
||||||
|
result = degree_rat + minute_rat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_CEIL => {
|
||||||
|
result = if RationalMath::frac(rat) > 0 {
|
||||||
|
RationalMath::integer(rat + 1)
|
||||||
|
} else {
|
||||||
|
RationalMath::integer(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
IDC_FLOOR => {
|
||||||
|
result = if RationalMath::frac(rat) < 0 {
|
||||||
|
RationalMath::integer(rat - 1)
|
||||||
|
} else {
|
||||||
|
RationalMath::integer(rat)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
IDC_ABS => {
|
||||||
|
result = RationalMath::abs(rat);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_error(&mut self, n_error: u32) {
|
||||||
|
let error_string = self.get_string(IDS_ERRORS_FIRST + SCODE_CODE(n_error));
|
||||||
|
self.set_primary_display(&error_string, true);
|
||||||
|
self.error = true;
|
||||||
|
self.history_collector.clear_history_line(&error_string);
|
||||||
|
}
|
||||||
|
}
|
101
src/CalcManager/CEngine/scioper.rs
Normal file
101
src/CalcManager/CEngine/scioper.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use crate::calc_engine::CalcEngine;
|
||||||
|
use crate::rational::Rational;
|
||||||
|
use crate::rational_math::{self, RationalMath};
|
||||||
|
use crate::winerror_cross_platform::CALC_E_NORESULT;
|
||||||
|
|
||||||
|
impl CalcEngine {
|
||||||
|
pub fn do_operation(&mut self, operation: i32, lhs: Rational, rhs: Rational) -> Rational {
|
||||||
|
let mut result = if lhs != Rational::default() { lhs } else { Rational::default() };
|
||||||
|
|
||||||
|
match operation {
|
||||||
|
IDC_AND => result &= rhs,
|
||||||
|
IDC_OR => result |= rhs,
|
||||||
|
IDC_XOR => result ^= rhs,
|
||||||
|
IDC_NAND => result = (result & rhs) ^ self.get_chop_number(),
|
||||||
|
IDC_NOR => result = (result | rhs) ^ self.get_chop_number(),
|
||||||
|
IDC_RSHF => {
|
||||||
|
if self.integer_mode && result >= self.word_bit_width {
|
||||||
|
return self.display_error(CALC_E_NORESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut w64_bits = rhs.to_u64();
|
||||||
|
let f_msb = (w64_bits >> (self.word_bit_width - 1)) & 1;
|
||||||
|
|
||||||
|
let hold_val = result;
|
||||||
|
result = rhs >> hold_val;
|
||||||
|
|
||||||
|
if f_msb != 0 {
|
||||||
|
result = RationalMath::integer(result);
|
||||||
|
|
||||||
|
let mut temp_rat = self.get_chop_number() >> hold_val;
|
||||||
|
temp_rat = RationalMath::integer(temp_rat);
|
||||||
|
|
||||||
|
result |= temp_rat ^ self.get_chop_number();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_RSHFL => {
|
||||||
|
if self.integer_mode && result >= self.word_bit_width {
|
||||||
|
return self.display_error(CALC_E_NORESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = rhs >> result;
|
||||||
|
}
|
||||||
|
IDC_LSHF => {
|
||||||
|
if self.integer_mode && result >= self.word_bit_width {
|
||||||
|
return self.display_error(CALC_E_NORESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = rhs << result;
|
||||||
|
}
|
||||||
|
IDC_ADD => result += rhs,
|
||||||
|
IDC_SUB => result = rhs - result,
|
||||||
|
IDC_MUL => result *= rhs,
|
||||||
|
IDC_DIV | IDC_MOD => {
|
||||||
|
let mut i_numerator_sign = 1;
|
||||||
|
let mut i_denominator_sign = 1;
|
||||||
|
let mut temp = result;
|
||||||
|
result = rhs;
|
||||||
|
|
||||||
|
if self.integer_mode {
|
||||||
|
let mut w64_bits = rhs.to_u64();
|
||||||
|
let f_msb = (w64_bits >> (self.word_bit_width - 1)) & 1;
|
||||||
|
|
||||||
|
if f_msb != 0 {
|
||||||
|
result = (rhs ^ self.get_chop_number()) + 1;
|
||||||
|
i_numerator_sign = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
w64_bits = temp.to_u64();
|
||||||
|
let f_msb = (w64_bits >> (self.word_bit_width - 1)) & 1;
|
||||||
|
|
||||||
|
if f_msb != 0 {
|
||||||
|
temp = (temp ^ self.get_chop_number()) + 1;
|
||||||
|
i_denominator_sign = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if operation == IDC_DIV {
|
||||||
|
result /= temp;
|
||||||
|
if self.integer_mode && (i_numerator_sign * i_denominator_sign) == -1 {
|
||||||
|
result = -RationalMath::integer(result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.integer_mode {
|
||||||
|
result %= temp;
|
||||||
|
if i_numerator_sign == -1 {
|
||||||
|
result = -RationalMath::integer(result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = RationalMath::modulus(result, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_PWR => result = RationalMath::pow(rhs, result),
|
||||||
|
IDC_ROOT => result = RationalMath::root(rhs, result),
|
||||||
|
IDC_LOGBASEY => result = RationalMath::log(rhs) / RationalMath::log(result),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
768
src/CalcManager/CEngine/sciset.rs
Normal file
768
src/CalcManager/CEngine/sciset.rs
Normal file
|
@ -0,0 +1,768 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SETTINGS: Mutex<HashMap<&'static str, String>> = Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_settings(resource_provider: &dyn ResourceProvider) {
|
||||||
|
let sids = vec![
|
||||||
|
"SIDS_DECIMAL_SEPARATOR", "SIDS_GROUP_SEPARATOR", "SIDS_GROUPING", "SIDS_MAX_DIGITS",
|
||||||
|
"SIDS_PRECISION", "SIDS_RADIX", "SIDS_NUMBER_FORMAT", "SIDS_ANGLE_TYPE", "SIDS_NUM_WIDTH",
|
||||||
|
"SIDS_INTEGER_MODE", "SIDS_RECORD", "SIDS_USE_SEPARATOR"
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut settings = SETTINGS.lock().unwrap();
|
||||||
|
for sid in sids {
|
||||||
|
if let Some(loc_string) = resource_provider.get_cengine_string(sid) {
|
||||||
|
settings.insert(sid, loc_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial_one_time_only_setup(resource_provider: &dyn ResourceProvider) {
|
||||||
|
load_settings(resource_provider);
|
||||||
|
change_base_constants(DEFAULT_RADIX, DEFAULT_MAX_DIGITS, DEFAULT_PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error_command(idc: OpCode) {
|
||||||
|
if !is_gui_setting_op_code(idc) {
|
||||||
|
// We would have saved the prev command. Need to forget this state
|
||||||
|
TEMP_COM.store(LAST_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_max_digits_reached(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.max_digits_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_temporary_values(calc_display: &dyn CalcDisplay) {
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
INPUT.lock().unwrap().clear();
|
||||||
|
RECORD.store(true, Ordering::SeqCst);
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
display_num(calc_display);
|
||||||
|
ERROR.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_display(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.set_expression_display(vec![], vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command(calc_display: &dyn CalcDisplay, resource_provider: &dyn ResourceProvider, w_param: OpCode) {
|
||||||
|
let mut w_param = w_param;
|
||||||
|
if w_param == OpCode::SetResult {
|
||||||
|
w_param = OpCode::Recall;
|
||||||
|
SET_CALC_STATE.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_command_worker(calc_display, resource_provider, w_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command_worker(calc_display: &dyn CalcDisplay, resource_provider: &dyn ResourceProvider, w_param: OpCode) {
|
||||||
|
if !is_gui_setting_op_code(w_param) {
|
||||||
|
LAST_COM.store(TEMP_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
clear_display(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
if w_param == OpCode::Clear {
|
||||||
|
// handle "C" normally
|
||||||
|
} else if w_param == OpCode::Centr {
|
||||||
|
// treat "CE" as "C"
|
||||||
|
w_param = OpCode::Clear;
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
if is_bin_op_code(w_param) || is_unary_op_code(w_param) || is_op_in_range(w_param, OpCode::Fe, OpCode::MMinus)
|
||||||
|
|| is_op_in_range(w_param, OpCode::OpenP, OpCode::CloseP) || is_op_in_range(w_param, OpCode::Hex, OpCode::Bin)
|
||||||
|
|| is_op_in_range(w_param, OpCode::Qword, OpCode::Byte) || is_op_in_range(w_param, OpCode::Deg, OpCode::Grad)
|
||||||
|
|| is_op_in_range(w_param, OpCode::BinEditStart, OpCode::BinEditEnd) || w_param == OpCode::Inv
|
||||||
|
|| (w_param == OpCode::Sign && RADIX.load(Ordering::SeqCst) != 10) || w_param == OpCode::Rand
|
||||||
|
|| w_param == OpCode::Euler {
|
||||||
|
RECORD.store(false, Ordering::SeqCst);
|
||||||
|
CURRENT_VAL.store(INPUT.lock().unwrap().to_rational(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
} else if is_digit_op_code(w_param) || w_param == OpCode::Pnt {
|
||||||
|
RECORD.store(true, Ordering::SeqCst);
|
||||||
|
INPUT.lock().unwrap().clear();
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_digit_op_code(w_param) {
|
||||||
|
let i_value = w_param as u32 - OpCode::Digit0 as u32;
|
||||||
|
|
||||||
|
if i_value >= RADIX.load(Ordering::SeqCst) {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !INPUT.lock().unwrap().try_add_digit(i_value, RADIX.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst), get_max_decimal_value_string(), WORD_BIT_WIDTH.load(Ordering::SeqCst), INT_DIGITS_SAV.load(Ordering::SeqCst)) {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
handle_max_digits_reached(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(w_param) {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
let mut f_prec_inv_to_higher = false;
|
||||||
|
|
||||||
|
OPCODE.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
|
||||||
|
if PRECEDENCE.load(Ordering::SeqCst) && PREV_OPCODE.load(Ordering::SeqCst) != 0 {
|
||||||
|
let n_prev = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(LAST_COM.load(Ordering::SeqCst));
|
||||||
|
let ni = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if nx <= n_prev && ni > n_prev {
|
||||||
|
f_prec_inv_to_higher = true;
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
change_last_bin_op(OPCODE.load(Ordering::SeqCst), f_prec_inv_to_higher, INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
display_announce_binary_operator(calc_display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
loop {
|
||||||
|
let nx = precedence_of_op(w_param as i32);
|
||||||
|
let ni = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
|
||||||
|
if nx > ni && PRECEDENCE.load(Ordering::SeqCst) {
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) < MAX_PREC_DEPTH {
|
||||||
|
PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = LAST_VAL.load(Ordering::SeqCst);
|
||||||
|
PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = OPCODE.load(Ordering::SeqCst);
|
||||||
|
push_last_opnd_start();
|
||||||
|
} else {
|
||||||
|
PRECEDENCE_OP_COUNT.store(MAX_PREC_DEPTH - 1, Ordering::SeqCst);
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
if !PRECEDENCE.load(Ordering::SeqCst) {
|
||||||
|
let grouped_string = group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst));
|
||||||
|
complete_equation(grouped_string);
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) != 0 && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_announce_binary_operator(calc_display);
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
OPCODE.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
add_bin_op_to_history(OPCODE.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(true, Ordering::SeqCst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_unary_op_code(w_param) || w_param == OpCode::Degrees {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param != OpCode::Percent {
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
add_unary_op_to_history(w_param as i32, INV.load(Ordering::SeqCst), ANGLE_TYPE.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param == OpCode::Sin || w_param == OpCode::Cos || w_param == OpCode::Tan || w_param == OpCode::Sinh
|
||||||
|
|| w_param == OpCode::Cosh || w_param == OpCode::Tanh || w_param == OpCode::Sec || w_param == OpCode::Csc
|
||||||
|
|| w_param == OpCode::Cot || w_param == OpCode::Sech || w_param == OpCode::Csch || w_param == OpCode::Coth {
|
||||||
|
if is_current_too_big_for_trig() {
|
||||||
|
CURRENT_VAL.store(0, Ordering::SeqCst);
|
||||||
|
display_error(calc_display, CALC_E_DOMAIN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(sci_calc_functions(CURRENT_VAL.load(Ordering::SeqCst), w_param as u32), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
|
||||||
|
if w_param == OpCode::Percent {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if INV.load(Ordering::SeqCst) && (w_param == OpCode::Chop || w_param == OpCode::Sin || w_param == OpCode::Cos
|
||||||
|
|| w_param == OpCode::Tan || w_param == OpCode::Ln || w_param == OpCode::Dms || w_param == OpCode::Degrees
|
||||||
|
|| w_param == OpCode::Sinh || w_param == OpCode::Cosh || w_param == OpCode::Tanh || w_param == OpCode::Sec
|
||||||
|
|| w_param == OpCode::Csc || w_param == OpCode::Cot || w_param == OpCode::Sech || w_param == OpCode::Csch
|
||||||
|
|| w_param == OpCode::Coth) {
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_op_in_range(w_param, OpCode::BinEditStart, OpCode::BinEditEnd) {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
|
||||||
|
if try_toggle_bit(CURRENT_VAL.load(Ordering::SeqCst), w_param as u32 - OpCode::BinEditStart as u32) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match w_param {
|
||||||
|
OpCode::Clear => {
|
||||||
|
if !CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAST_VAL.store(0, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
OPEN_PAREN_COUNT.store(0, Ordering::SeqCst);
|
||||||
|
PRECEDENCE_OP_COUNT.store(0, Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(0, Ordering::SeqCst);
|
||||||
|
LAST_COM.store(0, Ordering::SeqCst);
|
||||||
|
OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
CARRY_BIT.store(0, Ordering::SeqCst);
|
||||||
|
|
||||||
|
calc_display.set_parenthesis_number(0);
|
||||||
|
clear_display(calc_display);
|
||||||
|
|
||||||
|
clear_history_line();
|
||||||
|
clear_temporary_values(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Centr => {
|
||||||
|
clear_temporary_values(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Back => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
INPUT.lock().unwrap().backspace();
|
||||||
|
display_num(calc_display);
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpCode::Equ => {
|
||||||
|
while OPEN_PAREN_COUNT.load(Ordering::SeqCst) > 0 {
|
||||||
|
if ERROR.load(Ordering::SeqCst) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TEMP_COM.store(LAST_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
process_command(calc_display, resource_provider, OpCode::CloseP);
|
||||||
|
LAST_COM.store(TEMP_COM.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
TEMP_COM.store(w_param as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_highest_precedence_operation(calc_display);
|
||||||
|
while PRECEDENCE.load(Ordering::SeqCst) && PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) > 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
let ni = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
|
||||||
|
NO_PREV_EQU.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
resolve_highest_precedence_operation(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
let grouped_string = group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst));
|
||||||
|
complete_equation(grouped_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
OpCode::OpenP | OpCode::CloseP => {
|
||||||
|
if (OPEN_PAREN_COUNT.load(Ordering::SeqCst) >= MAX_PREC_DEPTH && w_param == OpCode::OpenP)
|
||||||
|
|| (OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 && w_param != OpCode::OpenP)
|
||||||
|
|| (PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) >= MAX_PREC_DEPTH && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0) {
|
||||||
|
if OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 && w_param != OpCode::OpenP {
|
||||||
|
calc_display.on_no_right_paren_added();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_error_command(w_param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_param == OpCode::OpenP {
|
||||||
|
if is_digit_op_code(LAST_COM.load(Ordering::SeqCst)) || is_unary_op_code(LAST_COM.load(Ordering::SeqCst))
|
||||||
|
|| LAST_COM.load(Ordering::SeqCst) == OpCode::Pnt || LAST_COM.load(Ordering::SeqCst) == OpCode::CloseP {
|
||||||
|
process_command(calc_display, resource_provider, OpCode::Mul);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
add_open_brace_to_history();
|
||||||
|
|
||||||
|
PAREN_VALS.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)] = LAST_VAL.load(Ordering::SeqCst);
|
||||||
|
OPCODE.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)] = if CHANGE_OP.load(Ordering::SeqCst) { OPCODE.load(Ordering::SeqCst) } else { 0 };
|
||||||
|
|
||||||
|
if PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) < PREC_OP.lock().unwrap().len() {
|
||||||
|
PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
|
LAST_VAL.store(0, Ordering::SeqCst);
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
TEMP_COM.store(0, Ordering::SeqCst);
|
||||||
|
OPCODE.store(0, Ordering::SeqCst);
|
||||||
|
CHANGE_OP.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
while PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) > 0 && PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst) - 1] != 0 {
|
||||||
|
PRECEDENCE_OP_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
OPCODE.store(PREC_OP.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PRECEDENCE_VALS.lock().unwrap()[PRECEDENCE_OP_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
let ni = precedence_of_op(PREV_OPCODE.load(Ordering::SeqCst));
|
||||||
|
let nx = precedence_of_op(OPCODE.load(Ordering::SeqCst));
|
||||||
|
if ni <= nx {
|
||||||
|
enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
pop_last_opnd_start();
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_close_brace_to_history();
|
||||||
|
|
||||||
|
OPEN_PAREN_COUNT.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(PAREN_VALS.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
OPCODE.store(OPCODE.lock().unwrap()[OPEN_PAREN_COUNT.load(Ordering::SeqCst)], Ordering::SeqCst);
|
||||||
|
|
||||||
|
CHANGE_OP.store(OPCODE.load(Ordering::SeqCst) != 0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
calc_display.set_parenthesis_number(OPEN_PAREN_COUNT.load(Ordering::SeqCst));
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpCode::Hex | OpCode::Dec | OpCode::Oct | OpCode::Bin => {
|
||||||
|
set_radix_type_and_num_width(w_param as i32 - OpCode::Hex as i32, -1);
|
||||||
|
update_history_expression(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
OpCode::Qword | OpCode::Dword | OpCode::Word | OpCode::Byte => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
CURRENT_VAL.store(INPUT.lock().unwrap().to_rational(RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
RECORD.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_radix_type_and_num_width(-1, w_param as i32 - OpCode::Qword as i32);
|
||||||
|
}
|
||||||
|
OpCode::Deg | OpCode::Rad | OpCode::Grad => {
|
||||||
|
ANGLE_TYPE.store(w_param as i32 - OpCode::Deg as i32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
OpCode::Sign => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) {
|
||||||
|
if INPUT.lock().unwrap().try_toggle_sign(INTEGER_MODE.load(Ordering::SeqCst), get_max_decimal_value_string()) {
|
||||||
|
display_num(calc_display);
|
||||||
|
} else {
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_bin_op_code(LAST_COM.load(Ordering::SeqCst)) {
|
||||||
|
CURRENT_VAL.store(LAST_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opnd_added_to_history() {
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(-CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
display_num(calc_display);
|
||||||
|
add_unary_op_to_history(OpCode::Sign as i32, INV.load(Ordering::SeqCst), ANGLE_TYPE.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
OpCode::Recall => {
|
||||||
|
if SET_CALC_STATE.load(Ordering::SeqCst) {
|
||||||
|
SET_CALC_STATE.store(false, Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(*MEMORY_VALUE.lock().unwrap(), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::MPlus => {
|
||||||
|
let result = *MEMORY_VALUE.lock().unwrap() + CURRENT_VAL.load(Ordering::SeqCst);
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = truncate_num_for_int_math(result);
|
||||||
|
}
|
||||||
|
OpCode::MMinus => {
|
||||||
|
let result = *MEMORY_VALUE.lock().unwrap() - CURRENT_VAL.load(Ordering::SeqCst);
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = truncate_num_for_int_math(result);
|
||||||
|
}
|
||||||
|
OpCode::Store | OpCode::MClear => {
|
||||||
|
*MEMORY_VALUE.lock().unwrap() = if w_param == OpCode::Store { truncate_num_for_int_math(CURRENT_VAL.load(Ordering::SeqCst)) } else { 0 };
|
||||||
|
}
|
||||||
|
OpCode::Pi => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
CURRENT_VAL.store(if INV.load(Ordering::SeqCst) { TWO_PI } else { PI }, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Rand => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
let mut str = String::new();
|
||||||
|
write!(str, "{:.precision$}", generate_random_number(), precision = PRECISION.load(Ordering::SeqCst)).unwrap();
|
||||||
|
let rat = string_to_rat(false, &str, false, "", RADIX.load(Ordering::SeqCst), PRECISION.load(Ordering::SeqCst));
|
||||||
|
CURRENT_VAL.store(if let Some(rat) = rat { rat } else { 0 }, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Euler => {
|
||||||
|
if !INTEGER_MODE.load(Ordering::SeqCst) {
|
||||||
|
check_and_add_last_bin_op_to_history();
|
||||||
|
CURRENT_VAL.store(RAT_EXP, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
INV.store(false, Ordering::SeqCst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Fe => {
|
||||||
|
let n_fe = if N_FE.load(Ordering::SeqCst) == NumberFormat::Float { NumberFormat::Scientific } else { NumberFormat::Float };
|
||||||
|
N_FE.store(n_fe, Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
OpCode::Exp => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) && !INTEGER_MODE.load(Ordering::SeqCst) && INPUT.lock().unwrap().try_begin_exponent() {
|
||||||
|
display_num(calc_display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Pnt => {
|
||||||
|
if RECORD.load(Ordering::SeqCst) && !INTEGER_MODE.load(Ordering::SeqCst) && INPUT.lock().unwrap().try_add_decimal_pt() {
|
||||||
|
display_num(calc_display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_error_command(w_param);
|
||||||
|
}
|
||||||
|
OpCode::Inv => {
|
||||||
|
INV.store(!INV.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_highest_precedence_operation(calc_display: &dyn CalcDisplay) {
|
||||||
|
if OPCODE.load(Ordering::SeqCst) != 0 {
|
||||||
|
if NO_PREV_EQU.load(Ordering::SeqCst) {
|
||||||
|
HOLD_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
CURRENT_VAL.store(HOLD_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
display_num(calc_display);
|
||||||
|
add_bin_op_to_history(OPCODE.load(Ordering::SeqCst), INTEGER_MODE.load(Ordering::SeqCst));
|
||||||
|
add_opnd_to_history(NUMBER_STRING.lock().unwrap().clone(), CURRENT_VAL.load(Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_VAL.store(do_operation(OPCODE.load(Ordering::SeqCst), CURRENT_VAL.load(Ordering::SeqCst), LAST_VAL.load(Ordering::SeqCst)), Ordering::SeqCst);
|
||||||
|
PREV_OPCODE.store(OPCODE.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
LAST_VAL.store(CURRENT_VAL.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_PREV_EQU.store(false, Ordering::SeqCst);
|
||||||
|
} else if !ERROR.load(Ordering::SeqCst) {
|
||||||
|
display_num(calc_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_and_add_last_bin_op_to_history(add_to_history: bool) {
|
||||||
|
if CHANGE_OP.load(Ordering::SeqCst) {
|
||||||
|
if opnd_added_to_history() {
|
||||||
|
remove_last_opnd_from_history();
|
||||||
|
}
|
||||||
|
} else if opnd_added_to_history() && !ERROR.load(Ordering::SeqCst) {
|
||||||
|
if (is_unary_op_code(LAST_COM.load(Ordering::SeqCst)) || LAST_COM.load(Ordering::SeqCst) == OpCode::Sign as i32 || LAST_COM.load(Ordering::SeqCst) == OpCode::CloseP as i32) && OPEN_PAREN_COUNT.load(Ordering::SeqCst) == 0 {
|
||||||
|
if add_to_history {
|
||||||
|
complete_history_line(group_digits_per_radix(NUMBER_STRING.lock().unwrap().clone(), RADIX.load(Ordering::SeqCst)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remove_last_opnd_from_history();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_primary_display(calc_display: &dyn CalcDisplay, sz_text: &str, is_error: bool) {
|
||||||
|
calc_display.set_primary_display(sz_text, is_error);
|
||||||
|
calc_display.set_is_in_error(is_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_announce_binary_operator(calc_display: &dyn CalcDisplay) {
|
||||||
|
calc_display.binary_operator_received();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precedence_of_op(nop_code: i32) -> i32 {
|
||||||
|
match nop_code {
|
||||||
|
OpCode::Or as i32 | OpCode::Xor as i32 => 0,
|
||||||
|
OpCode::And as i32 | OpCode::Nand as i32 | OpCode::Nor as i32 => 1,
|
||||||
|
OpCode::Add as i32 | OpCode::Sub as i32 => 2,
|
||||||
|
OpCode::Lshf as i32 | OpCode::Rshf as i32 | OpCode::Rshfl as i32 | OpCode::Mod as i32 | OpCode::Div as i32 | OpCode::Mul as i32 => 3,
|
||||||
|
OpCode::Pwr as i32 | OpCode::Root as i32 | OpCode::LogBaseY as i32 => 4,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_gui_setting_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Hex | OpCode::Dec | OpCode::Oct | OpCode::Bin | OpCode::Qword | OpCode::Dword | OpCode::Word | OpCode::Byte | OpCode::Deg | OpCode::Rad | OpCode::Grad | OpCode::Inv | OpCode::Fe | OpCode::MClear | OpCode::Back | OpCode::Exp | OpCode::Store | OpCode::MPlus | OpCode::MMinus)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_bin_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::And | OpCode::Or | OpCode::Xor | OpCode::Nand | OpCode::Nor | OpCode::Add | OpCode::Sub | OpCode::Lshf | OpCode::Rshf | OpCode::Rshfl | OpCode::Mod | OpCode::Div | OpCode::Mul | OpCode::Pwr | OpCode::Root | OpCode::LogBaseY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unary_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Chop | OpCode::Sin | OpCode::Cos | OpCode::Tan | OpCode::Ln | OpCode::Dms | OpCode::Degrees | OpCode::Sinh | OpCode::Cosh | OpCode::Tanh | OpCode::Sec | OpCode::Csc | OpCode::Cot | OpCode::Sech | OpCode::Csch | OpCode::Coth | OpCode::Sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_digit_op_code(op_code: OpCode) -> bool {
|
||||||
|
matches!(op_code, OpCode::Digit0 | OpCode::Digit1 | OpCode::Digit2 | OpCode::Digit3 | OpCode::Digit4 | OpCode::Digit5 | OpCode::Digit6 | OpCode::Digit7 | OpCode::Digit8 | OpCode::Digit9 | OpCode::DigitA | OpCode::DigitB | OpCode::DigitC | OpCode::DigitD | OpCode::DigitE | OpCode::DigitF)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_op_in_range(op_code: OpCode, start: OpCode, end: OpCode) -> bool {
|
||||||
|
(op_code as i32) >= (start as i32) && (op_code as i32) <= (end as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sci_calc_functions(current_val: Rational, w_param: u32) -> Rational {
|
||||||
|
// Implement the scientific calculator functions here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
current_val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_operation(op_code: i32, lhs: Rational, rhs: Rational) -> Rational {
|
||||||
|
// Implement the operation logic here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
lhs + rhs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_num(calc_display: &dyn CalcDisplay) {
|
||||||
|
// Implement the display logic here
|
||||||
|
// This is a placeholder implementation
|
||||||
|
calc_display.set_primary_display("0", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_and_add_last_bin_op_to_history() {
|
||||||
|
// Implement the logic to check and add the last binary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_opnd_to_history(num_str: String, rat: Rational) {
|
||||||
|
// Implement the logic to add operand to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_last_bin_op(op_code: i32, f_prec_inv_to_higher: bool, is_integer_mode: bool) {
|
||||||
|
// Implement the logic to change the last binary operator
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_digits_per_radix(num_str: String, radix: u32) -> String {
|
||||||
|
// Implement the logic to group digits per radix
|
||||||
|
// This is a placeholder implementation
|
||||||
|
num_str
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_equation(grouped_string: String) {
|
||||||
|
// Implement the logic to complete the equation
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_last_opnd_from_history() {
|
||||||
|
// Implement the logic to remove the last operand from history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_bin_op_to_history(op_code: i32, is_integer_mode: bool) {
|
||||||
|
// Implement the logic to add binary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_unary_op_to_history(op_code: i32, inv: bool, angle_type: i32) {
|
||||||
|
// Implement the logic to add unary operator to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_current_too_big_for_trig() -> bool {
|
||||||
|
// Implement the logic to check if the current value is too big for trigonometric functions
|
||||||
|
// This is a placeholder implementation
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_error(calc_display: &dyn CalcDisplay, error_code: u32) {
|
||||||
|
// Implement the logic to display error
|
||||||
|
// This is a placeholder implementation
|
||||||
|
calc_display.set_primary_display("Error", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_radix_type_and_num_width(radix_type: i32, num_width: i32) {
|
||||||
|
// Implement the logic to set radix type and number width
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_history_expression(radix: u32, precision: u32) {
|
||||||
|
// Implement the logic to update history expression
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_last_opnd_start() {
|
||||||
|
// Implement the logic to push the last operand start
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_last_opnd_start() {
|
||||||
|
// Implement the logic to pop the last operand start
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enclose_prec_inversion_brackets() {
|
||||||
|
// Implement the logic to enclose precedence inversion brackets
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_open_brace_to_history() {
|
||||||
|
// Implement the logic to add open brace to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_close_brace_to_history() {
|
||||||
|
// Implement the logic to add close brace to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate_num_for_int_math(num: Rational) -> Rational {
|
||||||
|
// Implement the logic to truncate number for integer math
|
||||||
|
// This is a placeholder implementation
|
||||||
|
num
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_random_number() -> f64 {
|
||||||
|
// Implement the logic to generate a random number
|
||||||
|
// This is a placeholder implementation
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_to_rat(negative: bool, num_str: &str, exp_negative: bool, exp_str: &str, radix: u32, precision: u32) -> Option<Rational> {
|
||||||
|
// Implement the logic to convert string to rational
|
||||||
|
// This is a placeholder implementation
|
||||||
|
Some(Rational::new(0, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_max_decimal_value_string() -> String {
|
||||||
|
// Implement the logic to get the maximum decimal value string
|
||||||
|
// This is a placeholder implementation
|
||||||
|
"0".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_toggle_bit(current_val: Rational, bit: u32) -> bool {
|
||||||
|
// Implement the logic to try toggling a bit
|
||||||
|
// This is a placeholder implementation
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_history_line() {
|
||||||
|
// Implement the logic to clear the history line
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opnd_added_to_history() -> bool {
|
||||||
|
// Implement the logic to check if operand is added to history
|
||||||
|
// This is a placeholder implementation
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_history_line(grouped_string: String) {
|
||||||
|
// Implement the logic to complete the history line
|
||||||
|
// This is a placeholder implementation
|
||||||
|
}
|
81
src/CalcManager/CalculatorHistory.rs
Normal file
81
src/CalcManager/CalculatorHistory.rs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct HistoryItemVector {
|
||||||
|
pub tokens: Arc<Vec<(String, i32)>>,
|
||||||
|
pub commands: Arc<Vec<Arc<dyn IExpressionCommand>>>,
|
||||||
|
pub expression: String,
|
||||||
|
pub result: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HistoryItem {
|
||||||
|
pub history_item_vector: HistoryItemVector,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CalculatorHistory {
|
||||||
|
max_history_size: usize,
|
||||||
|
history_items: VecDeque<Arc<HistoryItem>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalculatorHistory {
|
||||||
|
pub fn new(max_size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
max_history_size: max_size,
|
||||||
|
history_items: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_to_history(
|
||||||
|
&mut self,
|
||||||
|
tokens: Arc<Vec<(String, i32)>>,
|
||||||
|
commands: Arc<Vec<Arc<dyn IExpressionCommand>>>,
|
||||||
|
result: &str,
|
||||||
|
) -> u32 {
|
||||||
|
let history_item = Arc::new(HistoryItem {
|
||||||
|
history_item_vector: HistoryItemVector {
|
||||||
|
tokens: tokens.clone(),
|
||||||
|
commands: commands.clone(),
|
||||||
|
expression: Self::get_generated_expression(&tokens),
|
||||||
|
result: result.to_string(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
self.add_item(history_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_item(&mut self, history_item: Arc<HistoryItem>) -> u32 {
|
||||||
|
if self.history_items.len() >= self.max_history_size {
|
||||||
|
self.history_items.pop_front();
|
||||||
|
}
|
||||||
|
self.history_items.push_back(history_item);
|
||||||
|
(self.history_items.len() - 1) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_item(&mut self, index: u32) -> bool {
|
||||||
|
if (index as usize) < self.history_items.len() {
|
||||||
|
self.history_items.remove(index as usize);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history(&self) -> &VecDeque<Arc<HistoryItem>> {
|
||||||
|
&self.history_items
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_item(&self, index: u32) -> Option<&Arc<HistoryItem>> {
|
||||||
|
self.history_items.get(index as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_history(&mut self) {
|
||||||
|
self.history_items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_generated_expression(tokens: &[(String, i32)]) -> String {
|
||||||
|
tokens
|
||||||
|
.iter()
|
||||||
|
.map(|(token, _)| token.clone())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
}
|
||||||
|
}
|
566
src/CalcManager/CalculatorManager.rs
Normal file
566
src/CalcManager/CalculatorManager.rs
Normal file
|
@ -0,0 +1,566 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::calc_engine::CCalcEngine;
|
||||||
|
use crate::calc_history::CalculatorHistory;
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_input::CalcInput;
|
||||||
|
use crate::calc_utils::Rational;
|
||||||
|
|
||||||
|
pub enum CalculatorMode {
|
||||||
|
Standard,
|
||||||
|
Scientific,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CalculatorPrecision {
|
||||||
|
StandardModePrecision = 16,
|
||||||
|
ScientificModePrecision = 32,
|
||||||
|
ProgrammerModePrecision = 64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MemoryCommand {
|
||||||
|
MemorizeNumber = 330,
|
||||||
|
MemorizedNumberLoad = 331,
|
||||||
|
MemorizedNumberAdd = 332,
|
||||||
|
MemorizedNumberSubtract = 333,
|
||||||
|
MemorizedNumberClearAll = 334,
|
||||||
|
MemorizedNumberClear = 335,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CalculatorManager {
|
||||||
|
display_callback: Arc<dyn ICalcDisplay>,
|
||||||
|
current_calculator_engine: Option<Arc<CCalcEngine>>,
|
||||||
|
scientific_calculator_engine: Option<Arc<CCalcEngine>>,
|
||||||
|
standard_calculator_engine: Option<Arc<CCalcEngine>>,
|
||||||
|
programmer_calculator_engine: Option<Arc<CCalcEngine>>,
|
||||||
|
resource_provider: Arc<dyn IResourceProvider>,
|
||||||
|
in_history_item_load_mode: bool,
|
||||||
|
memorized_numbers: Vec<Rational>,
|
||||||
|
persisted_primary_value: Rational,
|
||||||
|
is_exponential_format: bool,
|
||||||
|
current_degree_mode: Command,
|
||||||
|
std_history: Arc<CalculatorHistory>,
|
||||||
|
sci_history: Arc<CalculatorHistory>,
|
||||||
|
history: Option<Arc<CalculatorHistory>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalculatorManager {
|
||||||
|
pub fn new(display_callback: Arc<dyn ICalcDisplay>, resource_provider: Arc<dyn IResourceProvider>) -> Self {
|
||||||
|
let std_history = Arc::new(CalculatorHistory::new(20));
|
||||||
|
let sci_history = Arc::new(CalculatorHistory::new(20));
|
||||||
|
|
||||||
|
CCalcEngine::initial_one_time_only_setup(resource_provider.clone());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
display_callback,
|
||||||
|
current_calculator_engine: None,
|
||||||
|
scientific_calculator_engine: None,
|
||||||
|
standard_calculator_engine: None,
|
||||||
|
programmer_calculator_engine: None,
|
||||||
|
resource_provider,
|
||||||
|
in_history_item_load_mode: false,
|
||||||
|
memorized_numbers: Vec::new(),
|
||||||
|
persisted_primary_value: Rational::default(),
|
||||||
|
is_exponential_format: false,
|
||||||
|
current_degree_mode: Command::CommandNULL,
|
||||||
|
std_history: std_history.clone(),
|
||||||
|
sci_history: sci_history.clone(),
|
||||||
|
history: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_primary_display(&self, display_string: &str, is_error: bool) {
|
||||||
|
if !self.in_history_item_load_mode {
|
||||||
|
self.display_callback.set_primary_display(display_string, is_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_is_in_error(&self, is_error: bool) {
|
||||||
|
self.display_callback.set_is_in_error(is_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_paste_error(&self) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.display_error(CALC_E_DOMAIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_digits_reached(&self) {
|
||||||
|
self.display_callback.max_digits_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary_operator_received(&self) {
|
||||||
|
self.display_callback.binary_operator_received();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memory_item_changed(&self, index_of_memory: u32) {
|
||||||
|
self.display_callback.memory_item_changed(index_of_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input_changed(&self) {
|
||||||
|
self.display_callback.input_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_expression_display(
|
||||||
|
&self,
|
||||||
|
tokens: Arc<Vec<(String, i32)>>,
|
||||||
|
commands: Arc<Vec<Arc<dyn IExpressionCommand>>>,
|
||||||
|
) {
|
||||||
|
if !self.in_history_item_load_mode {
|
||||||
|
self.display_callback.set_expression_display(tokens, commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_memorized_numbers(&self, memorized_numbers: Vec<String>) {
|
||||||
|
self.display_callback.set_memorized_numbers(memorized_numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_parenthesis_number(&self, parenthesis_count: u32) {
|
||||||
|
self.display_callback.set_parenthesis_number(parenthesis_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_no_right_paren_added(&self) {
|
||||||
|
self.display_callback.on_no_right_paren_added();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self, clear_memory: bool) {
|
||||||
|
self.set_standard_mode();
|
||||||
|
|
||||||
|
if let Some(engine) = &self.scientific_calculator_engine {
|
||||||
|
engine.process_command(IDC_DEG);
|
||||||
|
engine.process_command(IDC_CLEAR);
|
||||||
|
|
||||||
|
if self.is_exponential_format {
|
||||||
|
self.is_exponential_format = false;
|
||||||
|
engine.process_command(IDC_FE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(engine) = &self.programmer_calculator_engine {
|
||||||
|
engine.process_command(IDC_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if clear_memory {
|
||||||
|
self.memorized_number_clear_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_standard_mode(&mut self) {
|
||||||
|
if self.standard_calculator_engine.is_none() {
|
||||||
|
self.standard_calculator_engine = Some(Arc::new(CCalcEngine::new(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
self.resource_provider.clone(),
|
||||||
|
self.display_callback.clone(),
|
||||||
|
self.std_history.clone(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_calculator_engine = self.standard_calculator_engine.clone();
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.process_command(IDC_DEC);
|
||||||
|
engine.process_command(IDC_CLEAR);
|
||||||
|
engine.change_precision(CalculatorPrecision::StandardModePrecision as i32);
|
||||||
|
self.update_max_int_digits();
|
||||||
|
}
|
||||||
|
self.history = Some(self.std_history.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scientific_mode(&mut self) {
|
||||||
|
if self.scientific_calculator_engine.is_none() {
|
||||||
|
self.scientific_calculator_engine = Some(Arc::new(CCalcEngine::new(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
self.resource_provider.clone(),
|
||||||
|
self.display_callback.clone(),
|
||||||
|
self.sci_history.clone(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_calculator_engine = self.scientific_calculator_engine.clone();
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.process_command(IDC_DEC);
|
||||||
|
engine.process_command(IDC_CLEAR);
|
||||||
|
engine.change_precision(CalculatorPrecision::ScientificModePrecision as i32);
|
||||||
|
}
|
||||||
|
self.history = Some(self.sci_history.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_programmer_mode(&mut self) {
|
||||||
|
if self.programmer_calculator_engine.is_none() {
|
||||||
|
self.programmer_calculator_engine = Some(Arc::new(CCalcEngine::new(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
self.resource_provider.clone(),
|
||||||
|
self.display_callback.clone(),
|
||||||
|
None,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_calculator_engine = self.programmer_calculator_engine.clone();
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.process_command(IDC_DEC);
|
||||||
|
engine.process_command(IDC_CLEAR);
|
||||||
|
engine.change_precision(CalculatorPrecision::ProgrammerModePrecision as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_command(&mut self, command: Command) {
|
||||||
|
if command == Command::CommandCLEAR
|
||||||
|
|| command == Command::CommandEQU
|
||||||
|
|| command == Command::ModeBasic
|
||||||
|
|| command == Command::ModeScientific
|
||||||
|
|| command == Command::ModeProgrammer
|
||||||
|
{
|
||||||
|
match command {
|
||||||
|
Command::ModeBasic => self.set_standard_mode(),
|
||||||
|
Command::ModeScientific => self.set_scientific_mode(),
|
||||||
|
Command::ModeProgrammer => self.set_programmer_mode(),
|
||||||
|
_ => {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.process_command(command as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.input_changed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if command == Command::CommandDEG
|
||||||
|
|| command == Command::CommandRAD
|
||||||
|
|| command == Command::CommandGRAD
|
||||||
|
{
|
||||||
|
self.current_degree_mode = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
match command {
|
||||||
|
Command::CommandASIN => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandSIN as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACOS => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCOS as i32);
|
||||||
|
}
|
||||||
|
Command::CommandATAN => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandTAN as i32);
|
||||||
|
}
|
||||||
|
Command::CommandPOWE => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandLN as i32);
|
||||||
|
}
|
||||||
|
Command::CommandASINH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandSINH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACOSH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCOSH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandATANH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandTANH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandASEC => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandSEC as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACSC => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCSC as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACOT => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCOT as i32);
|
||||||
|
}
|
||||||
|
Command::CommandASECH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandSECH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACSCH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCSCH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandACOTH => {
|
||||||
|
engine.process_command(Command::CommandINV as i32);
|
||||||
|
engine.process_command(Command::CommandCOTH as i32);
|
||||||
|
}
|
||||||
|
Command::CommandFE => {
|
||||||
|
self.is_exponential_format = !self.is_exponential_format;
|
||||||
|
engine.process_command(command as i32);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
engine.process_command(command as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.input_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_persisted_primary_value(&mut self) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.persisted_mem_object(self.persisted_primary_value.clone());
|
||||||
|
engine.process_command(IDC_RECALL);
|
||||||
|
}
|
||||||
|
self.input_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorize_number(&mut self) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.process_command(IDC_STORE);
|
||||||
|
|
||||||
|
if let Some(memory_object) = engine.persisted_mem_object() {
|
||||||
|
self.memorized_numbers.insert(0, memory_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.memorized_numbers.len() > 100 {
|
||||||
|
self.memorized_numbers.truncate(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_memorized_numbers_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorized_number_load(&mut self, index_of_memory: u32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.memorized_number_select(index_of_memory);
|
||||||
|
engine.process_command(IDC_RECALL);
|
||||||
|
}
|
||||||
|
self.input_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorized_number_add(&mut self, index_of_memory: u32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.memorized_numbers.is_empty() {
|
||||||
|
self.memorize_number();
|
||||||
|
} else {
|
||||||
|
self.memorized_number_select(index_of_memory);
|
||||||
|
engine.process_command(IDC_MPLUS);
|
||||||
|
|
||||||
|
self.memorized_number_changed(index_of_memory);
|
||||||
|
self.set_memorized_numbers_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.display_callback.memory_item_changed(index_of_memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorized_number_clear(&mut self, index_of_memory: u32) {
|
||||||
|
if index_of_memory < self.memorized_numbers.len() as u32 {
|
||||||
|
self.memorized_numbers.remove(index_of_memory as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorized_number_subtract(&mut self, index_of_memory: u32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.memorized_numbers.is_empty() {
|
||||||
|
self.memorize_number();
|
||||||
|
self.memorized_number_subtract(0);
|
||||||
|
self.memorized_number_subtract(0);
|
||||||
|
} else {
|
||||||
|
self.memorized_number_select(index_of_memory);
|
||||||
|
engine.process_command(IDC_MMINUS);
|
||||||
|
|
||||||
|
self.memorized_number_changed(index_of_memory);
|
||||||
|
self.set_memorized_numbers_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.display_callback.memory_item_changed(index_of_memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memorized_number_clear_all(&mut self) {
|
||||||
|
self.memorized_numbers.clear();
|
||||||
|
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.process_command(IDC_MCLEAR);
|
||||||
|
}
|
||||||
|
self.set_memorized_numbers_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memorized_number_select(&mut self, index_of_memory: u32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(memory_object) = self.memorized_numbers.get(index_of_memory as usize) {
|
||||||
|
engine.persisted_mem_object(memory_object.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memorized_number_changed(&mut self, index_of_memory: u32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
if engine.f_in_error_state() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(memory_object) = engine.persisted_mem_object() {
|
||||||
|
if let Some(mem) = self.memorized_numbers.get_mut(index_of_memory as usize) {
|
||||||
|
*mem = memory_object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_items(&self) -> Vec<Arc<HISTORYITEM>> {
|
||||||
|
if let Some(history) = &self.history {
|
||||||
|
history.get_history().clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_items_by_mode(&self, mode: CalculatorMode) -> Vec<Arc<HISTORYITEM>> {
|
||||||
|
match mode {
|
||||||
|
CalculatorMode::Standard => self.std_history.get_history().clone(),
|
||||||
|
CalculatorMode::Scientific => self.sci_history.get_history().clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_history_items(&mut self, history_items: Vec<Arc<HISTORYITEM>>) {
|
||||||
|
if let Some(history) = &self.history {
|
||||||
|
for item in history_items {
|
||||||
|
let index = history.add_item(item);
|
||||||
|
self.on_history_item_added(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_item(&self, index: u32) -> Option<Arc<HISTORYITEM>> {
|
||||||
|
if let Some(history) = &self.history {
|
||||||
|
history.get_history_item(index)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_history_item_added(&self, added_item_index: u32) {
|
||||||
|
self.display_callback.on_history_item_added(added_item_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_history_item(&mut self, index: u32) -> bool {
|
||||||
|
if let Some(history) = &self.history {
|
||||||
|
history.remove_item(index)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_history(&mut self) {
|
||||||
|
if let Some(history) = &self.history {
|
||||||
|
history.clear_history();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_radix(&mut self, radix_type: RadixType) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
match radix_type {
|
||||||
|
RadixType::Hex => engine.process_command(IDC_HEX),
|
||||||
|
RadixType::Decimal => engine.process_command(IDC_DEC),
|
||||||
|
RadixType::Octal => engine.process_command(IDC_OCT),
|
||||||
|
RadixType::Binary => engine.process_command(IDC_BIN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.set_memorized_numbers_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_memorized_numbers_string(&self) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
let mut result_vector = Vec::new();
|
||||||
|
for memory_item in &self.memorized_numbers {
|
||||||
|
let radix = engine.get_current_radix();
|
||||||
|
let string_value = engine.get_string_for_display(memory_item, radix);
|
||||||
|
|
||||||
|
if !string_value.is_empty() {
|
||||||
|
result_vector.push(engine.group_digits_per_radix(&string_value, radix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.display_callback.set_memorized_numbers(result_vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_degree_mode(&self) -> Command {
|
||||||
|
if self.current_degree_mode == Command::CommandNULL {
|
||||||
|
self.current_degree_mode = Command::CommandDEG;
|
||||||
|
}
|
||||||
|
self.current_degree_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_result_for_radix(&self, radix: u32, precision: i32, group_digits_per_radix: bool) -> String {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.get_current_result_for_radix(radix, precision, group_digits_per_radix)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_precision(&mut self, precision: i32) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.change_precision(precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_max_int_digits(&mut self) {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.update_max_int_digits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decimal_separator(&self) -> char {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.decimal_separator()
|
||||||
|
} else {
|
||||||
|
self.resource_provider.get_cengine_string("sDecimal").chars().next().unwrap_or('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_engine_recording(&self) -> bool {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.f_in_recording_state()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_input_empty(&self) -> bool {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.is_input_empty()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_in_history_item_load_mode(&mut self, is_history_item_load_mode: bool) {
|
||||||
|
self.in_history_item_load_mode = is_history_item_load_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_display_commands_snapshot(&self) -> Vec<Arc<dyn IExpressionCommand>> {
|
||||||
|
if let Some(engine) = &self.current_calculator_engine {
|
||||||
|
engine.get_history_collector_commands_snapshot()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
266
src/CalcManager/ExpressionCommand.rs
Normal file
266
src/CalcManager/ExpressionCommand.rs
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::calc_engine::CCalcEngine;
|
||||||
|
use crate::calc_utils::Rational;
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_history::CHistoryCollector;
|
||||||
|
use crate::calc_resource::IResourceProvider;
|
||||||
|
|
||||||
|
pub struct CParentheses {
|
||||||
|
command: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CParentheses {
|
||||||
|
pub fn new(command: i32) -> Self {
|
||||||
|
Self { command }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command(&self) -> i32 {
|
||||||
|
self.command
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command_type(&self) -> CommandType {
|
||||||
|
CommandType::Parentheses
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(&self, command_visitor: &mut dyn ISerializeCommandVisitor) {
|
||||||
|
command_visitor.visit_parentheses(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CUnaryCommand {
|
||||||
|
commands: Arc<Vec<i32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CUnaryCommand {
|
||||||
|
pub fn new(command: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
commands: Arc::new(vec![command]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_two_commands(command1: i32, command2: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
commands: Arc::new(vec![command1, command2]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_commands(&self) -> Arc<Vec<i32>> {
|
||||||
|
Arc::clone(&self.commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command_type(&self) -> CommandType {
|
||||||
|
CommandType::UnaryCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_command(&mut self, command: i32) {
|
||||||
|
Arc::make_mut(&mut self.commands).clear();
|
||||||
|
Arc::make_mut(&mut self.commands).push(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_commands(&mut self, command1: i32, command2: i32) {
|
||||||
|
Arc::make_mut(&mut self.commands).clear();
|
||||||
|
Arc::make_mut(&mut self.commands).push(command1);
|
||||||
|
Arc::make_mut(&mut self.commands).push(command2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(&self, command_visitor: &mut dyn ISerializeCommandVisitor) {
|
||||||
|
command_visitor.visit_unary_command(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CBinaryCommand {
|
||||||
|
command: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CBinaryCommand {
|
||||||
|
pub fn new(command: i32) -> Self {
|
||||||
|
Self { command }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_command(&mut self, command: i32) {
|
||||||
|
self.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command(&self) -> i32 {
|
||||||
|
self.command
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command_type(&self) -> CommandType {
|
||||||
|
CommandType::BinaryCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(&self, command_visitor: &mut dyn ISerializeCommandVisitor) {
|
||||||
|
command_visitor.visit_binary_command(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct COpndCommand {
|
||||||
|
commands: Arc<Vec<i32>>,
|
||||||
|
is_negative: bool,
|
||||||
|
is_sci_fmt: bool,
|
||||||
|
is_decimal: bool,
|
||||||
|
is_initialized: bool,
|
||||||
|
token: String,
|
||||||
|
value: Rational,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl COpndCommand {
|
||||||
|
pub fn new(commands: Arc<Vec<i32>>, is_negative: bool, is_decimal: bool, is_sci_fmt: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
commands,
|
||||||
|
is_negative,
|
||||||
|
is_sci_fmt,
|
||||||
|
is_decimal,
|
||||||
|
is_initialized: false,
|
||||||
|
token: String::new(),
|
||||||
|
value: Rational::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize(&mut self, rat: Rational) {
|
||||||
|
self.value = rat;
|
||||||
|
self.is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_commands(&self) -> Arc<Vec<i32>> {
|
||||||
|
Arc::clone(&self.commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_commands(&mut self, commands: Arc<Vec<i32>>) {
|
||||||
|
self.commands = commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_command(&mut self, command: i32) {
|
||||||
|
if self.is_sci_fmt {
|
||||||
|
self.clear_all_and_append_command(command);
|
||||||
|
} else {
|
||||||
|
Arc::make_mut(&mut self.commands).push(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
if command == IDC_PNT {
|
||||||
|
self.is_decimal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_sign(&mut self) {
|
||||||
|
for &n_op_code in self.commands.iter() {
|
||||||
|
if n_op_code != IDC_0 {
|
||||||
|
self.is_negative = !self.is_negative;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_from_end(&mut self) {
|
||||||
|
if self.is_sci_fmt {
|
||||||
|
self.clear_all_and_append_command(IDC_0);
|
||||||
|
} else {
|
||||||
|
let n_commands = self.commands.len();
|
||||||
|
|
||||||
|
if n_commands == 1 {
|
||||||
|
self.clear_all_and_append_command(IDC_0);
|
||||||
|
} else {
|
||||||
|
let n_op_code = self.commands[n_commands - 1];
|
||||||
|
|
||||||
|
if n_op_code == IDC_PNT {
|
||||||
|
self.is_decimal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::make_mut(&mut self.commands).pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative(&self) -> bool {
|
||||||
|
self.is_negative
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_sci_fmt(&self) -> bool {
|
||||||
|
self.is_sci_fmt
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_decimal_present(&self) -> bool {
|
||||||
|
self.is_decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command_type(&self) -> CommandType {
|
||||||
|
CommandType::OperandCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_all_and_append_command(&mut self, command: i32) {
|
||||||
|
Arc::make_mut(&mut self.commands).clear();
|
||||||
|
Arc::make_mut(&mut self.commands).push(command);
|
||||||
|
self.is_sci_fmt = false;
|
||||||
|
self.is_negative = false;
|
||||||
|
self.is_decimal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_token(&mut self, decimal_symbol: char) -> &str {
|
||||||
|
const CH_ZERO: char = '0';
|
||||||
|
const CH_EXP: char = 'e';
|
||||||
|
const CH_NEGATE: char = '-';
|
||||||
|
const CH_PLUS: char = '+';
|
||||||
|
|
||||||
|
self.token.clear();
|
||||||
|
|
||||||
|
for &n_op_code in self.commands.iter() {
|
||||||
|
match n_op_code {
|
||||||
|
IDC_PNT => self.token.push(decimal_symbol),
|
||||||
|
IDC_EXP => {
|
||||||
|
self.token.push(CH_EXP);
|
||||||
|
if self.commands.iter().position(|&x| x == IDC_SIGN).is_none() {
|
||||||
|
self.token.push(CH_PLUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDC_SIGN => self.token.push(CH_NEGATE),
|
||||||
|
_ => self.token.push_str(&((n_op_code - IDC_0).to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, ch) in self.token.chars().enumerate() {
|
||||||
|
if ch != CH_ZERO {
|
||||||
|
if ch == decimal_symbol {
|
||||||
|
self.token.drain(0..i - 1);
|
||||||
|
} else {
|
||||||
|
self.token.drain(0..i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_negative {
|
||||||
|
self.token.insert(0, CH_NEGATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &self.token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.token = CH_ZERO.to_string();
|
||||||
|
&self.token
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_string(&self, radix: u32, precision: i32) -> String {
|
||||||
|
if self.is_initialized {
|
||||||
|
self.value.to_string(radix, NumberFormat::Float, precision)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(&self, command_visitor: &mut dyn ISerializeCommandVisitor) {
|
||||||
|
command_visitor.visit_opnd_command(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ISerializeCommandVisitor {
|
||||||
|
fn visit_opnd_command(&mut self, opnd_cmd: &COpndCommand);
|
||||||
|
fn visit_unary_command(&mut self, unary_cmd: &CUnaryCommand);
|
||||||
|
fn visit_binary_command(&mut self, binary_cmd: &CBinaryCommand);
|
||||||
|
fn visit_parentheses(&mut self, para_cmd: &CParentheses);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CommandType {
|
||||||
|
Parentheses,
|
||||||
|
UnaryCommand,
|
||||||
|
BinaryCommand,
|
||||||
|
OperandCommand,
|
||||||
|
}
|
89
src/CalcManager/Header Files/CCommand.rs
Normal file
89
src/CalcManager/Header Files/CCommand.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub enum Command {
|
||||||
|
CommandNULL,
|
||||||
|
CommandSIGN,
|
||||||
|
CommandPNT,
|
||||||
|
CommandEQU,
|
||||||
|
CommandADD,
|
||||||
|
CommandSUB,
|
||||||
|
CommandMUL,
|
||||||
|
CommandDIV,
|
||||||
|
CommandPWR,
|
||||||
|
CommandSQRT,
|
||||||
|
CommandDIVINV,
|
||||||
|
CommandPERCENT,
|
||||||
|
CommandFRAC,
|
||||||
|
CommandSQR,
|
||||||
|
CommandCUB,
|
||||||
|
CommandREC,
|
||||||
|
CommandSIN,
|
||||||
|
CommandCOS,
|
||||||
|
CommandTAN,
|
||||||
|
CommandLOG,
|
||||||
|
CommandLN,
|
||||||
|
CommandEXP,
|
||||||
|
CommandPOWE,
|
||||||
|
CommandPOW10,
|
||||||
|
CommandASIN,
|
||||||
|
CommandACOS,
|
||||||
|
CommandATAN,
|
||||||
|
CommandSINH,
|
||||||
|
CommandCOSH,
|
||||||
|
CommandTANH,
|
||||||
|
CommandASINH,
|
||||||
|
CommandACOSH,
|
||||||
|
CommandATANH,
|
||||||
|
CommandSEC,
|
||||||
|
CommandCSC,
|
||||||
|
CommandCOT,
|
||||||
|
CommandASEC,
|
||||||
|
CommandACSC,
|
||||||
|
CommandACOT,
|
||||||
|
CommandSECH,
|
||||||
|
CommandCSCH,
|
||||||
|
CommandCOTH,
|
||||||
|
CommandASECH,
|
||||||
|
CommandACSCH,
|
||||||
|
CommandACOTH,
|
||||||
|
CommandDEG,
|
||||||
|
CommandRAD,
|
||||||
|
CommandGRAD,
|
||||||
|
CommandFE,
|
||||||
|
CommandMCLEAR,
|
||||||
|
CommandBACK,
|
||||||
|
CommandEXP,
|
||||||
|
CommandSTORE,
|
||||||
|
CommandMPLUS,
|
||||||
|
CommandMMINUS,
|
||||||
|
CommandCLEAR,
|
||||||
|
ModeBasic,
|
||||||
|
ModeScientific,
|
||||||
|
ModeProgrammer,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IExpressionCommand {
|
||||||
|
fn execute(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CCommand {
|
||||||
|
command: Command,
|
||||||
|
expression_command: Arc<dyn IExpressionCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CCommand {
|
||||||
|
pub fn new(command: Command, expression_command: Arc<dyn IExpressionCommand>) -> Self {
|
||||||
|
Self {
|
||||||
|
command,
|
||||||
|
expression_command,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&self) {
|
||||||
|
self.expression_command.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command(&self) -> Command {
|
||||||
|
self.command
|
||||||
|
}
|
||||||
|
}
|
234
src/CalcManager/Header Files/CalcEngine.rs
Normal file
234
src/CalcManager/Header Files/CalcEngine.rs
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::calc_input::CalcInput;
|
||||||
|
use crate::calc_utils::{Rational, RationalMath};
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_history::CHistoryCollector;
|
||||||
|
use crate::calc_resource::IResourceProvider;
|
||||||
|
|
||||||
|
const DEFAULT_MAX_DIGITS: i32 = 32;
|
||||||
|
const DEFAULT_PRECISION: i32 = 32;
|
||||||
|
const DEFAULT_RADIX: i32 = 10;
|
||||||
|
|
||||||
|
const DEFAULT_DEC_SEPARATOR: char = '.';
|
||||||
|
const DEFAULT_GRP_SEPARATOR: char = ',';
|
||||||
|
const DEFAULT_GRP_STR: &str = "3;0";
|
||||||
|
const DEFAULT_NUMBER_STR: &str = "0";
|
||||||
|
|
||||||
|
pub struct CCalcEngine {
|
||||||
|
f_precedence: bool,
|
||||||
|
f_integer_mode: bool,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
resource_provider: Arc<dyn IResourceProvider>,
|
||||||
|
n_op_code: i32,
|
||||||
|
n_prev_op_code: i32,
|
||||||
|
b_change_op: bool,
|
||||||
|
b_record: bool,
|
||||||
|
b_set_calc_state: bool,
|
||||||
|
input: CalcInput,
|
||||||
|
n_fe: NumberFormat,
|
||||||
|
memory_value: Rational,
|
||||||
|
hold_val: Rational,
|
||||||
|
current_val: Rational,
|
||||||
|
last_val: Rational,
|
||||||
|
paren_vals: Vec<Rational>,
|
||||||
|
precedence_vals: Vec<Rational>,
|
||||||
|
b_error: bool,
|
||||||
|
b_inv: bool,
|
||||||
|
b_no_prev_equ: bool,
|
||||||
|
radix: i32,
|
||||||
|
precision: i32,
|
||||||
|
c_int_digits_sav: i32,
|
||||||
|
dec_grouping: Vec<i32>,
|
||||||
|
number_string: String,
|
||||||
|
n_temp_com: i32,
|
||||||
|
open_paren_count: usize,
|
||||||
|
n_op: Vec<i32>,
|
||||||
|
n_prec_op: Vec<i32>,
|
||||||
|
precedence_op_count: usize,
|
||||||
|
n_last_com: i32,
|
||||||
|
angletype: AngleType,
|
||||||
|
numwidth: NUM_WIDTH,
|
||||||
|
dw_word_bit_width: i32,
|
||||||
|
history_collector: CHistoryCollector,
|
||||||
|
group_separator: char,
|
||||||
|
chop_numbers: Vec<Rational>,
|
||||||
|
max_decimal_value_strings: Vec<String>,
|
||||||
|
decimal_separator: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CCalcEngine {
|
||||||
|
pub fn new(
|
||||||
|
f_precedence: bool,
|
||||||
|
f_integer_mode: bool,
|
||||||
|
resource_provider: Arc<dyn IResourceProvider>,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut engine = CCalcEngine {
|
||||||
|
f_precedence,
|
||||||
|
f_integer_mode,
|
||||||
|
p_calc_display: p_calc_display.clone(),
|
||||||
|
resource_provider: resource_provider.clone(),
|
||||||
|
n_op_code: 0,
|
||||||
|
n_prev_op_code: 0,
|
||||||
|
b_change_op: false,
|
||||||
|
b_record: false,
|
||||||
|
b_set_calc_state: false,
|
||||||
|
input: CalcInput::new(DEFAULT_DEC_SEPARATOR),
|
||||||
|
n_fe: NumberFormat::Float,
|
||||||
|
memory_value: Rational::default(),
|
||||||
|
hold_val: Rational::default(),
|
||||||
|
current_val: Rational::default(),
|
||||||
|
last_val: Rational::default(),
|
||||||
|
paren_vals: vec![Rational::default(); MAXPRECDEPTH],
|
||||||
|
precedence_vals: vec![Rational::default(); MAXPRECDEPTH],
|
||||||
|
b_error: false,
|
||||||
|
b_inv: false,
|
||||||
|
b_no_prev_equ: true,
|
||||||
|
radix: DEFAULT_RADIX,
|
||||||
|
precision: DEFAULT_PRECISION,
|
||||||
|
c_int_digits_sav: DEFAULT_MAX_DIGITS,
|
||||||
|
dec_grouping: vec![],
|
||||||
|
number_string: DEFAULT_NUMBER_STR.to_string(),
|
||||||
|
n_temp_com: 0,
|
||||||
|
open_paren_count: 0,
|
||||||
|
n_op: vec![0; MAXPRECDEPTH],
|
||||||
|
n_prec_op: vec![0; MAXPRECDEPTH],
|
||||||
|
precedence_op_count: 0,
|
||||||
|
n_last_com: 0,
|
||||||
|
angletype: AngleType::Degrees,
|
||||||
|
numwidth: NUM_WIDTH::QWORD_WIDTH,
|
||||||
|
dw_word_bit_width: 0,
|
||||||
|
history_collector: CHistoryCollector::new(p_calc_display, p_history_display, DEFAULT_DEC_SEPARATOR),
|
||||||
|
group_separator: DEFAULT_GRP_SEPARATOR,
|
||||||
|
chop_numbers: vec![Rational::default(); NUM_WIDTH_LENGTH],
|
||||||
|
max_decimal_value_strings: vec![String::new(); NUM_WIDTH_LENGTH],
|
||||||
|
decimal_separator: DEFAULT_DEC_SEPARATOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
engine.init_chop_numbers();
|
||||||
|
engine.dw_word_bit_width = engine.dw_word_bit_width_from_num_width(engine.numwidth);
|
||||||
|
engine.max_trigonometric_num = RationalMath::pow(10, 100);
|
||||||
|
engine.set_radix_type_and_num_width(RadixType::Decimal, engine.numwidth);
|
||||||
|
engine.settings_changed();
|
||||||
|
engine.display_num();
|
||||||
|
|
||||||
|
engine
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_chop_numbers(&mut self) {
|
||||||
|
self.chop_numbers[0] = Rational::from_rat(rat_qword);
|
||||||
|
self.chop_numbers[1] = Rational::from_rat(rat_dword);
|
||||||
|
self.chop_numbers[2] = Rational::from_rat(rat_word);
|
||||||
|
self.chop_numbers[3] = Rational::from_rat(rat_byte);
|
||||||
|
|
||||||
|
for i in 0..self.chop_numbers.len() {
|
||||||
|
let max_val = self.chop_numbers[i] / 2;
|
||||||
|
let max_val = RationalMath::integer(max_val);
|
||||||
|
self.max_decimal_value_strings[i] = max_val.to_string(10, NumberFormat::Float, self.precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_chop_number(&self) -> Rational {
|
||||||
|
self.chop_numbers[self.numwidth as usize].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_max_decimal_value_string(&self) -> String {
|
||||||
|
self.max_decimal_value_strings[self.numwidth as usize].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn persisted_mem_object(&self) -> Rational {
|
||||||
|
self.memory_value.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_persisted_mem_object(&mut self, mem_object: Rational) {
|
||||||
|
self.memory_value = mem_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn settings_changed(&mut self) {
|
||||||
|
let last_dec = self.decimal_separator;
|
||||||
|
let dec_str = self.resource_provider.get_cengine_string("sDecimal");
|
||||||
|
self.decimal_separator = if dec_str.is_empty() {
|
||||||
|
DEFAULT_DEC_SEPARATOR
|
||||||
|
} else {
|
||||||
|
dec_str.chars().next().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_sep = self.group_separator;
|
||||||
|
let sep_str = self.resource_provider.get_cengine_string("sThousand");
|
||||||
|
self.group_separator = if sep_str.is_empty() {
|
||||||
|
DEFAULT_GRP_SEPARATOR
|
||||||
|
} else {
|
||||||
|
sep_str.chars().next().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_dec_grouping = self.dec_grouping.clone();
|
||||||
|
let grp_str = self.resource_provider.get_cengine_string("sGrouping");
|
||||||
|
self.dec_grouping = if grp_str.is_empty() {
|
||||||
|
digit_grouping_string_to_grouping_vector(DEFAULT_GRP_STR)
|
||||||
|
} else {
|
||||||
|
digit_grouping_string_to_grouping_vector(&grp_str)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut num_changed = false;
|
||||||
|
|
||||||
|
if self.dec_grouping != last_dec_grouping || self.group_separator != last_sep {
|
||||||
|
num_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.decimal_separator != last_dec {
|
||||||
|
self.input.set_decimal_symbol(self.decimal_separator);
|
||||||
|
self.history_collector.set_decimal_symbol(self.decimal_separator);
|
||||||
|
s_engine_strings.insert(SIDS_DECIMAL_SEPARATOR.to_string(), self.decimal_separator.to_string());
|
||||||
|
num_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if num_changed {
|
||||||
|
self.display_num();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decimal_separator(&self) -> char {
|
||||||
|
self.decimal_separator
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_history_collector_commands_snapshot(&self) -> Vec<Arc<dyn IExpressionCommand>> {
|
||||||
|
let mut commands = self.history_collector.get_commands();
|
||||||
|
if !self.history_collector.f_opnd_added_to_history() && self.b_record {
|
||||||
|
commands.push(self.history_collector.get_operand_commands_from_string(&self.number_string, &self.current_val));
|
||||||
|
}
|
||||||
|
commands
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initial_one_time_only_setup(resource_provider: Arc<dyn IResourceProvider>) {
|
||||||
|
Self::load_engine_strings(resource_provider);
|
||||||
|
Self::change_base_constants(DEFAULT_RADIX, DEFAULT_MAX_DIGITS, DEFAULT_PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_engine_strings(resource_provider: Arc<dyn IResourceProvider>) {
|
||||||
|
for sid in G_SIDS.iter() {
|
||||||
|
let loc_string = resource_provider.get_cengine_string(sid);
|
||||||
|
if !loc_string.is_empty() {
|
||||||
|
s_engine_strings.insert(sid.to_string(), loc_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_base_constants(radix: i32, max_int_digits: i32, precision: i32) {
|
||||||
|
// Implementation of ChangeBaseConstants
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_num(&self) {
|
||||||
|
// Implementation of DisplayNum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_radix_type_and_num_width(&mut self, radix_type: RadixType, num_width: NUM_WIDTH) {
|
||||||
|
// Implementation of SetRadixTypeAndNumWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dw_word_bit_width_from_num_width(&self, num_width: NUM_WIDTH) -> i32 {
|
||||||
|
// Implementation of DwWordBitWidthFromNumWidth
|
||||||
|
}
|
||||||
|
}
|
264
src/CalcManager/Header Files/CalcInput.rs
Normal file
264
src/CalcManager/Header Files/CalcInput.rs
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
pub struct CalcNumSec {
|
||||||
|
value: String,
|
||||||
|
is_negative: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalcNumSec {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
value: String::new(),
|
||||||
|
is_negative: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.value.clear();
|
||||||
|
self.is_negative = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.value.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative(&self) -> bool {
|
||||||
|
self.is_negative
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_negative(&mut self, is_negative: bool) {
|
||||||
|
self.is_negative = is_negative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CalcInput {
|
||||||
|
base: CalcNumSec,
|
||||||
|
exponent: CalcNumSec,
|
||||||
|
has_exponent: bool,
|
||||||
|
has_decimal: bool,
|
||||||
|
dec_pt_index: usize,
|
||||||
|
dec_symbol: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalcInput {
|
||||||
|
pub fn new(dec_symbol: char) -> Self {
|
||||||
|
Self {
|
||||||
|
base: CalcNumSec::new(),
|
||||||
|
exponent: CalcNumSec::new(),
|
||||||
|
has_exponent: false,
|
||||||
|
has_decimal: false,
|
||||||
|
dec_pt_index: 0,
|
||||||
|
dec_symbol,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.base.clear();
|
||||||
|
self.exponent.clear();
|
||||||
|
self.has_exponent = false;
|
||||||
|
self.has_decimal = false;
|
||||||
|
self.dec_pt_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_toggle_sign(&mut self, is_integer_mode: bool, max_num_str: &str) -> bool {
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.set_negative(false);
|
||||||
|
self.exponent.set_negative(false);
|
||||||
|
} else if self.has_exponent {
|
||||||
|
self.exponent.set_negative(!self.exponent.is_negative());
|
||||||
|
} else {
|
||||||
|
if is_integer_mode && self.base.is_negative() {
|
||||||
|
if self.base.value.len() >= max_num_str.len() && self.base.value.chars().last() > max_num_str.chars().last() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.base.set_negative(!self.base.is_negative());
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_add_digit(&mut self, value: u32, radix: u32, is_integer_mode: bool, max_num_str: &str, word_bit_width: i32, max_digits: usize) -> bool {
|
||||||
|
let ch_digit = if value < 10 {
|
||||||
|
(b'0' + value as u8) as char
|
||||||
|
} else {
|
||||||
|
(b'A' + value as u8 - 10) as char
|
||||||
|
};
|
||||||
|
|
||||||
|
let (p_num_sec, max_count) = if self.has_exponent {
|
||||||
|
(&mut self.exponent, 4)
|
||||||
|
} else {
|
||||||
|
let mut max_count = max_digits;
|
||||||
|
if self.has_decimal {
|
||||||
|
max_count += 1;
|
||||||
|
}
|
||||||
|
if !self.base.is_empty() && self.base.value.starts_with('0') {
|
||||||
|
max_count += 1;
|
||||||
|
}
|
||||||
|
(&mut self.base, max_count)
|
||||||
|
};
|
||||||
|
|
||||||
|
if p_num_sec.is_empty() && value == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if p_num_sec.value.len() < max_count {
|
||||||
|
p_num_sec.value.push(ch_digit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_integer_mode && p_num_sec.value.len() == max_count && !self.has_exponent {
|
||||||
|
let allow_extra_digit = match radix {
|
||||||
|
8 => match word_bit_width % 3 {
|
||||||
|
1 => p_num_sec.value.starts_with('1'),
|
||||||
|
2 => p_num_sec.value.starts_with(|c| c <= '3'),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
10 => {
|
||||||
|
if p_num_sec.value.len() < max_num_str.len() {
|
||||||
|
match p_num_sec.value.cmp(&max_num_str[..p_num_sec.value.len()]) {
|
||||||
|
Ordering::Less => true,
|
||||||
|
Ordering::Equal => {
|
||||||
|
let last_char = max_num_str.chars().nth(p_num_sec.value.len()).unwrap();
|
||||||
|
ch_digit <= last_char || (p_num_sec.is_negative() && ch_digit <= last_char + 1)
|
||||||
|
}
|
||||||
|
Ordering::Greater => false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if allow_extra_digit {
|
||||||
|
p_num_sec.value.push(ch_digit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_add_decimal_pt(&mut self) -> bool {
|
||||||
|
if self.has_decimal || self.has_exponent {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.value.push('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dec_pt_index = self.base.value.len();
|
||||||
|
self.base.value.push(self.dec_symbol);
|
||||||
|
self.has_decimal = true;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_decimal_pt(&self) -> bool {
|
||||||
|
self.has_decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_begin_exponent(&mut self) -> bool {
|
||||||
|
self.try_add_decimal_pt();
|
||||||
|
|
||||||
|
if self.has_exponent {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.has_exponent = true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backspace(&mut self) {
|
||||||
|
if self.has_exponent {
|
||||||
|
if !self.exponent.is_empty() {
|
||||||
|
self.exponent.value.pop();
|
||||||
|
if self.exponent.is_empty() {
|
||||||
|
self.exponent.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.has_exponent = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !self.base.is_empty() {
|
||||||
|
self.base.value.pop();
|
||||||
|
if self.base.value == "0" {
|
||||||
|
self.base.value.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.value.len() <= self.dec_pt_index {
|
||||||
|
self.has_decimal = false;
|
||||||
|
self.dec_pt_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
self.base.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_decimal_symbol(&mut self, dec_symbol: char) {
|
||||||
|
if self.dec_symbol != dec_symbol {
|
||||||
|
self.dec_symbol = dec_symbol;
|
||||||
|
|
||||||
|
if self.has_decimal {
|
||||||
|
self.base.value.replace_range(self.dec_pt_index..=self.dec_pt_index, &dec_symbol.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.base.is_empty() && !self.has_exponent && self.exponent.is_empty() && !self.has_decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self, radix: u32) -> String {
|
||||||
|
if self.base.value.len() > 84 || (self.has_exponent && self.exponent.value.len() > 84) {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
if self.base.is_negative() {
|
||||||
|
result.push('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.base.is_empty() {
|
||||||
|
result.push('0');
|
||||||
|
} else {
|
||||||
|
result.push_str(&self.base.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.has_exponent {
|
||||||
|
if !self.has_decimal {
|
||||||
|
result.push(self.dec_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(if radix == 10 { 'e' } else { '^' });
|
||||||
|
result.push(if self.exponent.is_negative() { '-' } else { '+' });
|
||||||
|
|
||||||
|
if self.exponent.is_empty() {
|
||||||
|
result.push('0');
|
||||||
|
} else {
|
||||||
|
result.push_str(&self.exponent.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.len() > 168 {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_rational(&self, radix: u32, precision: i32) -> Rational {
|
||||||
|
let rat = string_to_rat(self.base.is_negative(), &self.base.value, self.exponent.is_negative(), &self.exponent.value, radix, precision);
|
||||||
|
if rat.is_none() {
|
||||||
|
return Rational::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = Rational::from_rat(rat.unwrap());
|
||||||
|
destroy_rat(rat.unwrap());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
28
src/CalcManager/Header Files/CalcUtils.rs
Normal file
28
src/CalcManager/Header Files/CalcUtils.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
pub type OpCode = usize;
|
||||||
|
|
||||||
|
pub fn is_op_in_range(op: OpCode, x: u32, y: u32) -> bool {
|
||||||
|
(op >= x as usize) && (op <= y as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_bin_op_code(op_code: OpCode) -> bool {
|
||||||
|
is_op_in_range(op_code, IDC_AND, IDC_PWR) || is_op_in_range(op_code, IDC_BINARYEXTENDEDFIRST, IDC_BINARYEXTENDEDLAST)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_unary_op_code(op_code: OpCode) -> bool {
|
||||||
|
is_op_in_range(op_code, IDC_UNARYFIRST, IDC_UNARYLAST) || is_op_in_range(op_code, IDC_UNARYEXTENDEDFIRST, IDC_UNARYEXTENDEDLAST)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_digit_op_code(op_code: OpCode) -> bool {
|
||||||
|
is_op_in_range(op_code, IDC_0, IDC_F)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_gui_setting_op_code(op_code: OpCode) -> bool {
|
||||||
|
if is_op_in_range(op_code, IDM_HEX, IDM_BIN) || is_op_in_range(op_code, IDM_QWORD, IDM_BYTE) || is_op_in_range(op_code, IDM_DEG, IDM_GRAD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match op_code {
|
||||||
|
IDC_INV | IDC_FE | IDC_MCLEAR | IDC_BACK | IDC_EXP | IDC_STORE | IDC_MPLUS | IDC_MMINUS => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
12
src/CalcManager/Header Files/EngineStrings.rs
Normal file
12
src/CalcManager/Header Files/EngineStrings.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref ENGINE_STRINGS: HashMap<&'static str, &'static str> = {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert("SIDS_DECIMAL_SEPARATOR", ".");
|
||||||
|
m.insert("SIDS_THOUSANDS_SEPARATOR", ",");
|
||||||
|
m.insert("SIDS_GROUPING", "3;0");
|
||||||
|
m.insert("SIDS_NUMBER", "0");
|
||||||
|
m
|
||||||
|
};
|
||||||
|
}
|
291
src/CalcManager/Header Files/History.rs
Normal file
291
src/CalcManager/Header Files/History.rs
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::calc_display::ICalcDisplay;
|
||||||
|
use crate::calc_history::IHistoryDisplay;
|
||||||
|
use crate::calc_utils::Rational;
|
||||||
|
|
||||||
|
const MAXPRECDEPTH: usize = 25;
|
||||||
|
|
||||||
|
pub struct CHistoryCollector {
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
i_cur_line_hist_start: i32,
|
||||||
|
last_op_start_index: i32,
|
||||||
|
last_bin_op_start_index: i32,
|
||||||
|
operand_indices: [i32; MAXPRECDEPTH],
|
||||||
|
cur_operand_index: i32,
|
||||||
|
b_last_opnd_brace: bool,
|
||||||
|
decimal_symbol: char,
|
||||||
|
sp_tokens: Option<Arc<Mutex<VecDeque<(String, i32)>>>>,
|
||||||
|
sp_commands: Option<Arc<Mutex<VecDeque<Arc<dyn IExpressionCommand>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CHistoryCollector {
|
||||||
|
pub fn new(
|
||||||
|
p_calc_display: Option<Arc<dyn ICalcDisplay>>,
|
||||||
|
p_history_display: Option<Arc<dyn IHistoryDisplay>>,
|
||||||
|
decimal_symbol: char,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
p_history_display,
|
||||||
|
p_calc_display,
|
||||||
|
i_cur_line_hist_start: -1,
|
||||||
|
last_op_start_index: -1,
|
||||||
|
last_bin_op_start_index: -1,
|
||||||
|
operand_indices: [-1; MAXPRECDEPTH],
|
||||||
|
cur_operand_index: 0,
|
||||||
|
b_last_opnd_brace: false,
|
||||||
|
decimal_symbol,
|
||||||
|
sp_tokens: None,
|
||||||
|
sp_commands: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_opnd_to_history(&mut self, num_str: &str, rat: &Rational, f_repetition: bool) {
|
||||||
|
let i_command_end = self.add_command(self.get_operand_commands_from_string(num_str, rat));
|
||||||
|
self.last_op_start_index = self.ich_add_sz_to_equation_sz(num_str, i_command_end);
|
||||||
|
|
||||||
|
if f_repetition {
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
self.b_last_opnd_brace = false;
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_last_opnd_from_history(&mut self) {
|
||||||
|
self.truncate_equation_sz_from_ich(self.last_op_start_index);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_bin_op_to_history(&mut self, n_op_code: i32, is_integer_mode: bool, f_no_repetition: bool) {
|
||||||
|
let i_command_end = self.add_command(Arc::new(CBinaryCommand::new(n_op_code)));
|
||||||
|
self.last_bin_op_start_index = self.ich_add_sz_to_equation_sz(" ", -1);
|
||||||
|
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_binary_string(n_op_code, is_integer_mode), i_command_end);
|
||||||
|
self.ich_add_sz_to_equation_sz(" ", -1);
|
||||||
|
|
||||||
|
if f_no_repetition {
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_last_bin_op(&mut self, n_op_code: i32, f_prec_inv_to_higher: bool, is_integer_mode: bool) {
|
||||||
|
self.truncate_equation_sz_from_ich(self.last_bin_op_start_index);
|
||||||
|
if f_prec_inv_to_higher {
|
||||||
|
self.enclose_prec_inversion_brackets();
|
||||||
|
}
|
||||||
|
self.add_bin_op_to_history(n_op_code, is_integer_mode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_last_opnd_start(&mut self, ich_opnd_start: i32) {
|
||||||
|
let ich = if ich_opnd_start == -1 {
|
||||||
|
self.last_op_start_index
|
||||||
|
} else {
|
||||||
|
ich_opnd_start
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.cur_operand_index < self.operand_indices.len() as i32 {
|
||||||
|
self.operand_indices[self.cur_operand_index as usize] = ich;
|
||||||
|
self.cur_operand_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_last_opnd_start(&mut self) {
|
||||||
|
if self.cur_operand_index > 0 {
|
||||||
|
self.cur_operand_index -= 1;
|
||||||
|
self.last_op_start_index = self.operand_indices[self.cur_operand_index as usize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_open_brace_to_history(&mut self) {
|
||||||
|
self.add_command(Arc::new(CParentheses::new(IDC_OPENP)));
|
||||||
|
let ich_opnd_start = self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_OPENP), -1);
|
||||||
|
self.push_last_opnd_start(ich_opnd_start);
|
||||||
|
|
||||||
|
self.set_expression_display();
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_close_brace_to_history(&mut self) {
|
||||||
|
self.add_command(Arc::new(CParentheses::new(IDC_CLOSEP)));
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_CLOSEP), -1);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.pop_last_opnd_start();
|
||||||
|
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
self.b_last_opnd_brace = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enclose_prec_inversion_brackets(&mut self) {
|
||||||
|
let ich_start = if self.cur_operand_index > 0 {
|
||||||
|
self.operand_indices[self.cur_operand_index as usize - 1]
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
self.insert_sz_in_equation_sz(&CCalcEngine::op_code_to_string(IDC_OPENP), -1, ich_start);
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_CLOSEP), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f_opnd_added_to_history(&self) -> bool {
|
||||||
|
self.last_op_start_index != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complete_history_line(&mut self, num_str: &str) {
|
||||||
|
if let Some(p_history_display) = &self.p_history_display {
|
||||||
|
let added_item_index = p_history_display.add_to_history(
|
||||||
|
self.sp_tokens.clone().unwrap(),
|
||||||
|
self.sp_commands.clone().unwrap(),
|
||||||
|
num_str,
|
||||||
|
);
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.on_history_item_added(added_item_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sp_tokens = None;
|
||||||
|
self.sp_commands = None;
|
||||||
|
self.i_cur_line_hist_start = -1;
|
||||||
|
self.reinit_history();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complete_equation(&mut self, num_str: &str) {
|
||||||
|
self.ich_add_sz_to_equation_sz(&CCalcEngine::op_code_to_string(IDC_EQU), -1);
|
||||||
|
self.set_expression_display();
|
||||||
|
self.complete_history_line(num_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_history_line(&mut self, err_str: &str) {
|
||||||
|
if err_str.is_empty() {
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.set_expression_display(
|
||||||
|
Arc::new(Mutex::new(VecDeque::new())),
|
||||||
|
Arc::new(Mutex::new(VecDeque::new())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.i_cur_line_hist_start = -1;
|
||||||
|
self.reinit_history();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ich_add_sz_to_equation_sz(&mut self, str: &str, i_command_index: i32) -> i32 {
|
||||||
|
if self.sp_tokens.is_none() {
|
||||||
|
self.sp_tokens = Some(Arc::new(Mutex::new(VecDeque::new())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_tokens.push_back((str.to_string(), i_command_index));
|
||||||
|
(sp_tokens.len() - 1) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_sz_in_equation_sz(&mut self, str: &str, i_command_index: i32, ich: i32) {
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_tokens.insert(ich as usize, (str.to_string(), i_command_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate_equation_sz_from_ich(&mut self, ich: i32) {
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
let mut sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
|
||||||
|
let mut min_idx = -1;
|
||||||
|
let n_tokens = sp_tokens.len();
|
||||||
|
|
||||||
|
for i in ich as usize..n_tokens {
|
||||||
|
let cur_token_id = sp_tokens[i].1;
|
||||||
|
if cur_token_id != -1 {
|
||||||
|
if min_idx == -1 || cur_token_id < min_idx {
|
||||||
|
min_idx = cur_token_id;
|
||||||
|
sp_commands.truncate(min_idx as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_tokens.truncate(ich as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_expression_display(&self) {
|
||||||
|
if let Some(p_calc_display) = &self.p_calc_display {
|
||||||
|
p_calc_display.set_expression_display(
|
||||||
|
self.sp_tokens.clone().unwrap(),
|
||||||
|
self.sp_commands.clone().unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_command(&mut self, sp_command: Arc<dyn IExpressionCommand>) -> i32 {
|
||||||
|
if self.sp_commands.is_none() {
|
||||||
|
self.sp_commands = Some(Arc::new(Mutex::new(VecDeque::new())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
sp_commands.push_back(sp_command);
|
||||||
|
(sp_commands.len() - 1) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_history_expression(&mut self, radix: u32, precision: i32) {
|
||||||
|
if self.sp_tokens.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sp_tokens = self.sp_tokens.as_ref().unwrap().lock().unwrap();
|
||||||
|
let sp_commands = self.sp_commands.as_ref().unwrap().lock().unwrap();
|
||||||
|
|
||||||
|
for token in sp_tokens.iter_mut() {
|
||||||
|
let command_position = token.1;
|
||||||
|
if command_position != -1 {
|
||||||
|
let exp_command = &sp_commands[command_position as usize];
|
||||||
|
if exp_command.get_command_type() == CommandType::OperandCommand {
|
||||||
|
let opnd_command = exp_command.as_any().downcast_ref::<COpndCommand>().unwrap();
|
||||||
|
token.0 = opnd_command.get_string(radix, precision);
|
||||||
|
opnd_command.set_commands(self.get_operand_commands_from_string(&token.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_expression_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_decimal_symbol(&mut self, decimal_symbol: char) {
|
||||||
|
self.decimal_symbol = decimal_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_operand_commands_from_string(&self, num_str: &str) -> Arc<dyn IExpressionCommand> {
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
let f_negative = num_str.starts_with('-');
|
||||||
|
|
||||||
|
for ch in num_str.chars().skip(if f_negative { 1 } else { 0 }) {
|
||||||
|
match ch {
|
||||||
|
ch if ch == self.decimal_symbol => commands.push(IDC_PNT),
|
||||||
|
'e' => commands.push(IDC_EXP),
|
||||||
|
'-' => commands.push(IDC_SIGN),
|
||||||
|
'+' => {}
|
||||||
|
ch => {
|
||||||
|
let num = ch as i32 - '0' as i32;
|
||||||
|
commands.push(num + IDC_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f_negative {
|
||||||
|
commands.push(IDC_SIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::new(COpndCommand::new(commands, f_negative, num_str.contains(self.decimal_symbol), num_str.contains('e')))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reinit_history(&mut self) {
|
||||||
|
self.last_op_start_index = -1;
|
||||||
|
self.last_bin_op_start_index = -1;
|
||||||
|
self.cur_operand_index = 0;
|
||||||
|
self.b_last_opnd_brace = false;
|
||||||
|
if let Some(sp_tokens) = &self.sp_tokens {
|
||||||
|
sp_tokens.lock().unwrap().clear();
|
||||||
|
}
|
||||||
|
if let Some(sp_commands) = &self.sp_commands {
|
||||||
|
sp_commands.lock().unwrap().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/CalcManager/Header Files/ICalcDisplay.rs
Normal file
17
src/CalcManager/Header Files/ICalcDisplay.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
pub trait ICalcDisplay {
|
||||||
|
fn set_primary_display(&self, text: &str, is_error: bool);
|
||||||
|
fn set_is_in_error(&self, is_in_error: bool);
|
||||||
|
fn set_expression_display(
|
||||||
|
&self,
|
||||||
|
tokens: std::sync::Arc<std::vec::Vec<(String, i32)>>,
|
||||||
|
commands: std::sync::Arc<std::vec::Vec<std::sync::Arc<dyn IExpressionCommand>>>,
|
||||||
|
);
|
||||||
|
fn set_parenthesis_number(&self, count: u32);
|
||||||
|
fn on_no_right_paren_added(&self);
|
||||||
|
fn max_digits_reached(&self);
|
||||||
|
fn binary_operator_received(&self);
|
||||||
|
fn on_history_item_added(&self, added_item_index: u32);
|
||||||
|
fn set_memorized_numbers(&self, memorized_numbers: Vec<String>);
|
||||||
|
fn memory_item_changed(&self, index_of_memory: u32);
|
||||||
|
fn input_changed(&self);
|
||||||
|
}
|
6
src/CalcManager/Header Files/IHistoryDisplay.rs
Normal file
6
src/CalcManager/Header Files/IHistoryDisplay.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pub trait IHistoryDisplay {
|
||||||
|
fn add_item_to_history(&self, item: &str);
|
||||||
|
fn remove_item_from_history(&self, index: usize);
|
||||||
|
fn clear_history(&self);
|
||||||
|
fn get_history_items(&self) -> Vec<String>;
|
||||||
|
}
|
54
src/CalcManager/Header Files/Number.rs
Normal file
54
src/CalcManager/Header Files/Number.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
pub struct Number {
|
||||||
|
sign: i32,
|
||||||
|
exp: i32,
|
||||||
|
mantissa: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Number {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
sign: 1,
|
||||||
|
exp: 0,
|
||||||
|
mantissa: vec![0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_values(sign: i32, exp: i32, mantissa: Vec<u32>) -> Self {
|
||||||
|
Self { sign, exp, mantissa }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pnumber(p: &PNUMBER) -> Self {
|
||||||
|
let mut mantissa = Vec::with_capacity(p.cdigit as usize);
|
||||||
|
mantissa.extend_from_slice(&p.mant[..p.cdigit as usize]);
|
||||||
|
Self {
|
||||||
|
sign: p.sign,
|
||||||
|
exp: p.exp,
|
||||||
|
mantissa,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pnumber(&self) -> PNUMBER {
|
||||||
|
let mut ret = PNUMBER::new(self.mantissa.len() + 1);
|
||||||
|
ret.sign = self.sign;
|
||||||
|
ret.exp = self.exp;
|
||||||
|
ret.cdigit = self.mantissa.len() as i32;
|
||||||
|
ret.mant[..self.mantissa.len()].copy_from_slice(&self.mantissa);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(&self) -> i32 {
|
||||||
|
self.sign
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exp(&self) -> i32 {
|
||||||
|
self.exp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mantissa(&self) -> &Vec<u32> {
|
||||||
|
&self.mantissa
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_zero(&self) -> bool {
|
||||||
|
self.mantissa.iter().all(|&x| x == 0)
|
||||||
|
}
|
||||||
|
}
|
6
src/CalcManager/Header Files/RadixType.rs
Normal file
6
src/CalcManager/Header Files/RadixType.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pub enum RadixType {
|
||||||
|
Decimal,
|
||||||
|
Hexadecimal,
|
||||||
|
Octal,
|
||||||
|
Binary,
|
||||||
|
}
|
378
src/CalcManager/Header Files/Rational.rs
Normal file
378
src/CalcManager/Header Files/Rational.rs
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
pub struct Rational {
|
||||||
|
p: Number,
|
||||||
|
q: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rational {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::new(),
|
||||||
|
q: Number::with_values(1, 0, vec![1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_number(n: &Number) -> Self {
|
||||||
|
let mut q_exp = 0;
|
||||||
|
if n.exp() < 0 {
|
||||||
|
q_exp -= n.exp();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
p: Number::with_values(n.sign(), 0, n.mantissa().clone()),
|
||||||
|
q: Number::with_values(1, q_exp, vec![1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_values(p: Number, q: Number) -> Self {
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_i32(i: i32) -> Self {
|
||||||
|
let prat = i32torat(i);
|
||||||
|
let p = Number::from_pnumber(&prat.pp);
|
||||||
|
let q = Number::from_pnumber(&prat.pq);
|
||||||
|
destroyrat(prat);
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u32(ui: u32) -> Self {
|
||||||
|
let prat = ui32torat(ui);
|
||||||
|
let p = Number::from_pnumber(&prat.pp);
|
||||||
|
let q = Number::from_pnumber(&prat.pq);
|
||||||
|
destroyrat(prat);
|
||||||
|
Self { p, q }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u64(ui: u64) -> Self {
|
||||||
|
let hi = (ui >> 32) as u32;
|
||||||
|
let lo = ui as u32;
|
||||||
|
let temp = Rational::from_u32(hi) << 32 | Rational::from_u32(lo);
|
||||||
|
Self {
|
||||||
|
p: temp.p,
|
||||||
|
q: temp.q,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_prat(prat: &PRAT) -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::from_pnumber(&prat.pp),
|
||||||
|
q: Number::from_pnumber(&prat.pq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_prat(&self) -> PRAT {
|
||||||
|
let mut ret = PRAT::new();
|
||||||
|
ret.pp = self.p.to_pnumber();
|
||||||
|
ret.pq = self.q.to_pnumber();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn p(&self) -> &Number {
|
||||||
|
&self.p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn q(&self) -> &Number {
|
||||||
|
&self.q
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negate(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
p: Number::with_values(-self.p.sign(), self.p.exp(), self.p.mantissa().clone()),
|
||||||
|
q: self.q.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
addrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
subrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
mulrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
divrat(&mut lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rem_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = rhs.to_prat();
|
||||||
|
remrat(&mut lhs_rat, &rhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shl_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
lshrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shr_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
rshrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
andrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
orrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xor_assign(&mut self, rhs: &Self) {
|
||||||
|
let mut lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = self.to_prat();
|
||||||
|
xorrat(&mut lhs_rat, &rhs_rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
*self = Rational::from_prat(&lhs_rat);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self, radix: u32, fmt: NumberFormat, precision: i32) -> String {
|
||||||
|
let rat = self.to_prat();
|
||||||
|
let result = rat_to_string(&rat, fmt, radix, precision);
|
||||||
|
destroyrat(rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_u64(&self) -> u64 {
|
||||||
|
let rat = self.to_prat();
|
||||||
|
let result = rat_to_u64(&rat, RATIONAL_BASE, RATIONAL_PRECISION);
|
||||||
|
destroyrat(rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Rational {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = other.to_prat();
|
||||||
|
let result = rat_equ(&lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Rational {}
|
||||||
|
|
||||||
|
impl PartialOrd for Rational {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Rational {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
let lhs_rat = self.to_prat();
|
||||||
|
let rhs_rat = other.to_prat();
|
||||||
|
let result = rat_cmp(&lhs_rat, &rhs_rat, RATIONAL_PRECISION);
|
||||||
|
destroyrat(lhs_rat);
|
||||||
|
destroyrat(rhs_rat);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::AddAssign for Rational {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.add_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::SubAssign for Rational {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.sub_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::MulAssign for Rational {
|
||||||
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
|
self.mul_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DivAssign for Rational {
|
||||||
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
|
self.div_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::RemAssign for Rational {
|
||||||
|
fn rem_assign(&mut self, rhs: Self) {
|
||||||
|
self.rem_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::ShlAssign for Rational {
|
||||||
|
fn shl_assign(&mut self, rhs: Self) {
|
||||||
|
self.shl_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::ShrAssign for Rational {
|
||||||
|
fn shr_assign(&mut self, rhs: Self) {
|
||||||
|
self.shr_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitAndAssign for Rational {
|
||||||
|
fn bitand_assign(&mut self, rhs: Self) {
|
||||||
|
self.and_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOrAssign for Rational {
|
||||||
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
|
self.or_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitXorAssign for Rational {
|
||||||
|
fn bitxor_assign(&mut self, rhs: Self) {
|
||||||
|
self.xor_assign(&rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
self.negate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.add_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.sub_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.mul_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Div for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.div_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Rem for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn rem(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.rem_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Shl for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn shl(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.shl_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Shr for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn shr(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.shr_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitAnd for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitand(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.and_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOr for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.or_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitXor for Rational {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitxor(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self.xor_assign(rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
19
src/CalcManager/Header Files/RationalMath.rs
Normal file
19
src/CalcManager/Header Files/RationalMath.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
pub struct RationalMath;
|
||||||
|
|
||||||
|
impl RationalMath {
|
||||||
|
pub fn add(a: Rational, b: Rational) -> Rational {
|
||||||
|
// Implementation of addition for Rational numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtract(a: Rational, b: Rational) -> Rational {
|
||||||
|
// Implementation of subtraction for Rational numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiply(a: Rational, b: Rational) -> Rational {
|
||||||
|
// Implementation of multiplication for Rational numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn divide(a: Rational, b: Rational) -> Rational {
|
||||||
|
// Implementation of division for Rational numbers
|
||||||
|
}
|
||||||
|
}
|
37
src/CalcManager/NumberFormattingUtils.rs
Normal file
37
src/CalcManager/NumberFormattingUtils.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
pub struct NumberFormattingUtils;
|
||||||
|
|
||||||
|
impl NumberFormattingUtils {
|
||||||
|
pub fn format_number(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Normal, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_scientific(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Scientific, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_engineering(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Engineering, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_fixed(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Fixed, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_currency(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Currency, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_percent(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Percent, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_fraction(number: &Rational, radix: u32, precision: i32) -> String {
|
||||||
|
number.to_string(radix, NumberFormat::Fraction, precision)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_number_custom(number: &Rational, radix: u32, precision: i32, format: NumberFormat) -> String {
|
||||||
|
number.to_string(radix, format, precision)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue