bitvec/slice/specialization/
lsb0.rs1use core::iter;
4
5use funty::Integral;
6use wyz::{
7 bidi::BidiIterator,
8 range::RangeExt,
9};
10
11use super::{
12 has_one,
13 has_zero,
14 WORD_BITS,
15};
16use crate::{
17 domain::Domain,
18 field::BitField,
19 mem::bits_of,
20 order::Lsb0,
21 slice::BitSlice,
22 store::BitStore,
23};
24
25impl<T> BitSlice<T, Lsb0>
26where T: BitStore
27{
28 pub(crate) fn sp_bitop_assign(
39 &mut self,
40 rhs: &Self,
41 word_op: fn(usize, usize) -> usize,
42 bool_op: fn(bool, bool) -> bool,
43 ) {
44 let (mut this, mut that) = (self, rhs);
45 while this.len() >= WORD_BITS && that.len() >= WORD_BITS {
46 unsafe {
47 let (l, left) = this.split_at_unchecked_mut_noalias(WORD_BITS);
48 let (r, right) = that.split_at_unchecked(WORD_BITS);
49 this = left;
50 that = right;
51 let (a, b) = (l.load_le::<usize>(), r.load_le::<usize>());
52 l.store_le(word_op(a, b));
53 }
54 }
55 for (l, r) in this
58 .as_mut_bitptr_range()
59 .zip(that.iter().by_vals().chain(iter::repeat(false)))
60 {
61 unsafe {
62 l.write(bool_op(l.read(), r));
63 }
64 }
65 }
66
67 pub(crate) fn sp_copy_from_bitslice(&mut self, src: &Self) {
69 assert_eq!(
70 self.len(),
71 src.len(),
72 "copying between bit-slices requires equal lengths",
73 );
74
75 for (to, from) in unsafe { self.chunks_mut(WORD_BITS).remove_alias() }
76 .zip(src.chunks(WORD_BITS))
77 {
78 to.store_le::<usize>(from.load_le::<usize>());
79 }
80 }
81
82 pub(crate) unsafe fn sp_copy_within_unchecked(
85 &mut self,
86 src: impl RangeExt<usize>,
87 dest: usize,
88 ) {
89 let source = src.normalize(None, self.len());
90 let rev = source.contains(&dest);
91 let dest = dest .. dest + source.len();
92
93 let this = self.as_accessor();
94 let from = this
95 .get_unchecked(source)
96 .chunks(WORD_BITS)
97 .map(|bits| bits as *const BitSlice<T::Access, Lsb0>);
98 let to = this.get_unchecked(dest).chunks(WORD_BITS).map(|bits| {
99 bits as *const BitSlice<T::Access, Lsb0>
100 as *mut BitSlice<T::Access, Lsb0>
101 });
102 for (from, to) in from.zip(to).bidi(rev) {
103 let value = (*from).load_le::<usize>();
104 (*to).store_le::<usize>(value);
105 }
106 }
107
108 pub(crate) fn sp_eq(&self, other: &Self) -> bool {
110 self.len() == other.len()
111 && self
112 .chunks(WORD_BITS)
113 .zip(other.chunks(WORD_BITS))
114 .all(|(a, b)| a.load_le::<usize>() == b.load_le::<usize>())
115 }
116
117 pub(crate) fn sp_first_one(&self) -> Option<usize> {
119 let mut accum = 0;
120
121 match self.domain() {
122 Domain::Enclave(elem) => {
123 let val = elem.load_value();
124 if has_one(val, elem.mask().into_inner()) {
125 accum += val.trailing_zeros() as usize
126 - elem.head().into_inner() as usize;
127 return Some(accum);
128 }
129 None
130 },
131 Domain::Region { head, body, tail } => {
132 if let Some(elem) = head {
133 let val = elem.load_value();
134 accum += val.trailing_zeros() as usize
135 - elem.head().into_inner() as usize;
136 if has_one(val, elem.mask().into_inner()) {
137 return Some(accum);
138 }
139 }
140
141 for val in body.iter().map(BitStore::load_value) {
142 accum += val.trailing_zeros() as usize;
143 if has_one(val, !<T::Mem as Integral>::ZERO) {
144 return Some(accum);
145 }
146 }
147
148 if let Some(elem) = tail {
149 let val = elem.load_value();
150 if has_one(val, elem.mask().into_inner()) {
151 accum += val.trailing_zeros() as usize;
152 return Some(accum);
153 }
154 }
155
156 None
157 },
158 }
159 }
160
161 pub(crate) fn sp_last_one(&self) -> Option<usize> {
163 let mut out = self.len();
164
165 match self.domain() {
166 Domain::Enclave(elem) => {
167 let val = elem.load_value();
168 let dead_bits =
169 bits_of::<T::Mem>() - elem.tail().into_inner() as usize;
170 if has_one(val, elem.mask().into_inner()) {
171 out -= val.leading_zeros() as usize - dead_bits as usize;
172 return Some(out - 1);
173 }
174 None
175 },
176 Domain::Region { head, body, tail } => {
177 if let Some(elem) = tail {
178 let val = elem.load_value();
179 let dead_bits =
180 bits_of::<T::Mem>() - elem.tail().into_inner() as usize;
181 out -= val.leading_zeros() as usize - dead_bits;
182 if has_one(val, elem.mask().into_inner()) {
183 return Some(out - 1);
184 }
185 }
186
187 for val in body.iter().map(BitStore::load_value).rev() {
188 out -= val.leading_zeros() as usize;
189 if has_one(val, !<T::Mem as Integral>::ZERO) {
190 return Some(out - 1);
191 }
192 }
193
194 if let Some(elem) = head {
195 let val = elem.load_value();
196 if has_one(val, elem.mask().into_inner()) {
197 out -= val.leading_zeros() as usize;
198 return Some(out - 1);
199 }
200 }
201
202 None
203 },
204 }
205 }
206
207 pub(crate) fn sp_first_zero(&self) -> Option<usize> {
209 let mut accum = 0;
210
211 match self.domain() {
212 Domain::Enclave(elem) => {
213 let val = elem.load_value() | !elem.mask().into_inner();
214 accum += val.trailing_ones() as usize
215 - elem.head().into_inner() as usize;
216 if has_zero(val, elem.mask().into_inner()) {
217 return Some(accum);
218 }
219 None
220 },
221 Domain::Region { head, body, tail } => {
222 if let Some(elem) = head {
223 let val = elem.load_value() | !elem.mask().into_inner();
224
225 accum += val.trailing_ones() as usize
226 - elem.head().into_inner() as usize;
227 if has_zero(val, elem.mask().into_inner()) {
228 return Some(accum);
229 }
230 }
231
232 for val in body.iter().map(BitStore::load_value) {
233 accum += val.trailing_ones() as usize;
234 if has_zero(val, !<T::Mem as Integral>::ZERO) {
235 return Some(accum);
236 }
237 }
238
239 if let Some(elem) = tail {
240 let val = elem.load_value() | !elem.mask().into_inner();
241 accum += val.trailing_ones() as usize;
242 if has_zero(val, elem.mask().into_inner()) {
243 return Some(accum);
244 }
245 }
246
247 None
248 },
249 }
250 }
251
252 pub(crate) fn sp_last_zero(&self) -> Option<usize> {
254 let mut out = self.len();
255
256 match self.domain() {
257 Domain::Enclave(elem) => {
258 let val = elem.load_value() | !elem.mask().into_inner();
259 let dead_bits =
260 bits_of::<T::Mem>() - elem.tail().into_inner() as usize;
261 if has_zero(val, elem.mask().into_inner()) {
262 out -= val.leading_ones() as usize - dead_bits as usize;
263 return Some(out - 1);
264 }
265 None
266 },
267 Domain::Region { head, body, tail } => {
268 if let Some(elem) = tail {
269 let val = elem.load_value() | !elem.mask().into_inner();
270 let dead_bits =
271 bits_of::<T::Mem>() - elem.tail().into_inner() as usize;
272 out -= val.leading_ones() as usize - dead_bits;
273 if has_zero(val, elem.mask().into_inner()) {
274 return Some(out - 1);
275 }
276 }
277
278 for val in body.iter().map(BitStore::load_value).rev() {
279 out -= val.leading_ones() as usize;
280 if has_zero(val, !<T::Mem as Integral>::ZERO) {
281 return Some(out - 1);
282 }
283 }
284
285 if let Some(elem) = head {
286 let val = elem.load_value() | !elem.mask().into_inner();
287 if has_zero(val, elem.mask().into_inner()) {
288 out -= val.leading_ones() as usize;
289 return Some(out - 1);
290 }
291 }
292
293 None
294 },
295 }
296 }
297
298 pub(crate) fn sp_swap_with_bitslice(&mut self, other: &mut Self) {
300 for (this, that) in unsafe {
301 self.chunks_mut(WORD_BITS)
302 .remove_alias()
303 .zip(other.chunks_mut(WORD_BITS).remove_alias())
304 } {
305 let (a, b) = (this.load_le::<usize>(), that.load_le::<usize>());
306 this.store_le(b);
307 that.store_le(a);
308 }
309 }
310}