From d5083f4cce47567644fd1b2c5923e5d0dcd98d44 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sun, 7 Mar 2021 10:17:40 -0700 Subject: don't round-trip everything through strings!!! --- src/basic_actors.rs | 3 ++- src/main.rs | 3 ++- src/number.rs | 54 +++++++++++++++++++++++++++++------------------------ 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/basic_actors.rs b/src/basic_actors.rs index da391cf..130c1e2 100644 --- a/src/basic_actors.rs +++ b/src/basic_actors.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::convert::TryInto; use std::sync::mpsc::{SyncSender, Receiver}; use crate::actor::{Value, Type, Actorful, Slot}; @@ -98,7 +99,7 @@ impl Actorful for RepeatValue { if let Value::Number(count) = count { // TODO figure out what a smart thing to do would be here instead // this API design is deliberately suboptimal because i'd like to not do it - let count: usize = format!("{}", count).parse().unwrap(); + let count: usize = count.try_into().unwrap(); let vec = vec![value; count]; output_channels["List"].send(Value::List(vec)).unwrap(); } diff --git a/src/main.rs b/src/main.rs index 6bf920b..8617d6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::time::Duration; use minifb::{Key, Window, WindowOptions, MouseMode}; @@ -119,7 +120,7 @@ fn main() { let u32_data: Vec = data.into_iter() .map(|x| { if let actor::Value::Number(x) = x { - format!("{}", x).parse().unwrap() + x.try_into().unwrap() } else { panic!("bruh") } diff --git a/src/number.rs b/src/number.rs index 94a67f1..5ea7949 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,10 +1,12 @@ use std::cmp::max; -use std::fmt::{Display, Formatter, Result as FormatResult}; +use std::convert::TryFrom; +use std::num::TryFromIntError; use std::ops::Add; #[derive(Clone)] pub struct Number { - pub integer_part: String, + // least significant first + pub integer_part: Vec, } macro_rules! int_conv { @@ -12,7 +14,19 @@ macro_rules! int_conv { impl From<$t> for Number { fn from(x: $t) -> Number { Number { - integer_part: x.to_string(), + integer_part: vec![x as usize], + } + } + } + + impl TryFrom for $t { + type Error = TryFromIntError; + + fn try_from(x: Number) -> Result<$t, TryFromIntError> { + if x.integer_part.len() > 1 { + ::try_from(-1).map(|_| 0) + } else { + <$t>::try_from(x.integer_part[0]).map_err(|_| ::try_from(-1).unwrap_err()) } } } @@ -21,33 +35,25 @@ macro_rules! int_conv { int_conv!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize); -impl Display for Number { - fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult { - f.write_str(&self.integer_part) - } -} - impl Add for Number { type Output = Number; fn add(self, rhs: Self) -> Self::Output { let longest_ipart_len = max(self.integer_part.len(), rhs.integer_part.len()); - let self_padded = format!("{:0>len$}", self.integer_part, len=longest_ipart_len); - let rhs_padded = format!("{:0>len$}", rhs.integer_part, len=longest_ipart_len); - let mut result_ipart_reverse = "".to_string(); - let mut carry: u8 = 0; - for (self_char, rhs_char) in self_padded.chars().rev().zip(rhs_padded.chars().rev()) { - let self_char_val = self_char.to_digit(10).unwrap() as u8; - let rhs_char_val = rhs_char.to_digit(10).unwrap() as u8; - let sum = self_char_val + rhs_char_val + carry; - let sum_last_digit = (sum % 10).to_string().chars().next().unwrap(); - carry = sum / 10; - result_ipart_reverse.push(sum_last_digit); - } - if carry > 0 { - result_ipart_reverse.push_str(&carry.to_string()); + let mut result_ipart = vec![]; + let mut carry: usize = 0; + for i in 0..longest_ipart_len { + let self_part = self.integer_part.get(i).copied().unwrap_or(0); + let rhs_part = rhs.integer_part.get(i).copied().unwrap_or(0); + let (half_sum, early_carry) = self_part.overflowing_add(rhs_part); + let (full_sum, late_carry) = half_sum.overflowing_add(carry); + carry = if early_carry || late_carry { + 1 + } else { + 0 + }; + result_ipart.push(full_sum); } - let result_ipart = result_ipart_reverse.chars().rev().collect(); Number { integer_part: result_ipart, } -- cgit v1.2.3