diff --git a/integer/src/convert.rs b/integer/src/convert.rs index 6c9fff6..d1d6c2a 100644 --- a/integer/src/convert.rs +++ b/integer/src/convert.rs @@ -1,18 +1,31 @@ //! Conversions between types. use crate::{ - add, arch::word::{DoubleWord, Word}, buffer::Buffer, helper_macros::debug_assert_zero, ibig::IBig, math, primitive::{self, PrimitiveSigned, PrimitiveUnsigned, DWORD_BITS_USIZE, DWORD_BYTES, WORD_BITS, WORD_BITS_USIZE, WORD_BYTES}, repr::{ + add, + arch::word::{DoubleWord, Word}, + buffer::Buffer, + helper_macros::debug_assert_zero, + ibig::IBig, + math, + primitive::{ + self, PrimitiveSigned, PrimitiveUnsigned, DWORD_BITS_USIZE, DWORD_BYTES, WORD_BITS, + WORD_BITS_USIZE, WORD_BYTES, + }, + repr::{ Repr, TypedReprRef::{self, *}, - }, shift, ubig::UBig, Sign::* + }, + shift, + ubig::UBig, + Sign::*, }; -use alloc::{boxed::Box, vec::Vec, vec}; -use static_assertions::const_assert; +use alloc::{boxed::Box, vec, vec::Vec}; use core::convert::{TryFrom, TryInto}; use dashu_base::{ Approximation::{self, *}, BitTest, ConversionError, FloatEncoding, PowerOfTwo, Sign, }; +use static_assertions::const_assert; impl Default for UBig { /// Default value: 0. @@ -65,12 +78,12 @@ fn words_to_be_bytes(words: &[Word]) -> Vec { } /// Convert a integer into an array of chunks by bit chunking -/// +/// /// Requirements: /// - chunks_out.len() tightly fits all chunks. /// - All words in chunks_out must has enough length (i.e. ceil(chunk_bits / WORD_BITS)) fn words_to_chunks(words: &[Word], chunks_out: &mut [&mut [Word]], chunk_bits: usize) { - assert!(words.len() > 0); + assert!(!words.is_empty()); if chunk_bits % WORD_BITS_USIZE == 0 { // shortcut for word aligned chunks @@ -78,15 +91,16 @@ fn words_to_chunks(words: &[Word], chunks_out: &mut [&mut [Word]], chunk_bits: u for (i, chunk_out) in chunks_out.iter_mut().enumerate() { let start_pos = i * words_per_chunk; let end_pos = start_pos + words_per_chunk; - chunk_out[..end_pos-start_pos].copy_from_slice(&words[start_pos..end_pos]); + chunk_out[..end_pos - start_pos].copy_from_slice(&words[start_pos..end_pos]); } } else { - let bit_len = words.len() * WORD_BITS_USIZE - words.last().unwrap().leading_zeros() as usize; + let bit_len = + words.len() * WORD_BITS_USIZE - words.last().unwrap().leading_zeros() as usize; for (i, chunk_out) in chunks_out.iter_mut().enumerate() { let start = i * chunk_bits; let end = bit_len.min(start + chunk_bits); debug_assert!(start < end); // make sure that there is no empty chunk - + let (start_pos, end_pos) = (start / WORD_BITS_USIZE, end / WORD_BITS_USIZE); let end_bits = (end % WORD_BITS_USIZE) as u32; let len; @@ -104,18 +118,26 @@ fn words_to_chunks(words: &[Word], chunks_out: &mut [&mut [Word]], chunk_bits: u } /// Convert chunks to a single integer by shifting and adding. -/// +/// /// Requirements: /// - words_out must have enough length /// - buffer must have enough length: buffer.len() > max(chunk.len()) for chunk in chunks -fn chunks_to_words(words_out: &mut [Word], chunks: &[&[Word]], chunk_bits: usize, buffer: &mut [Word]) { - assert!(chunks.len() > 0); +fn chunks_to_words( + words_out: &mut [Word], + chunks: &[&[Word]], + chunk_bits: usize, + buffer: &mut [Word], +) { + assert!(!chunks.is_empty()); for (i, chunk) in chunks.iter().enumerate() { let shift = i * chunk_bits; buffer[..chunk.len()].copy_from_slice(chunk); buffer[chunk.len()] = 0; shift::shl_in_place(&mut buffer[..=chunk.len()], (shift % WORD_BITS_USIZE) as u32); - debug_assert_zero!(add::add_in_place(&mut words_out[shift / WORD_BITS_USIZE..], &buffer[..=chunk.len()])); + debug_assert_zero!(add::add_in_place( + &mut words_out[shift / WORD_BITS_USIZE..], + &buffer[..=chunk.len()] + )); } } @@ -235,7 +257,7 @@ impl TypedReprRef<'_> { buffers } }, - RefLarge(words) =>{ + RefLarge(words) => { let mut buffers = Vec::::new(); let word_per_chunk = math::ceil_div(chunk_bits, WORD_BITS_USIZE); buffers.resize_with(chunk_count, || { @@ -244,10 +266,14 @@ impl TypedReprRef<'_> { buf.push_zeros(word_per_chunk + 1); buf }); - let mut buffer_refs: Box<[&mut [Word]]> = buffers.iter_mut().map(|buf| buf.as_mut()).collect(); + let mut buffer_refs: Box<[&mut [Word]]> = + buffers.iter_mut().map(|buf| buf.as_mut()).collect(); words_to_chunks(words, &mut buffer_refs, chunk_bits); - buffers.into_iter().map(|buf| Repr::from_buffer(buf)).collect() - } + buffers + .into_iter() + .map(Repr::from_buffer) + .collect() + } } } } @@ -421,13 +447,13 @@ impl UBig { } /// Reconstruct an integer from a group of bit chunks. - /// + /// /// Denote the chunks as C_i, then this function calculates sum(C_i * 2^(i * chunk_bits)) /// for i from 0 to len(chunks) - 1. - /// + /// /// Note that it's allowed for each chunk to have more bits than chunk_bits, which is different /// from the [UBig::to_chunks] method. - /// + /// /// # Examples /// /// ``` @@ -437,9 +463,9 @@ impl UBig { /// UBig::from(0x010203u32) /// ); /// ``` - /// + /// /// # Panics - /// + /// /// Panics if chunk_bits is zero. #[inline] pub fn from_chunks<'a, I: Iterator>(chunks: I, chunk_bits: usize) -> Self { @@ -459,13 +485,17 @@ impl UBig { /// assert_eq!(*UBig::from(0x010203u32).to_chunks(8), /// [0x3u8.into(), 0x2u8.into(), 0x1u8.into()]); /// ``` - /// + /// /// # Panics - /// + /// /// Panics if chunk_bits is zero. #[inline] pub fn to_chunks(&self, chunk_bits: usize) -> Box<[UBig]> { - self.repr().to_chunks(chunk_bits).into_iter().map(|r| UBig(r)).collect() + self.repr() + .to_chunks(chunk_bits) + .into_iter() + .map(UBig) + .collect() } /// Convert to f32. diff --git a/integer/tests/convert.rs b/integer/tests/convert.rs index af9d8c3..286c86e 100644 --- a/integer/tests/convert.rs +++ b/integer/tests/convert.rs @@ -58,13 +58,30 @@ fn test_from_to_chunks() { assert_eq!(*ubig!(0xabcd).to_chunks(8), [ubig!(0xcd), ubig!(0xab)]); assert_eq!(*ubig!(0xabcd).to_chunks(12), [ubig!(0xbcd), ubig!(0xa)]); assert_eq!(*ubig!(0xabcd).to_chunks(16), [ubig!(0xabcd)]); - assert_eq!(*ubig!(0x123456789abcdef).to_chunks(17), [ubig!(0x1cdef), ubig!(0x1c4d5), ubig!(0xd159), ubig!(0x24)]); - assert_eq!(*ubig!(0x123456789abcdef0123456789abcdef0123456789abcdef).to_chunks(29), [ - ubig!(0x9abcdef), ubig!(0x91a2b3c), ubig!(0xaf37bc0), ubig!(0x68acf13), ubig!(0x1cdef012), ubig!(0x2b3c4d5), ubig!(0x48d) - ]); - assert_eq!(*ubig!(0x123456789abcdef0123456789abcdef0123456789abcdef).to_chunks(64), [ - ubig!(0x123456789abcdef), ubig!(0x123456789abcdef), ubig!(0x123456789abcdef) - ]); + assert_eq!( + *ubig!(0x123456789abcdef).to_chunks(17), + [ubig!(0x1cdef), ubig!(0x1c4d5), ubig!(0xd159), ubig!(0x24)] + ); + assert_eq!( + *ubig!(0x123456789abcdef0123456789abcdef0123456789abcdef).to_chunks(29), + [ + ubig!(0x9abcdef), + ubig!(0x91a2b3c), + ubig!(0xaf37bc0), + ubig!(0x68acf13), + ubig!(0x1cdef012), + ubig!(0x2b3c4d5), + ubig!(0x48d) + ] + ); + assert_eq!( + *ubig!(0x123456789abcdef0123456789abcdef0123456789abcdef).to_chunks(64), + [ + ubig!(0x123456789abcdef), + ubig!(0x123456789abcdef), + ubig!(0x123456789abcdef) + ] + ); assert_eq!(UBig::from_chunks(empty.iter(), 1), UBig::ZERO); assert_eq!(UBig::from_chunks([ubig!(1)].iter(), 1), UBig::ONE); @@ -74,7 +91,10 @@ fn test_from_to_chunks() { (ubig!(0xffff), vec![1, 3]), (ubig!(0xfefefefe), vec![3, 4]), (ubig!(0xffffffff000000001), vec![16, 32, 64, 65, 66]), - (ubig!(0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000), vec![13, 32, 64]), + ( + ubig!(0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000), + vec![13, 32, 64], + ), ]; for (n, chunk_bits) in test_cases { for bits in chunk_bits { diff --git a/python/src/convert.rs b/python/src/convert.rs index 6350182..9962631 100644 --- a/python/src/convert.rs +++ b/python/src/convert.rs @@ -216,12 +216,14 @@ impl<'a> UniInput<'a> { Self::Uint(x) => Ok(x.into()), Self::BUint(x) => Ok(x.0.clone()), Self::OBInt(x) => x.try_into().map_err(|_| err), - Self::BInt(x) => if let Some(u) = x.0.as_ubig() { - Ok(u.clone()) - } else { - Err(err) + Self::BInt(x) => { + if let Some(u) = x.0.as_ubig() { + Ok(u.clone()) + } else { + Err(err) + } } - _ => Err(err) + _ => Err(err), } } -} \ No newline at end of file +} diff --git a/python/src/int.rs b/python/src/int.rs index e374c76..be0c97a 100644 --- a/python/src/int.rs +++ b/python/src/int.rs @@ -419,14 +419,19 @@ impl UPy { if chunk_bits == 0 { Err(PyValueError::new_err(ERRMSG_ZERO_CHUNK_SIZE)) } else { - let iter = self.0.to_chunks(chunk_bits).into_vec().into_iter().map(|u| UPy(u).into_py(py)); + let iter = self + .0 + .to_chunks(chunk_bits) + .into_vec() + .into_iter() + .map(|u| UPy(u).into_py(py)); Ok(PyTuple::new(py, iter).into_py(py)) } } #[staticmethod] fn from_chunks(chunks: &PyAny, chunk_bits: usize) -> PyResult { if chunk_bits == 0 { - return Err(PyValueError::new_err(ERRMSG_ZERO_CHUNK_SIZE)) + return Err(PyValueError::new_err(ERRMSG_ZERO_CHUNK_SIZE)); } let mut input = Vec::new();