1use crate::{
4 arch::word::{DoubleWord, Word},
5 buffer::Buffer,
6 primitive::{double_word, split_dword},
7 Sign,
8};
9use core::{
10 fmt::{self, Write},
11 hash::{Hash, Hasher},
12 hint::unreachable_unchecked,
13 mem,
14 num::NonZeroIsize,
15 ptr::{self, NonNull},
16 slice,
17};
18use static_assertions::const_assert_eq;
19
20#[repr(C)]
23union ReprData {
24 inline: [Word; 2], heap: (*mut Word, usize), }
27
28#[repr(C)]
38pub struct Repr {
39 data: ReprData,
41
42 capacity: NonZeroIsize,
51}
52
53const_assert_eq!(mem::size_of::<Buffer>(), mem::size_of::<Repr>());
56
57const_assert_eq!(mem::size_of::<Repr>(), mem::size_of::<Option<Repr>>());
59
60unsafe impl Send for Repr {}
62
63unsafe impl Sync for Repr {}
65
66#[derive(Clone)]
68pub enum TypedRepr {
69 Small(DoubleWord),
70 Large(Buffer),
71}
72
73#[derive(Clone, Copy, PartialEq, Eq)]
75pub enum TypedReprRef<'a> {
76 RefSmall(DoubleWord),
77 RefLarge(&'a [Word]),
78}
79
80impl Repr {
81 #[inline]
83 pub const fn len(&self) -> usize {
84 unsafe {
87 match self.capacity() {
88 0 => unreachable_unchecked(),
89 1 => (self.data.inline[0] != 0) as usize,
90 2 => 2,
91 _ => self.data.heap.1,
92 }
93 }
94 }
95
96 #[inline]
100 pub const fn capacity(&self) -> usize {
101 self.capacity.get().unsigned_abs()
102 }
103
104 #[inline]
106 pub const fn sign(&self) -> Sign {
107 if self.capacity.get() > 0 {
108 Sign::Positive
109 } else {
110 Sign::Negative
111 }
112 }
113
114 #[inline]
116 pub const fn sign_capacity(&self) -> (usize, Sign) {
117 if self.capacity.get() > 0 {
118 (self.capacity.get() as usize, Sign::Positive)
119 } else {
120 (self.capacity.get().wrapping_neg() as usize, Sign::Negative)
122 }
123 }
124
125 #[inline]
128 pub const fn with_sign(mut self, sign: Sign) -> Self {
129 let is_positive = match sign {
130 Sign::Positive => true,
131 Sign::Negative => false,
132 };
133 if !self.is_zero() && (is_positive ^ (self.capacity.get() > 0)) {
134 self.capacity = unsafe { NonZeroIsize::new_unchecked(-self.capacity.get()) }
136 }
137 self
138 }
139
140 #[rustversion::attr(since(1.64), const)]
143 #[inline]
144 pub fn as_typed(&self) -> TypedReprRef<'_> {
145 let (sign, typed) = self.as_sign_typed();
146 match sign {
147 Sign::Positive => {}
149 Sign::Negative => unreachable!(),
150 }
151
152 typed
153 }
154
155 #[rustversion::attr(since(1.64), const)]
157 #[inline]
158 pub fn as_sign_typed(&self) -> (Sign, TypedReprRef<'_>) {
159 let (abs_capacity, sign) = self.sign_capacity();
160
161 let typed = unsafe {
164 match abs_capacity {
165 0 => unreachable_unchecked(),
166 1 | 2 => {
167 TypedReprRef::RefSmall(double_word(self.data.inline[0], self.data.inline[1]))
168 }
169 _ => TypedReprRef::RefLarge(slice::from_raw_parts(
170 self.data.heap.0,
172 self.data.heap.1,
173 )),
174 }
175 };
176 (sign, typed)
177 }
178
179 #[inline]
185 pub fn into_typed(self) -> TypedRepr {
186 debug_assert!(self.capacity.get() > 0);
187
188 unsafe {
191 match self.capacity.get() {
192 0 => unreachable_unchecked(),
193 1 | 2 => TypedRepr::Small(double_word(self.data.inline[0], self.data.inline[1])),
194 _ => {
195 TypedRepr::Large(mem::transmute(self))
198 }
199 }
200 }
201 }
202
203 #[inline]
205 pub fn into_sign_typed(mut self) -> (Sign, TypedRepr) {
206 let (abs_capacity, sign) = self.sign_capacity();
207 self.capacity = unsafe { NonZeroIsize::new_unchecked(abs_capacity as isize) };
209 (sign, self.into_typed())
210 }
211
212 #[inline]
218 pub fn as_slice(&self) -> &[Word] {
219 let (sign, slice) = self.as_sign_slice();
220 assert!(sign == Sign::Positive);
221 slice
222 }
223
224 pub fn as_sign_slice(&self) -> (Sign, &[Word]) {
226 let (capacity, sign) = self.sign_capacity();
227
228 let words = unsafe {
231 match capacity {
232 0 => unreachable_unchecked(),
233 1 => {
234 if self.data.inline[0] == 0 {
235 &[]
236 } else {
237 &self.data.inline[..1]
238 }
239 }
240 2 => &self.data.inline,
241 _ => slice::from_raw_parts(self.data.heap.0, self.data.heap.1),
242 }
243 };
244 (sign, words)
245 }
246
247 #[cfg(feature = "zeroize")]
248 pub fn as_full_slice(&mut self) -> &mut [Word] {
250 unsafe {
253 let capacity = self.capacity();
254 if capacity <= 2 {
255 &mut self.data.inline
256 } else {
257 slice::from_raw_parts_mut(self.data.heap.0, capacity)
258 }
259 }
260 }
261
262 #[inline]
264 pub const fn from_word(n: Word) -> Self {
265 Repr {
266 data: ReprData { inline: [n, 0] },
267 capacity: unsafe { NonZeroIsize::new_unchecked(1) },
270 }
271 }
272
273 #[inline]
275 pub const fn from_dword(n: DoubleWord) -> Self {
276 let (lo, hi) = split_dword(n);
277 Repr {
278 data: ReprData { inline: [lo, hi] },
279 capacity: unsafe { NonZeroIsize::new_unchecked(1 + (hi != 0) as isize) },
281 }
282 }
283
284 #[inline]
289 pub const unsafe fn from_static_words(words: &'static [Word]) -> Repr {
290 match words {
291 &[] => Self::zero(),
292 &[n] => Self::from_word(n),
293 &[lo, hi] => {
294 assert!(hi > 0);
295 Self::from_dword(double_word(lo, hi))
296 }
297 large => {
298 if let Some(n) = large.last() {
300 assert!(*n != 0, "the array input must be normalized.");
301 }
302
303 let ptr = large.as_ptr() as _;
304 Self {
305 data: ReprData {
306 heap: (ptr, large.len()),
307 },
308 capacity: NonZeroIsize::new_unchecked(large.len() as _),
309 }
310 }
311 }
312 }
313
314 pub fn from_buffer(mut buffer: Buffer) -> Self {
317 buffer.pop_zeros();
318
319 match buffer.len() {
320 0 => Self::from_word(0),
321 1 => Self::from_word(buffer[0]),
322 2 => Self::from_dword(double_word(buffer[0], buffer[1])),
323 _ => {
324 buffer.shrink_to_fit();
329
330 unsafe { mem::transmute(buffer) }
333 }
334 }
335 }
336
337 pub fn from_ref(tref: TypedReprRef) -> Self {
339 match tref {
340 TypedReprRef::RefSmall(dw) => Self::from_dword(dw),
341 TypedReprRef::RefLarge(words) => Self::from_buffer(Buffer::from(words)),
342 }
343 }
344
345 pub fn into_buffer(self) -> Buffer {
351 debug_assert!(self.capacity.get() > 0); unsafe {
356 match self.capacity.get() {
357 0 => unreachable_unchecked(),
358 1 => {
359 let mut buffer = Buffer::allocate(1);
360 if self.data.inline[0] != 0 {
361 buffer.push(self.data.inline[0]);
362 }
363 buffer
364 }
365 2 => {
366 debug_assert!(self.data.inline[1] != 0); let mut buffer = Buffer::allocate(2);
368 buffer.push(self.data.inline[0]);
369 buffer.push(self.data.inline[1]);
370 buffer
371 }
372 _ => {
373 mem::transmute(self)
376 }
377 }
378 }
379 }
380
381 #[inline]
383 pub const fn zero() -> Self {
384 Self::from_word(0)
385 }
386
387 #[inline]
389 pub const fn is_zero(&self) -> bool {
390 self.capacity() == 1 && unsafe { self.data.inline[0] == 0 }
393 }
394
395 #[inline]
397 pub const fn one() -> Self {
398 Self::from_word(1)
399 }
400
401 #[inline]
403 pub const fn is_one(&self) -> bool {
404 self.capacity.get() == 1 && unsafe { self.data.inline[0] == 1 }
407 }
408
409 #[inline]
411 pub const fn neg_one() -> Self {
412 Self::from_word(1).with_sign(Sign::Negative)
413 }
414
415 pub const fn neg(mut self) -> Self {
417 if !self.is_zero() {
418 self.capacity = unsafe { NonZeroIsize::new_unchecked(-self.capacity.get()) }
420 }
421 self
422 }
423
424 pub const fn signum(&self) -> Self {
430 if self.is_zero() {
431 Self::zero()
432 } else if self.capacity.get() < 0 {
433 Self::neg_one()
434 } else {
435 Self::one()
436 }
437 }
438}
439
440impl Clone for Repr {
442 fn clone(&self) -> Self {
443 let (capacity, sign) = self.sign_capacity();
444
445 let new = unsafe {
447 if capacity <= 2 {
450 Repr {
451 data: ReprData {
452 inline: self.data.inline,
453 },
454 capacity: NonZeroIsize::new_unchecked(capacity as isize),
456 }
457 } else {
458 let (ptr, len) = self.data.heap;
459 let mut new_buffer = Buffer::allocate(len);
461 new_buffer.push_slice(slice::from_raw_parts(ptr, len));
462
463 mem::transmute(new_buffer)
466 }
467 };
468 new.with_sign(sign)
469 }
470
471 fn clone_from(&mut self, src: &Self) {
472 let (src_cap, src_sign) = src.sign_capacity();
473 let (cap, _) = self.sign_capacity();
474
475 unsafe {
477 if src_cap <= 2 {
479 if cap > 2 {
480 Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
483 }
484 self.data.inline = src.data.inline;
485 self.capacity = src.capacity;
486 return;
487 }
488
489 let (src_ptr, src_len) = src.data.heap;
491 debug_assert!(src_len >= 3);
492
493 if cap < src_len || cap > Buffer::max_compact_capacity(src_len) {
495 if cap > 2 {
496 Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
498 }
499
500 let new_cap = Buffer::default_capacity(src_len);
501 let new_ptr = Buffer::allocate_raw(new_cap);
502 self.data.heap.0 = new_ptr.as_ptr();
503 self.capacity = NonZeroIsize::new_unchecked(new_cap as isize);
505 }
506
507 ptr::copy_nonoverlapping(src_ptr, self.data.heap.0, src_len);
510
511 self.data.heap.1 = src_len;
513 if (src_sign == Sign::Positive) ^ (self.capacity.get() > 0) {
514 self.capacity = NonZeroIsize::new_unchecked(-self.capacity.get());
515 }
516 }
517 }
518}
519
520impl Drop for Repr {
521 fn drop(&mut self) {
522 let cap = self.capacity();
523 if cap > 2 {
524 unsafe {
526 Buffer::deallocate_raw(NonNull::new_unchecked(self.data.heap.0), cap);
527 }
528 }
529 }
530}
531
532impl PartialEq for Repr {
533 #[inline]
534 fn eq(&self, other: &Self) -> bool {
535 self.as_sign_slice() == other.as_sign_slice()
536 }
537}
538impl Eq for Repr {}
539
540impl fmt::Debug for Repr {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 let (sign, words) = self.as_sign_slice();
543 if let Sign::Negative = sign {
544 f.write_char('-')?;
545 }
546 f.debug_list().entries(words).finish()
547 }
548}
549
550impl Hash for Repr {
551 fn hash<H: Hasher>(&self, state: &mut H) {
552 let (sign, arr) = self.as_sign_slice();
553 sign.hash(state);
554 (*arr).hash(state);
555 }
556}
557
558impl TypedRepr {
559 #[inline]
561 pub fn as_ref(&self) -> TypedReprRef {
562 match self {
563 Self::Small(dword) => TypedReprRef::RefSmall(*dword),
564 Self::Large(words) => TypedReprRef::RefLarge(words),
565 }
566 }
567}
568
569impl<'a> TypedReprRef<'a> {
570 #[inline]
572 pub fn len(&self) -> usize {
573 match self {
574 Self::RefSmall(dword) => {
575 if *dword == 0 {
576 0
577 } else if *dword <= Word::MAX as DoubleWord {
578 1
579 } else {
580 2
581 }
582 }
583 Self::RefLarge(words) => words.len(),
584 }
585 }
586
587 #[inline]
589 pub fn as_ref(&self) -> TypedReprRef {
590 *self
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597 use crate::primitive::WORD_BITS_USIZE;
598
599 #[test]
600 fn test_inline() {
601 let repr = Repr::zero();
602 assert_eq!(repr.capacity(), 1);
603 assert_eq!(repr.len(), 0);
604
605 let repr = Repr::from_word(123);
606 assert_eq!(repr.capacity(), 1);
607 assert_eq!(repr.len(), 1);
608
609 let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
610 assert_eq!(repr.capacity(), 2);
611 assert_eq!(repr.len(), 2);
612 }
613
614 #[test]
615 fn test_deref() {
616 let repr = Repr::zero();
617 assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[][..]));
618
619 let repr = Repr::one();
620 assert_eq!(repr.as_slice(), &[1][..]);
621 assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1][..]));
622
623 let mut buffer = Buffer::allocate(1);
624 buffer.push(1);
625 let repr = Repr::from_buffer(buffer).with_sign(Sign::Negative);
626 assert_eq!(repr.as_sign_slice(), (Sign::Negative, &[1][..]));
627
628 let mut buffer = Buffer::allocate(2);
629 buffer.push(1);
630 buffer.push(2);
631 let repr = Repr::from_buffer(buffer);
632 assert_eq!(repr.as_slice(), &[1, 2][..]);
633 assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1, 2][..]));
634
635 let mut buffer = Buffer::allocate(2);
636 buffer.push(1);
637 buffer.push(2);
638 buffer.push(3);
639 buffer.push(4);
640 let repr = Repr::from_buffer(buffer);
641 assert_eq!(repr.as_slice(), &[1, 2, 3, 4][..]);
642 assert_eq!(repr.as_sign_slice(), (Sign::Positive, &[1, 2, 3, 4][..]));
643 }
644
645 #[test]
646 fn test_sign() {
647 let repr = Repr::zero();
648 assert_eq!(repr.sign(), Sign::Positive);
649 let repr = Repr::zero().neg();
650 assert_eq!(repr.sign(), Sign::Positive);
651
652 let repr = Repr::one();
653 assert_eq!(repr.sign(), Sign::Positive);
654 let repr = Repr::one().neg();
655 assert_eq!(repr.sign(), Sign::Negative);
656 }
657
658 #[test]
659 fn test_clone() {
660 let repr = Repr::from_word(123);
662 let repr2 = repr.clone();
663 assert_eq!(repr2.capacity(), 1);
664 assert_eq!(repr2.len(), 1);
665 assert_eq!(repr, repr2);
666
667 let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
668 let repr2 = repr.clone();
669 assert_eq!(repr2.capacity(), repr.capacity());
670 assert_eq!(repr2.len(), repr.len());
671 assert_eq!(repr, repr2);
672
673 let mut buffer = Buffer::allocate(100);
675 buffer.push(7);
676 buffer.push(8);
677 buffer.push(9);
678 let buffer2 = buffer.clone();
679 assert_eq!(buffer, buffer2);
680 assert_eq!(buffer2.capacity(), Buffer::default_capacity(3));
681
682 let repr = Repr::from_buffer(buffer);
683 let repr2 = repr.clone();
684 assert_eq!(repr.capacity(), Buffer::default_capacity(3));
685 assert_eq!(repr, repr2);
686 }
687
688 #[test]
689 fn test_convert_buffer() {
690 let buffer = Buffer::allocate(0);
691 let repr = Repr::from_buffer(buffer);
692 assert_eq!(repr.len(), 0);
693 assert!(repr.as_slice().is_empty());
694 let buffer_back = repr.into_buffer();
695 assert_eq!(buffer_back.len(), 0);
696 assert!(buffer_back.is_empty());
697
698 let mut buffer = Buffer::allocate(1);
699 buffer.push(123);
700 let repr = Repr::from_buffer(buffer);
701 assert_eq!(repr.len(), 1);
702 assert_eq!(repr.as_slice(), &[123][..]);
703 let buffer_back = repr.into_buffer();
704 assert_eq!(buffer_back.len(), 1);
705 assert_eq!(&buffer_back[..], &[123][..]);
706
707 let mut buffer = Buffer::allocate(2);
708 buffer.push(123);
709 buffer.push(456);
710 let repr = Repr::from_buffer(buffer);
711 assert_eq!(repr.len(), 2);
712 assert_eq!(repr.as_slice(), &[123, 456][..]);
713 let buffer_back = repr.into_buffer();
714 assert_eq!(buffer_back.len(), 2);
715 assert_eq!(&buffer_back[..], &[123, 456][..]);
716
717 let mut buffer = Buffer::allocate(3);
718 buffer.push(123);
719 buffer.push(456);
720 buffer.push(789);
721 let repr = Repr::from_buffer(buffer);
722 assert_eq!(repr.len(), 3);
723 assert_eq!(repr.as_slice(), &[123, 456, 789][..]);
724 let buffer_back = repr.into_buffer();
725 assert_eq!(buffer_back.len(), 3);
726 assert_eq!(&buffer_back[..], &[123, 456, 789][..]);
727 }
728
729 #[test]
730 fn test_clone_from() {
731 let repr = Repr::from_word(123);
733 let mut repr2 = Repr::zero();
734 repr2.clone_from(&repr);
735 assert_eq!(repr2.capacity(), repr.capacity());
736 assert_eq!(repr2.len(), repr.len());
737 assert_eq!(repr, repr2);
738
739 let repr = Repr::from_dword(123 << WORD_BITS_USIZE);
740 let mut repr2 = Repr::zero();
741 repr2.clone_from(&repr);
742 assert_eq!(repr2.capacity(), repr.capacity());
743 assert_eq!(repr2.len(), repr.len());
744 assert_eq!(repr, repr2);
745
746 let mut buffer = Buffer::allocate(100);
748 buffer.push(7);
749 buffer.push(8);
750 buffer.push(9);
751 let mut buffer2 = Buffer::allocate(50);
752 buffer2.clone_from(&buffer);
753 assert_eq!(buffer, buffer2);
754 assert_ne!(buffer.capacity(), buffer2.capacity());
755
756 let repr = Repr::from_buffer(buffer);
757 let mut repr2 = Repr::from_buffer(buffer2);
758 repr2.clone_from(&repr);
759 assert_eq!(repr, repr2);
760 }
761
762 #[test]
763 fn test_resizing_clone_from() {
764 let mut buf = Buffer::allocate(5);
766 assert_eq!(buf.capacity(), 7);
767
768 let mut buf2 = Buffer::allocate(4);
769 assert_eq!(buf2.capacity(), 6);
770 for i in 0..4 {
771 buf2.push(i);
772 }
773 buf.clone_from(&buf2);
774 assert_eq!(buf.capacity(), 7);
775 assert_eq!(&buf[..], [0, 1, 2, 3]);
776
777 let mut buf3 = Buffer::allocate(100);
778 for i in 0..100 {
779 buf3.push(i);
780 }
781 buf.clone_from(&buf3);
782 assert_eq!(buf.capacity(), Buffer::default_capacity(100));
783 assert_eq!(buf.len(), 100);
784
785 buf.clone_from(&buf2);
786 assert_eq!(buf.capacity(), 6);
787 assert_eq!(&buf[..], [0, 1, 2, 3]);
788
789 let mut repr = Repr::zero(); let repr2 = Repr::from_buffer(buf2);
792 repr.clone_from(&repr2);
793 assert_eq!(repr.len(), 4);
794 assert_eq!(repr, repr2);
795 assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
796
797 let repr3 = Repr::from_buffer(buf3);
798 repr.clone_from(&repr3);
799 assert_eq!(repr.len(), 100);
800 assert_eq!(repr, repr3);
801 assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
802
803 repr.clone_from(&repr2);
804 assert_eq!(repr.len(), 4);
805 assert_eq!(repr, repr2);
806 assert!(matches!(repr.as_typed(), TypedReprRef::RefLarge(_)));
807
808 let repr_inline = Repr::from_word(123);
809 repr.clone_from(&repr_inline);
810 assert_eq!(repr.len(), 1);
811 assert_eq!(repr, repr_inline);
812 assert!(matches!(repr.as_typed(), TypedReprRef::RefSmall(_)));
813 }
814}