dashu_int/ubig.rs
1//! Definitions of [UBig].
2//!
3//! Conversion from internal representations including [Buffer][crate::buffer::Buffer], [TypedRepr], [TypedReprRef]
4//! to [UBig] is not implemented, the designed way to construct UBig from them is first convert them
5//! into [Repr], and then directly construct from the [Repr]. This restriction is set to make
6//! the source type explicit.
7
8use crate::repr::{Repr, TypedRepr, TypedReprRef};
9
10/// An unsigned arbitrary precision integer.
11///
12/// `UBig` represents an arbitrarily large non-negative integer. Values that fit in a
13/// [`DoubleWord`](crate::DoubleWord) are inlined (no heap allocation); larger values are stored as a
14/// heap-allocated array of [`Word`](crate::Word)s. The type carries a niche bit, so
15/// [`Option<UBig>`] occupies the same space as [`UBig`].
16///
17/// For the full discussion — construction, parsing, printing, and the memory layout — see the
18/// [user guide](https://zyxin.xyz/dashu/types.html).
19///
20/// # Examples
21///
22/// Parsing and printing (base 2–36 is supported for string/literal parsing):
23///
24/// ```
25/// # use dashu_base::ParseError;
26/// # use dashu_int::{UBig, Word};
27/// // parsing
28/// let a = UBig::from(408580953453092208335085386466371u128);
29/// let b = UBig::from(0x1231abcd4134u64);
30/// let c = UBig::from_str_radix("a2a123bbb127779cccc123", 32)?;
31/// let d = UBig::from_str_radix("1231abcd4134", 16)?;
32/// assert_eq!(a, c);
33/// assert_eq!(b, d);
34///
35/// // printing
36/// assert_eq!(format!("{}", UBig::from(12u8)), "12");
37/// assert_eq!(format!("{:#X}", UBig::from(0xabcdu16)), "0xABCD");
38/// if Word::BITS == 64 {
39/// // number of digits to display depends on the word size
40/// assert_eq!(
41/// format!("{:?}", UBig::ONE << 1000),
42/// "1071508607186267320..4386837205668069376"
43/// );
44/// }
45/// # Ok::<(), ParseError>(())
46/// ```
47///
48/// The niche bit makes `Option<UBig>` free:
49///
50/// ```
51/// # use dashu_int::UBig;
52/// use core::mem::size_of;
53/// assert_eq!(size_of::<UBig>(), size_of::<Option<UBig>>());
54/// ```
55#[derive(Eq, Hash, PartialEq)]
56#[repr(transparent)]
57pub struct UBig(pub(crate) Repr);
58
59impl UBig {
60 /// Get the representation of UBig.
61 #[rustversion::attr(since(1.64), const)]
62 #[inline]
63 pub(crate) fn repr(&self) -> TypedReprRef<'_> {
64 self.0.as_typed()
65 }
66
67 /// Convert into representation.
68 #[inline]
69 pub(crate) fn into_repr(self) -> TypedRepr {
70 self.0.into_typed()
71 }
72
73 /// [UBig] with value 0
74 pub const ZERO: Self = Self(Repr::zero());
75 /// [UBig] with value 1
76 pub const ONE: Self = Self(Repr::one());
77
78 /// Get the raw representation in [Word][crate::Word]s.
79 ///
80 /// If the number is zero, then empty slice will be returned.
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// # use dashu_int::{UBig, Word};
86 /// assert_eq!(UBig::ZERO.as_words(), &[] as &[Word]);
87 /// assert_eq!(UBig::ONE.as_words(), &[1]);
88 /// ```
89 #[inline]
90 pub fn as_words(&self) -> &[crate::Word] {
91 let (sign, words) = self.0.as_sign_slice();
92 debug_assert!(matches!(sign, crate::Sign::Positive));
93 words
94 }
95
96 /// Create a UBig from a single [Word][crate::Word].
97 ///
98 /// # Examples
99 ///
100 /// ```
101 /// # use dashu_int::UBig;
102 /// const ZERO: UBig = UBig::from_word(0);
103 /// assert_eq!(ZERO, UBig::ZERO);
104 /// const ONE: UBig = UBig::from_word(1);
105 /// assert_eq!(ONE, UBig::ONE);
106 /// ```
107 #[inline]
108 pub const fn from_word(word: crate::Word) -> Self {
109 Self(Repr::from_word(word))
110 }
111
112 /// Create a UBig from a [DoubleWord][crate::DoubleWord].
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// # use dashu_int::UBig;
118 /// const ZERO: UBig = UBig::from_dword(0);
119 /// assert_eq!(ZERO, UBig::ZERO);
120 /// const ONE: UBig = UBig::from_dword(1);
121 /// assert_eq!(ONE, UBig::ONE);
122 /// ```
123 #[inline]
124 pub const fn from_dword(dword: crate::DoubleWord) -> Self {
125 Self(Repr::from_dword(dword))
126 }
127
128 /// Create a UBig from a u64.
129 ///
130 /// This function is const on 32-bit and 64-bit targets.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// # use dashu_int::UBig;
136 /// assert_eq!(UBig::from_u64(42), UBig::from(42u64));
137 /// assert_eq!(UBig::from_u64(10_939_058_860_032_000), UBig::from(10_939_058_860_032_000u64));
138 /// ```
139 #[cfg(not(any(target_pointer_width = "16", force_bits = "16")))]
140 #[inline]
141 pub const fn from_u64(n: u64) -> Self {
142 Self(Repr::from_dword(n as crate::DoubleWord))
143 }
144
145 /// Create a UBig from a u64.
146 ///
147 /// On 16-bit targets `u64` is wider than [`DoubleWord`][crate::DoubleWord], so this delegates
148 /// to `From<u64>` and is not `const`; on 32-bit and 64-bit targets the `const` constructor
149 /// above is used instead.
150 #[cfg(any(target_pointer_width = "16", force_bits = "16"))]
151 #[inline]
152 pub fn from_u64(n: u64) -> Self {
153 Self::from(n)
154 }
155
156 /// Convert a sequence of [Word][crate::Word]s into a UBig
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// # use dashu_int::{UBig, Word};
162 /// assert_eq!(UBig::from_words(&[] as &[Word]), UBig::ZERO);
163 /// assert_eq!(UBig::from_words(&[1]), UBig::ONE);
164 /// assert_eq!(UBig::from_words(&[1, 1]), (UBig::ONE << Word::BITS as usize) + UBig::ONE);
165 /// ```
166 #[inline]
167 pub fn from_words(words: &[crate::Word]) -> Self {
168 Self(Repr::from_buffer(words.into()))
169 }
170
171 /// Create an UBig from a static sequence of [Word][crate::Word]s. Similar to [from_words][UBig::from_words].
172 ///
173 /// The top word of the input word array must not be zero.
174 ///
175 /// This method is unsafe because it must be carefully handled. The generated instance
176 /// must not be mutated or dropped. Therefore the correct usage is to assign it to an
177 /// immutable static variable. Due to the risk, it's generally not recommended to use this method.
178 /// This method is intended for the use of static creation macros.
179 #[doc(hidden)]
180 #[inline]
181 pub const unsafe fn from_static_words(words: &'static [crate::Word]) -> Self {
182 Self(Repr::from_static_words(words))
183 }
184
185 /// Check whether the value is 0
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// # use dashu_int::UBig;
191 /// assert!(UBig::ZERO.is_zero());
192 /// assert!(!UBig::ONE.is_zero());
193 /// ```
194 #[inline]
195 pub const fn is_zero(&self) -> bool {
196 self.0.is_zero()
197 }
198
199 /// Check whether the value is 1
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// # use dashu_int::UBig;
205 /// assert!(!UBig::ZERO.is_one());
206 /// assert!(UBig::ONE.is_one());
207 /// ```
208 #[inline]
209 pub const fn is_one(&self) -> bool {
210 self.0.is_one()
211 }
212
213 /// Create an integer with `n` consecutive one bits (i.e. 2^n - 1).
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// # use dashu_int::UBig;
219 /// let mut n = UBig::ZERO;
220 /// n.set_bit(20);
221 /// n -= UBig::ONE;
222 /// assert_eq!(UBig::ones(20), n);
223 /// ```
224 #[inline]
225 pub fn ones(n: usize) -> Self {
226 Self(Repr::ones(n))
227 }
228}
229
230// This custom implementation is necessary due to https://github.com/rust-lang/rust/issues/98374
231impl Clone for UBig {
232 #[inline]
233 fn clone(&self) -> UBig {
234 UBig(self.0.clone())
235 }
236 #[inline]
237 fn clone_from(&mut self, source: &UBig) {
238 self.0.clone_from(&source.0)
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245 use crate::{buffer::Buffer, DoubleWord, Word};
246
247 impl UBig {
248 /// Capacity in Words.
249 #[inline]
250 fn capacity(&self) -> usize {
251 self.0.capacity()
252 }
253 }
254
255 fn gen_ubig(num_words: usize) -> UBig {
256 let mut buf = Buffer::allocate(num_words);
257 for i in 0..num_words {
258 buf.push(i as Word);
259 }
260 UBig(Repr::from_buffer(buf))
261 }
262
263 #[test]
264 fn test_buffer_to_ubig() {
265 let buf = Buffer::allocate(5);
266 let num = UBig(Repr::from_buffer(buf));
267 assert_eq!(num, UBig::ZERO);
268
269 let mut buf = Buffer::allocate(5);
270 buf.push(7);
271 let num = UBig(Repr::from_buffer(buf));
272 assert_eq!(num, UBig::from(7u8));
273
274 let mut buf = Buffer::allocate(100);
275 buf.push(7);
276 buf.push(0);
277 buf.push(0);
278 let num = UBig(Repr::from_buffer(buf));
279 assert_eq!(num, UBig::from(7u8));
280
281 let mut buf = Buffer::allocate(5);
282 buf.push(1);
283 buf.push(2);
284 buf.push(3);
285 buf.push(4);
286 let num = UBig(Repr::from_buffer(buf));
287 assert_eq!(num.capacity(), 7);
288
289 let mut buf = Buffer::allocate(100);
290 buf.push(1);
291 buf.push(2);
292 buf.push(3);
293 buf.push(4);
294 let num = UBig(Repr::from_buffer(buf));
295 assert_eq!(num.capacity(), 6);
296 }
297
298 #[test]
299 fn test_clone() {
300 let a = UBig::from(5u8);
301 assert_eq!(a.clone(), a);
302
303 let a = gen_ubig(10);
304 let b = a.clone();
305 assert_eq!(a, b);
306 assert_eq!(a.capacity(), b.capacity());
307 }
308
309 #[test]
310 fn test_clone_from() {
311 let num: UBig = gen_ubig(10);
312
313 let mut a = UBig::from(3u8);
314 a.clone_from(&num);
315 assert_eq!(a, num);
316 let b = UBig::from(7u8);
317 a.clone_from(&b);
318 assert_eq!(a, b);
319 a.clone_from(&b);
320 assert_eq!(a, b);
321
322 let mut a = gen_ubig(9);
323 let prev_cap = a.capacity();
324 a.clone_from(&num);
325 // the buffer should be reused, 9 is close enough to 10.
326 assert_eq!(a.capacity(), prev_cap);
327 assert_ne!(a.capacity(), num.capacity());
328
329 let mut a = gen_ubig(3);
330 let prev_cap = a.capacity();
331 a.clone_from(&num);
332 // the buffer should now be reallocated, it's too Small.
333 assert_ne!(a.capacity(), prev_cap);
334 assert_eq!(a.capacity(), num.capacity());
335
336 let mut a = gen_ubig(100);
337 let prev_cap = a.capacity();
338 a.clone_from(&num);
339 // the buffer should now be reallocated, it's too large.
340 assert_ne!(a.capacity(), prev_cap);
341 assert_eq!(a.capacity(), num.capacity());
342 }
343
344 #[test]
345 fn test_const_generation() {
346 const ZERO: UBig = UBig::from_word(0);
347 const ONE_SINGLE: UBig = UBig::from_word(1);
348 const ONE_DOUBLE: UBig = UBig::from_dword(1);
349 const DMAX: UBig = UBig::from_dword(DoubleWord::MAX);
350
351 const CDATA: [Word; 3] = [Word::MAX, Word::MAX, Word::MAX];
352 // SAFETY: DATA meets the requirements of from_static_words
353 static CONST_TMAX: UBig = unsafe { UBig::from_static_words(&CDATA) };
354 static DATA: [Word; 3] = [Word::MAX, Word::MAX, Word::MAX];
355 // SAFETY: DATA meets the requirements of from_static_words
356 static STATIC_TMAX: UBig = unsafe { UBig::from_static_words(&DATA) };
357
358 assert_eq!(ZERO, UBig::ZERO);
359 assert_eq!(ONE_SINGLE, UBig::ONE);
360 assert_eq!(ONE_DOUBLE, UBig::ONE);
361 assert_eq!(DMAX.capacity(), 2);
362 assert_eq!(CONST_TMAX.capacity(), 3);
363 assert_eq!(STATIC_TMAX.capacity(), 3);
364 }
365}