1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
use crate::{ Btrit, RawEncoding, RawEncodingBuf, ShiftTernary, Utrit, }; use std::ops::Range; const TPB: usize = 5; const BAL: i8 = 121; #[repr(transparent)] pub struct T5B1([()]); impl T5B1 { unsafe fn make(ptr: *const i8, offset: usize, len: usize) -> *const Self { let len = (len << 3) | (offset % TPB); std::mem::transmute((ptr.offset((offset / TPB) as isize), len)) } unsafe fn ptr(&self, index: usize) -> *const i8 { let byte_offset = (self.len_offset().1 + index) / TPB; (self.0.as_ptr() as *const i8).offset(byte_offset as isize) } fn len_offset(&self) -> (usize, usize) { (self.0.len() >> 3, self.0.len() & 0b111) } } fn extract(x: i8, elem: usize) -> Btrit { if elem < TPB { Utrit::from_u8((((x as i16 + BAL as i16) / 3i16.pow(elem as u32)) % 3) as u8).shift() } else { unreachable!("Attempted to extract invalid element {} from balanced T5B1", elem) } } fn insert(x: i8, elem: usize, trit: Btrit) -> i8 { if elem < TPB { let utrit = trit.shift(); let ux = x as i16 + BAL as i16; let ux = ux + (utrit.into_u8() as i16 - (ux / 3i16.pow(elem as u32)) % 3) * 3i16.pow(elem as u32); (ux - BAL as i16) as i8 } else { unreachable!("Attempted to insert invalid element {} into balanced T5B1", elem) } } impl RawEncoding for T5B1 { type Trit = Btrit; type Buf = T5B1Buf; fn empty() -> &'static Self { unsafe { &*Self::make(&[] as *const _, 0, 0) } } fn len(&self) -> usize { self.len_offset().0 } fn as_i8_slice(&self) -> &[i8] { assert!(self.len_offset().1 == 0); unsafe { std::slice::from_raw_parts( self.ptr(0) as *const _, (self.len() + self.len_offset().1 + TPB - 1) / TPB, ) } } unsafe fn as_i8_slice_mut(&mut self) -> &mut [i8] { assert!(self.len_offset().1 == 0); std::slice::from_raw_parts_mut( self.ptr(0) as *mut _, (self.len() + self.len_offset().1 + TPB - 1) / TPB, ) } unsafe fn get_unchecked(&self, index: usize) -> Self::Trit { let b = self.ptr(index).read(); extract(b, (self.len_offset().1 + index) % TPB) } unsafe fn set_unchecked(&mut self, index: usize, trit: Self::Trit) { let b = self.ptr(index).read(); let b = insert(b, (self.len_offset().1 + index) % TPB, trit); (self.ptr(index) as *mut i8).write(b); } unsafe fn slice_unchecked(&self, range: Range<usize>) -> &Self { &*Self::make( self.ptr(range.start), (self.len_offset().1 + range.start) % TPB, range.end - range.start, ) } unsafe fn slice_unchecked_mut(&mut self, range: Range<usize>) -> &mut Self { &mut *(Self::make( self.ptr(range.start), (self.len_offset().1 + range.start) % TPB, range.end - range.start, ) as *mut Self) } fn is_valid(b: &i8) -> bool { *b >= -BAL && *b <= BAL } unsafe fn from_raw_unchecked(b: &[i8], num_trits: usize) -> &Self { debug_assert!(num_trits <= b.len() * TPB); &*Self::make(b.as_ptr() as *const _, 0, num_trits) } unsafe fn from_raw_unchecked_mut(b: &mut [i8], num_trits: usize) -> &mut Self { debug_assert!(num_trits <= b.len() * TPB); &mut *(Self::make(b.as_ptr() as *const _, 0, num_trits) as *mut _) } } #[derive(Clone)] pub struct T5B1Buf(Vec<i8>, usize); impl RawEncodingBuf for T5B1Buf { type Slice = T5B1; fn new() -> Self { Self(Vec::new(), 0) } fn push(&mut self, trit: <Self::Slice as RawEncoding>::Trit) { if self.1 % TPB == 0 { self.0.push(insert(0, 0, trit)); } else { let last_index = self.0.len() - 1; let b = unsafe { self.0.get_unchecked_mut(last_index) }; *b = insert(*b, self.1 % TPB, trit); } self.1 += 1; } fn pop(&mut self) -> Option<<Self::Slice as RawEncoding>::Trit> { let val = if self.1 == 0 { return None; } else if self.1 % TPB == 1 { self.0.pop().map(|b| extract(b, 0)) } else { let last_index = self.0.len() - 1; unsafe { Some(extract(*self.0.get_unchecked(last_index), (self.1 + TPB - 1) % TPB)) } }; self.1 -= 1; val } fn as_slice(&self) -> &Self::Slice { unsafe { &*Self::Slice::make(self.0.as_ptr() as _, 0, self.1) } } fn as_slice_mut(&mut self) -> &mut Self::Slice { unsafe { &mut *(Self::Slice::make(self.0.as_ptr() as _, 0, self.1) as *mut _) } } }