From b7f39a5cf7311a5863a53a3d8bbc4a8a25e00087 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 24 Sep 2020 11:28:13 -0400 Subject: [PATCH] More work on parsing numbers from strings --- src/bigint.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/src/bigint.rs b/src/bigint.rs index e8c0a1e..6269714 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -135,7 +135,36 @@ impl BigInt { /// Only alphanumeric characters are considered, so exponents and /// other forms are not parsed pub fn from_str_radix(s: T, radix: usize) -> BigInt { - let input = s.to_string(); + let input = s.to_string().to_ascii_uppercase(); + let input = input.trim(); + + assert!( + radix > 0 && radix <= 36, + "Radix must be between 1 and 36, inclusive. Given radix: {}", + radix + ); + + // In base 1, number of place values = total value + if radix == 1 { + let mut raw_digits: Vec = Vec::with_capacity(input.len()); + for char in input.chars() { + match char { + '1' => raw_digits.push(1), + _ => continue, + } + } + + return BigInt::from(raw_digits.len()); + } + + // If the number fits in a usize, try the easy way + let easy_res = usize::from_str_radix(input, radix as u32); + if easy_res.is_ok() { + return BigInt::from(easy_res.unwrap()); + } + + // TODO: consider parsing out the error, to tell if the + // parsed result is valid for the base // Convert each digit to it's decimal representation let mut raw_digits: Vec = Vec::with_capacity(input.len()); @@ -148,8 +177,6 @@ impl BigInt { // Calculate the decimal value by calculating the value // of each place value - - // In base 1, number of place values = total value todo!(); } @@ -907,21 +934,56 @@ mod tests { #[test] #[should_panic] - fn test_from_str() { + fn test_from_str_large() { + let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"; + BigInt::from(str); + } + + #[test] + fn test_from_str_small() { let str = "012345"; - BigInt::from(str); + let num = BigInt::from(str); + assert_eq!(num.inner[0], 12345usize); } #[test] #[should_panic] - fn test_from_string() { + fn test_from_string_large() { + let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"); + BigInt::from(str); + } + + #[test] + fn test_from_string_small() { let str = String::from("012345"); - BigInt::from(str); + let num = BigInt::from(str); + assert_eq!(num.inner[0], 12345usize); + } + + #[test] + fn test_from_str_radix_1() { + let s = "1".repeat(32); + let num = BigInt::from_str_radix(s, 1); + assert_eq!(num.inner[0], 32usize); } #[test] #[should_panic] - fn test_from_str_radix() { - BigInt::from_str_radix("123456", 16); + fn test_from_str_radix_large() { + BigInt::from_str_radix("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321", 36); + } + + #[test] + fn test_from_str_radix_small() { + let num = BigInt::from_str_radix("FEDCBA", 16); + assert!(num.inner[0] > 0, "Number is not greater than 0"); + assert!(num.inner[0] < usize::MAX, "Result is larger than usize"); + assert_eq!(num.inner[0], 0xFEDCBAusize); + } + + #[test] + fn test_from_str_radix_lowercase() { + let num = BigInt::from_str_radix("fedcba", 16); + assert_eq!(num.inner[0], 0xFEDCBAusize); } }