Created
November 12, 2022 00:52
-
-
Save LiosK/d655130b2f563bba1e35d638bf4bdf90 to your computer and use it in GitHub Desktop.
Converts a digit value array in `src_base` to that in `dst_base`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// XXX NOT TESTED | |
/// Converts a digit value array in `src_base` to that in `dst_base`. | |
/// | |
/// # Panics | |
/// | |
/// Panics if: | |
/// | |
/// - `src_base` is not between 2 and 256, inclusive; | |
/// - `dst_base` is not between 2 and 256, inclusive; or, | |
/// - `dst` is too small to store the result. | |
#[inline] | |
pub fn convert_base(src: &[u8], src_base: usize, dst: &mut [u8], dst_base: usize) { | |
assert!((2..=256).contains(&src_base) && (2..=256).contains(&dst_base)); | |
let (src_base, dst_base) = (src_base as u64, dst_base as u64); | |
let (word_len, word_base) = compute_word_size(src_base, dst_base); | |
dst.fill(0); | |
let mut dst_used = dst.len() - 1; // storage to memorize range of `dst` filled | |
// read `word_len` digits from `src` for each outer loop | |
for chunk in src.rchunks(word_len).rev() { | |
let mut carry = chunk.iter().fold(0u64, |acc, e| acc * src_base + *e as u64); | |
// fill in `dst` from right to left, while carrying up prior result to left | |
for (i, e) in dst.iter_mut().enumerate().rev() { | |
carry += *e as u64 * word_base; | |
*e = (carry % dst_base) as u8; | |
carry /= dst_base; | |
// break inner loop when `carry` and remaining `dst` digits are all zero | |
if carry == 0 && i <= dst_used { | |
dst_used = i; | |
break; | |
} | |
} | |
assert_eq!(carry, 0, "too small dst"); | |
} | |
} | |
/// Determines the number of `src` digits to read for each outer loop. | |
const fn compute_word_size(src_base: u64, dst_base: u64) -> (usize, u64) { | |
let mut word_len = 0; | |
let mut word_base = 1; | |
while word_base < u64::MAX / (src_base * dst_base) { | |
word_len += 1; | |
word_base *= src_base; | |
} | |
(word_len, word_base) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment