Skip to main content

baa/bv/
ops.rs

1// Copyright 2023-2024 The Regents of the University of California
2// Copyright 2024 Cornell University
3// released under BSD 3-Clause License
4// author: Kevin Laeufer <laeufer@cornell.edu>
5//
6// Traits for operations on bit-vectors.
7
8use crate::bv::arithmetic::mask_double_word;
9use crate::bv::io::strings::ParseIntError;
10use crate::bv::owned::{double_word_from_words, double_word_to_words};
11use crate::{BitVecValue, BitVecValueRef, DoubleWord, WidthInt, Word, mask};
12#[cfg(feature = "rand1")]
13use rand::RngExt;
14
15/// Declares an arithmetic function which takes in two equal size bitvector and yields a
16/// bitvector of the same size.
17macro_rules! declare_arith_bin_fn {
18    ($name:ident) => {
19        fn $name<R: BitVecOps>(&self, rhs: &R) -> BitVecValue {
20            debug_assert_eq!(self.width(), rhs.width());
21            debug_assert_eq!(self.words().len(), rhs.words().len());
22            let mut out = BitVecValue::zero(self.width());
23            if self.words().len() == 1 {
24                // specialized for 1-word case
25                crate::bv::arithmetic::$name(
26                    &mut out.words_mut()[0..1],
27                    &self.words()[0..1],
28                    &rhs.words()[0..1],
29                    self.width(),
30                );
31            } else {
32                crate::bv::arithmetic::$name(
33                    out.words_mut(),
34                    self.words(),
35                    rhs.words(),
36                    self.width(),
37                );
38            }
39            out
40        }
41    };
42}
43
44/// Declares a bitwise function which takes in two equal size bitvector and yields a
45/// bitvector of the same size.
46macro_rules! declare_bit_arith_bin_fn {
47    ($name:ident) => {
48        fn $name<R: BitVecOps>(&self, rhs: &R) -> BitVecValue {
49            debug_assert_eq!(self.width(), rhs.width());
50            debug_assert_eq!(self.words().len(), rhs.words().len());
51            let mut out = BitVecValue::zero(self.width());
52            if self.words().len() == 1 {
53                // specialized for 1-word case
54                crate::bv::arithmetic::$name(
55                    &mut out.words_mut()[0..1],
56                    &self.words()[0..1],
57                    &rhs.words()[0..1],
58                );
59            } else {
60                crate::bv::arithmetic::$name(out.words_mut(), self.words(), rhs.words());
61            }
62            out
63        }
64    };
65}
66
67/// Operations over immutable bit-vector values.
68pub trait BitVecOps {
69    fn width(&self) -> WidthInt;
70    fn words(&self) -> &[Word];
71
72    /// Convert to a string of 1s and 0s.
73    fn to_bit_str(&self) -> String {
74        crate::bv::io::strings::to_bit_str(self.words(), self.width())
75    }
76
77    /// Convert to a string of 1s and 0s with a `-` if the value is negative.
78    fn to_bit_str_signed(&self) -> String {
79        crate::bv::io::strings::to_bit_str_signed(self.words(), self.width())
80    }
81
82    /// Convert to a string of hex characters
83    fn to_hex_str(&self) -> String {
84        crate::bv::io::strings::to_hex_str(self.words(), self.width())
85    }
86
87    /// Convert to a string of a decimal number. No leading zeros.
88    fn to_dec_str(&self) -> String {
89        crate::bv::io::strings::to_dec_str(self.words(), self.width())
90    }
91
92    /// Convert to a string of hex characters with a `-` if the value is negative.
93    fn to_hex_str_signed(&self) -> String {
94        crate::bv::io::strings::to_hex_str_signed(self.words(), self.width())
95    }
96
97    fn to_bytes_le(&self) -> Vec<u8> {
98        crate::bv::io::bytes::to_bytes_le(self.words(), self.width())
99    }
100
101    #[cfg(feature = "bigint")]
102    fn to_big_int(&self) -> num_bigint::BigInt {
103        crate::bv::io::bigint::to_big_int(self.words(), self.width())
104    }
105
106    #[cfg(feature = "bigint")]
107    fn to_big_uint(&self) -> num_bigint::BigUint {
108        crate::bv::io::bigint::to_big_uint(self.words())
109    }
110
111    #[cfg(feature = "fraction1")]
112    fn to_signed_fixed_point(&self, fraction_width: WidthInt) -> Option<fraction::Fraction> {
113        debug_assert!(fraction_width <= self.width());
114        if self.is_negative() {
115            // before we do a costly conversion we make sure that we can actually fit into 64-bits
116            if self.width() > u64::BITS {
117                None
118            } else {
119                let negated = self.negate();
120                let frac = negated.to_unsigned_fixed_point(fraction_width);
121                frac.map(|f| -f)
122            }
123        } else {
124            self.to_unsigned_fixed_point(fraction_width)
125        }
126    }
127
128    #[cfg(feature = "fraction1")]
129    fn to_unsigned_fixed_point(&self, fraction_width: WidthInt) -> Option<fraction::Fraction> {
130        debug_assert!(fraction_width <= self.width());
131        let denom = 1u64 << fraction_width;
132        self.to_u64().map(|v| fraction::Fraction::new(v, denom))
133    }
134
135    /// Returns value as a bool iff the value is a 1-bit value.
136    fn to_bool(&self) -> Option<bool> {
137        if self.width() == 1 {
138            Some(crate::bv::arithmetic::word_to_bool(self.words()[0]))
139        } else {
140            None
141        }
142    }
143
144    /// Returns the value as a 64-bit unsigned integer if the value can be represented
145    fn to_u64(&self) -> Option<u64> {
146        debug_assert_eq!(Word::BITS, u64::BITS);
147        // check msbs
148        let non_zero_msb = self.words().iter().skip(1).any(|w| *w != 0);
149        if non_zero_msb {
150            None
151        } else {
152            Some(self.words().iter().next().cloned().unwrap_or(0))
153        }
154    }
155
156    /// Returns the value as a 64-bit signed integer if the value can be represented
157    fn to_i64(&self) -> Option<i64> {
158        debug_assert_eq!(Word::BITS, i64::BITS);
159        if self.width() <= i64::BITS {
160            if self.width() == 0 {
161                Some(0)
162            } else if self.width() == i64::BITS {
163                Some(self.words()[0] as i64)
164            } else {
165                debug_assert_eq!(self.words().len(), 1);
166                if crate::bv::arithmetic::is_neg(self.words(), self.width()) {
167                    let extra_sign_bits =
168                        crate::bv::arithmetic::mask(Word::BITS - self.width()) << self.width();
169                    Some((self.words()[0] | extra_sign_bits) as i64)
170                } else {
171                    Some(self.words()[0] as i64)
172                }
173            }
174        } else {
175            let all_zero_msbs = self.words().iter().skip(1).all(|w| *w == 0);
176            let word_0 = self.words()[0];
177            let all_max_msbs = self.words().iter().skip(1).all(|w| *w == Word::MAX);
178            match (
179                all_zero_msbs,
180                all_max_msbs,
181                crate::bv::arithmetic::is_neg(&[word_0], Word::BITS),
182            ) {
183                (true, false, false) => Some(word_0 as i64),
184                (false, true, true) => Some(word_0 as i64),
185                _ => None,
186            }
187        }
188    }
189
190    fn is_true(&self) -> bool {
191        self.width() == 1 && self.words()[0] == 1
192    }
193
194    fn is_false(&self) -> bool {
195        self.width() == 1 && self.words()[0] == 0
196    }
197
198    fn is_zero(&self) -> bool {
199        self.words().iter().all(|w| *w == 0)
200    }
201
202    fn is_one(&self) -> bool {
203        let msbs_are_zero = self.words().iter().skip(1).all(|w| *w == 0);
204        msbs_are_zero && self.words()[0] == 1
205    }
206
207    fn is_all_ones(&self) -> bool {
208        let lsbs_are_max = self
209            .words()
210            .iter()
211            .take(self.words().len() - 1)
212            .all(|w| *w == Word::MAX);
213        lsbs_are_max && (*self.words().last().unwrap() == mask(self.width() % Word::BITS))
214    }
215
216    fn is_negative(&self) -> bool {
217        crate::bv::arithmetic::is_neg(self.words(), self.width())
218    }
219
220    fn is_pow_2(&self) -> Option<WidthInt> {
221        crate::bv::arithmetic::is_pow2(self.words())
222    }
223
224    /// Computes the minimum number of bits that are necessary to represent the current value.
225    /// This corresponds to the position of the most significant `1` plus one.
226    fn min_width(&self) -> WidthInt {
227        crate::bv::arithmetic::min_width(self.words())
228    }
229
230    /// Computes all ranges for which the bits are one.
231    fn bit_set_intervals(&self) -> Vec<std::ops::Range<WidthInt>> {
232        match self.width() {
233            0 => vec![],
234            1 if self.is_zero() => vec![],
235            1 => {
236                let range = 0..1;
237                vec![range]
238            }
239            _ => crate::bv::arithmetic::find_ranges_of_ones(self.words()),
240        }
241    }
242
243    declare_arith_bin_fn!(add);
244    declare_arith_bin_fn!(sub);
245    declare_arith_bin_fn!(shift_left);
246    declare_arith_bin_fn!(shift_right);
247    declare_arith_bin_fn!(arithmetic_shift_right);
248
249    fn mul<R: BitVecOps>(&self, rhs: &R) -> BitVecValue {
250        debug_assert_eq!(self.width(), rhs.width());
251        debug_assert_eq!(self.words().len(), rhs.words().len());
252        match (self.words(), rhs.words()) {
253            ([a], [b]) => {
254                BitVecValue::from_u64(a.overflowing_mul(*b).0 & mask(self.width()), self.width())
255            }
256            ([a_lsb, a_msb], [b_lsb, b_msb]) => BitVecValue::from_u128(
257                double_word_from_words(*a_lsb, *a_msb)
258                    .overflowing_mul(double_word_from_words(*b_lsb, *b_msb))
259                    .0
260                    & mask_double_word(self.width()),
261                self.width(),
262            ),
263            (a_words, b_words) => {
264                let mut out = BitVecValue::zero(self.width());
265                crate::bv::arithmetic::mul(out.words_mut(), a_words, b_words, self.width());
266                out
267            }
268        }
269    }
270
271    declare_bit_arith_bin_fn!(and);
272    declare_bit_arith_bin_fn!(or);
273    declare_bit_arith_bin_fn!(xor);
274
275    fn is_equal<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
276        debug_assert_eq!(
277            self.width(),
278            rhs.width(),
279            "cannot compare bv<{}> with bv<{}>",
280            self.width(),
281            rhs.width()
282        );
283        debug_assert_eq!(self.words().len(), rhs.words().len());
284        if self.words().len() == 1 {
285            // specialized for 1-word case
286            crate::bv::arithmetic::cmp_equal(self.words(), rhs.words())
287        } else {
288            crate::bv::arithmetic::cmp_equal(self.words(), rhs.words())
289        }
290    }
291
292    fn is_not_equal<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
293        !self.is_equal(rhs)
294    }
295
296    fn is_greater<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
297        debug_assert_eq!(self.width(), rhs.width());
298        debug_assert_eq!(self.words().len(), rhs.words().len());
299        if self.words().len() == 1 {
300            // specialized for 1-word case
301            crate::bv::arithmetic::cmp_greater(&self.words()[0..1], &rhs.words()[0..1])
302        } else {
303            crate::bv::arithmetic::cmp_greater(self.words(), rhs.words())
304        }
305    }
306
307    fn is_greater_or_equal<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
308        debug_assert_eq!(self.width(), rhs.width());
309        debug_assert_eq!(self.words().len(), rhs.words().len());
310        if self.words().len() == 1 {
311            // specialized for 1-word case
312            crate::bv::arithmetic::cmp_greater_equal(&self.words()[0..1], &rhs.words()[0..1])
313        } else {
314            crate::bv::arithmetic::cmp_greater(self.words(), rhs.words())
315        }
316    }
317
318    fn is_less<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
319        // a < b <=> b > a
320        rhs.is_greater(self)
321    }
322
323    fn is_less_or_equal<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
324        // a <= b <=> b >= a
325        rhs.is_greater_or_equal(self)
326    }
327
328    fn is_greater_signed<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
329        debug_assert_eq!(self.width(), rhs.width());
330        debug_assert_eq!(self.words().len(), rhs.words().len());
331        if self.words().len() == 1 {
332            // specialized for 1-word case
333            crate::bv::arithmetic::cmp_greater_signed(
334                &self.words()[0..1],
335                &rhs.words()[0..1],
336                self.width(),
337            )
338        } else {
339            crate::bv::arithmetic::cmp_greater_signed(self.words(), rhs.words(), self.width())
340        }
341    }
342
343    fn is_greater_or_equal_signed<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
344        debug_assert_eq!(self.width(), rhs.width());
345        debug_assert_eq!(self.words().len(), rhs.words().len());
346        if self.words().len() == 1 {
347            // specialized for 1-word case
348            crate::bv::arithmetic::cmp_greater_equal_signed(
349                &self.words()[0..1],
350                &rhs.words()[0..1],
351                self.width(),
352            )
353        } else {
354            crate::bv::arithmetic::cmp_greater_equal_signed(self.words(), rhs.words(), self.width())
355        }
356    }
357
358    fn is_less_signed<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
359        // a < b <=> b > a
360        rhs.is_greater_signed(self)
361    }
362
363    fn is_less_or_equal_signed<R: BitVecOps + ?Sized>(&self, rhs: &R) -> bool {
364        // a <= b <=> b >= a
365        rhs.is_greater_or_equal_signed(self)
366    }
367
368    fn slice(&self, msb: WidthInt, lsb: WidthInt) -> BitVecValue {
369        debug_assert!(msb <= self.width());
370        debug_assert!(msb >= lsb);
371        let out_width = msb - lsb + 1;
372        let mut out = BitVecValue::zero(out_width);
373        if out_width <= Word::BITS {
374            // specialized for 1-word case
375            crate::bv::arithmetic::slice(&mut out.words_mut()[0..1], self.words(), msb, lsb);
376        } else {
377            crate::bv::arithmetic::slice(out.words_mut(), self.words(), msb, lsb);
378        }
379        out
380    }
381
382    fn is_bit_set(&self, pos: WidthInt) -> bool {
383        crate::bv::arithmetic::is_bit_set(self.words(), pos)
384    }
385
386    fn sign_extend(&self, by: WidthInt) -> BitVecValue {
387        let out_width = self.width() + by;
388        let mut out = BitVecValue::zero(out_width);
389        if out_width <= Word::BITS {
390            // specialized for 1-word case
391            crate::bv::arithmetic::sign_extend(
392                &mut out.words_mut()[0..1],
393                &self.words()[0..1],
394                self.width(),
395                out_width,
396            );
397        } else {
398            crate::bv::arithmetic::sign_extend(
399                out.words_mut(),
400                self.words(),
401                self.width(),
402                out_width,
403            );
404        }
405        out
406    }
407
408    fn zero_extend(&self, by: WidthInt) -> BitVecValue {
409        let out_width = self.width() + by;
410        let mut out = BitVecValue::zero(out_width);
411        if out_width <= Word::BITS {
412            // specialized for 1-word case
413            crate::bv::arithmetic::zero_extend(&mut out.words_mut()[0..1], &self.words()[0..1]);
414        } else {
415            crate::bv::arithmetic::zero_extend(out.words_mut(), self.words());
416        }
417        out
418    }
419
420    fn not(&self) -> BitVecValue {
421        let mut out = BitVecValue::zero(self.width());
422        if self.words().len() <= 1 {
423            // specialized for 1-word case
424            crate::bv::arithmetic::not(
425                &mut out.words_mut()[0..1],
426                &self.words()[0..1],
427                self.width(),
428            );
429        } else {
430            crate::bv::arithmetic::not(out.words_mut(), self.words(), self.width());
431        }
432        out
433    }
434
435    fn negate(&self) -> BitVecValue {
436        let mut out = BitVecValue::zero(self.width());
437        if self.words().len() <= 1 {
438            // specialized for 1-word case
439            crate::bv::arithmetic::negate(
440                &mut out.words_mut()[0..1],
441                &self.words()[0..1],
442                self.width(),
443            );
444        } else {
445            crate::bv::arithmetic::negate(out.words_mut(), self.words(), self.width());
446        }
447        out
448    }
449
450    fn concat<R: BitVecOps + ?Sized>(&self, rhs: &R) -> BitVecValue {
451        let out_width = self.width() + rhs.width();
452        let mut out = BitVecValue::zero(out_width);
453        if out_width <= Word::BITS {
454            // specialized for 1-word case
455            crate::bv::arithmetic::concat(
456                &mut out.words_mut()[0..1],
457                &self.words()[0..1],
458                &rhs.words()[0..1],
459                rhs.width(),
460            );
461        } else {
462            crate::bv::arithmetic::concat(out.words_mut(), self.words(), rhs.words(), rhs.width());
463        }
464        out
465    }
466}
467
468/// Declares an arithmetic function which takes in two equal size bitvector and modifies
469/// a bitvector of same width in place.
470macro_rules! declare_in_place_arith_bin_fn {
471    ($name:ident) => {
472        paste::paste! {
473            fn [<$name _in_place>](&mut self, lhs: &impl BitVecOps, rhs: &impl BitVecOps) {
474                let width = self.width();
475                debug_assert_eq!(width, lhs.width());
476                debug_assert_eq!(lhs.width(), rhs.width());
477                crate::bv::arithmetic::$name(self.words_mut(), lhs.words(), rhs.words(), width);
478            }
479        }
480    };
481}
482
483/// Declares an arithmetic function which takes in two equal size bitvector and modifies
484/// a bitvector of same width in place.
485macro_rules! declare_in_place_bit_bin_fn {
486    ($name:ident) => {
487        paste::paste! {
488            fn [<$name _in_place>](&mut self, lhs: &impl BitVecOps, rhs: &impl BitVecOps) {
489                debug_assert_eq!(self.width(), lhs.width());
490                debug_assert_eq!(lhs.width(), rhs.width());
491                crate::bv::arithmetic::$name(self.words_mut(), lhs.words(), rhs.words());
492            }
493        }
494    };
495}
496
497/// Operations over mutable bit-vector values.
498pub trait BitVecMutOps: BitVecOps {
499    fn words_mut(&mut self) -> &mut [Word];
500
501    declare_in_place_arith_bin_fn!(add);
502    declare_in_place_arith_bin_fn!(sub);
503    declare_in_place_arith_bin_fn!(shift_left);
504    declare_in_place_arith_bin_fn!(shift_right);
505    declare_in_place_arith_bin_fn!(arithmetic_shift_right);
506
507    fn mul_in_place(&mut self, lhs: &impl BitVecOps, rhs: &impl BitVecOps) {
508        let width = self.width();
509        match (self.words_mut(), lhs.words(), rhs.words()) {
510            ([dst], [a], [b]) => {
511                *dst = a.overflowing_mul(*b).0 & mask(width);
512            }
513            ([dst_lsb, dst_msb], [a_lsb, a_msb], [b_lsb, b_msb]) => {
514                [*dst_lsb, *dst_msb] = double_word_to_words(
515                    double_word_from_words(*a_lsb, *a_msb)
516                        .overflowing_mul(double_word_from_words(*b_lsb, *b_msb))
517                        .0
518                        & mask_double_word(width),
519                );
520            }
521            (dst_words_mut, a_words, b_words) => {
522                crate::bv::arithmetic::mul(dst_words_mut, a_words, b_words, width);
523            }
524        }
525    }
526
527    declare_in_place_bit_bin_fn!(and);
528    declare_in_place_bit_bin_fn!(or);
529    declare_in_place_bit_bin_fn!(xor);
530
531    fn concat_in_place(&mut self, lhs: &impl BitVecOps, rhs: &impl BitVecOps) {
532        let width = self.width();
533        debug_assert_eq!(width, lhs.width() + rhs.width());
534        crate::bv::arithmetic::concat(self.words_mut(), lhs.words(), rhs.words(), rhs.width());
535    }
536
537    fn slice_in_place(&mut self, src: &impl BitVecOps, msb: WidthInt, lsb: WidthInt) {
538        let width = self.width();
539        debug_assert_eq!(width, msb - lsb + 1);
540        crate::bv::arithmetic::slice(self.words_mut(), src.words(), msb, lsb);
541    }
542
543    fn not_in_place(&mut self) {
544        self.words_mut().iter_mut().for_each(|word| *word = !*word);
545    }
546
547    fn negate_in_place(&mut self) {
548        let width = self.width();
549        crate::bv::arithmetic::negate_in_place(self.words_mut(), width);
550    }
551
552    fn sign_extend_in_place(&mut self, src: &impl BitVecOps, by: WidthInt) {
553        let width = self.width();
554        debug_assert_eq!(width, src.width() + by);
555        crate::bv::arithmetic::sign_extend(self.words_mut(), src.words(), src.width(), width);
556    }
557
558    fn zero_extend_in_place(&mut self, src: &impl BitVecOps, by: WidthInt) {
559        let width = self.width();
560        debug_assert_eq!(width, src.width() + by);
561        crate::bv::arithmetic::zero_extend(self.words_mut(), src.words());
562    }
563
564    fn assign<'a>(&mut self, value: impl Into<BitVecValueRef<'a>>) {
565        let value = value.into();
566        debug_assert_eq!(self.width(), value.width());
567        debug_assert_eq!(self.words_mut().len(), value.words().len());
568        self.words_mut().copy_from_slice(value.words());
569    }
570
571    /// ensures that all unused bits in the most significant word are set to zero
572    fn mask_msb(&mut self) {
573        let width = self.width();
574        crate::bv::arithmetic::mask_msb(self.words_mut(), width);
575    }
576
577    /// sets all bits to zero
578    fn clear(&mut self) {
579        self.words_mut().iter_mut().for_each(|w| {
580            *w = 0;
581        });
582    }
583
584    /// sets all bits to one
585    fn assign_ones(&mut self) {
586        // set everything to one and then mask off the msb
587        self.words_mut().iter_mut().for_each(|w| {
588            *w = Word::MAX;
589        });
590        self.mask_msb();
591    }
592
593    fn assign_from_u64(&mut self, value: u64) {
594        debug_assert_eq!(Word::BITS, u64::BITS, "basic assumption of this function");
595        // clear all words
596        self.clear();
597        // assign lsb
598        self.words_mut()[0] = value;
599        // make sure the value agrees with the bit width
600        self.mask_msb();
601        debug_assert_eq!(
602            self.words()[0],
603            value,
604            "value {value} does not fit into {} bits",
605            self.width()
606        );
607    }
608
609    fn assign_from_u128(&mut self, value: u128) {
610        debug_assert_eq!(
611            DoubleWord::BITS,
612            u128::BITS,
613            "basic assumption of this function"
614        );
615        // clear all words
616        self.clear();
617        // assign values
618        let words = double_word_to_words(value);
619        self.words_mut()[0] = words[0];
620        self.words_mut()[1] = words[1];
621        // make sure the value agrees with the bit width
622        self.mask_msb();
623        debug_assert_eq!(
624            self.words()[0],
625            words[0],
626            "value {value} does not fit into {} bits",
627            self.width()
628        );
629        debug_assert_eq!(
630            self.words()[1],
631            words[1],
632            "value {value} does not fit into {} bits",
633            self.width()
634        );
635    }
636
637    fn assign_from_i64(&mut self, value: i64) {
638        debug_assert_eq!(Word::BITS, i64::BITS, "basic assumption of this function");
639        let width = self.width();
640        // clear all words
641        self.clear();
642        // assign lsb and sign extend if necessary
643        if self.words().len() == 1 {
644            let masked = value as u64 & crate::bv::arithmetic::mask(width);
645            self.words_mut()[0] = masked;
646        } else {
647            crate::bv::arithmetic::sign_extend(self.words_mut(), &[value as u64], u64::BITS, width);
648        };
649
650        #[cfg(debug_assertions)]
651        if self.is_negative() {
652            if self.width() < Word::BITS {
653                let extra_sign_bits =
654                    crate::bv::arithmetic::mask(Word::BITS - self.width()) << self.width();
655                let word_0 = self.words()[0];
656                let word_0_with_bits = word_0 | extra_sign_bits;
657                debug_assert_eq!(
658                    word_0_with_bits,
659                    value as u64,
660                    "value {value} does not fit into {} bits",
661                    self.width()
662                );
663            } else {
664                debug_assert_eq!(
665                    self.words()[0],
666                    value as u64,
667                    "value {value} does not fit into {} bits",
668                    self.width()
669                );
670            }
671        } else {
672            debug_assert_eq!(
673                self.words()[0],
674                value as u64,
675                "value {value} does not fit into {} bits",
676                self.width()
677            );
678        }
679    }
680
681    fn assign_from_str_radix(&mut self, value: &str, radix: u32) -> Result<(), ParseIntError> {
682        let width = self.width();
683        crate::bv::io::strings::from_str_radix(value, radix, self.words_mut(), width)
684    }
685
686    fn set_bit(&mut self, pos: WidthInt) {
687        crate::bv::arithmetic::set_bit(self.words_mut(), pos);
688    }
689
690    fn clear_bit(&mut self, pos: WidthInt) {
691        crate::bv::arithmetic::clear_bit(self.words_mut(), pos);
692    }
693
694    #[cfg(feature = "rand1")]
695    fn randomize(&mut self, rng: &mut impl RngExt) {
696        rng.fill(self.words_mut());
697        self.mask_msb();
698    }
699}
700
701#[cfg(test)]
702mod tests {
703    use super::*;
704
705    #[test]
706    fn assign_bit_vector() {
707        let mut dst = BitVecValue::zero(123);
708
709        // owned values need to be passed as reference
710        let src = BitVecValue::from_u64(1111111111, 123);
711        dst.assign(&src);
712
713        // bit vec value references are copy, so we can just pass them around as values
714        let src = BitVecValue::from_u64(1111111111 * 2, 123);
715        let src_ref = BitVecValueRef::from(&src);
716        dst.assign(src_ref);
717
718        // make sure src_ref was not moved
719        let value = src_ref.to_u64().unwrap();
720        assert_eq!(value, 1111111111 * 2);
721    }
722
723    #[test]
724    fn test_is_all_ones() {
725        let mut a = BitVecValue::ones(23);
726        assert!(a.is_all_ones());
727        a.clear_bit(20);
728        assert!(!a.is_all_ones());
729
730        let mut a = BitVecValue::ones(1345);
731        assert!(a.is_all_ones());
732        a.clear_bit(1000);
733        assert!(!a.is_all_ones());
734        a.set_bit(1000);
735        assert!(a.is_all_ones());
736    }
737
738    #[test]
739    fn test_is_one() {
740        let mut a = BitVecValue::zero(23);
741        assert!(!a.is_one());
742        a.set_bit(0);
743        assert!(a.is_one());
744        a.set_bit(20);
745        assert!(!a.is_one());
746    }
747
748    #[test]
749    fn test_is_pow_2() {
750        let mut a = BitVecValue::zero(1456);
751        assert_eq!(a.is_pow_2(), None);
752        a.set_bit(0);
753        assert_eq!(a.is_pow_2(), Some(0));
754        a.set_bit(20);
755        assert_eq!(a.is_pow_2(), None);
756
757        for bit in 0..a.width() {
758            a.clear();
759            a.set_bit(bit);
760            assert_eq!(a.is_pow_2(), Some(bit));
761        }
762    }
763
764    #[test]
765    fn test_bit_set_intervals() {
766        let a = BitVecValue::zero(1456);
767        assert_eq!(a.bit_set_intervals(), []);
768        let a = BitVecValue::from_u64(Word::MAX, Word::BITS);
769        assert_eq!(a.bit_set_intervals(), [0..Word::BITS]);
770        let mut a = BitVecValue::from_u64((1 as Word) << (Word::BITS - 1), 127);
771        assert_eq!(a.bit_set_intervals(), [(Word::BITS - 1)..Word::BITS]);
772        a.set_bit(Word::BITS);
773        assert_eq!(a.bit_set_intervals(), [(Word::BITS - 1)..(Word::BITS + 1)]);
774        a.clear_bit(Word::BITS - 1);
775        assert_eq!(a.bit_set_intervals(), [Word::BITS..(Word::BITS + 1)]);
776        a.set_bit(13);
777        assert_eq!(
778            a.bit_set_intervals(),
779            [13..14, Word::BITS..(Word::BITS + 1)]
780        );
781        a.set_bit(14);
782        assert_eq!(
783            a.bit_set_intervals(),
784            [13..15, Word::BITS..(Word::BITS + 1)]
785        );
786    }
787}