1 use num_bigint::{BigInt, Sign, ToBigInt};
2 use num_traits::ToPrimitive;
3
4 enum ValueVec {
5 N,
6 P(&'static [u32]),
7 M(&'static [u32]),
8 }
9
10 use crate::ValueVec::*;
11
12 impl ToBigInt for ValueVec {
to_bigint(&self) -> Option<BigInt>13 fn to_bigint(&self) -> Option<BigInt> {
14 match self {
15 &N => Some(BigInt::from_slice(Sign::NoSign, &[])),
16 &P(s) => Some(BigInt::from_slice(Sign::Plus, s)),
17 &M(s) => Some(BigInt::from_slice(Sign::Minus, s)),
18 }
19 }
20 }
21
22 // a, !a
23 const NOT_VALUES: &[(ValueVec, ValueVec)] = &[
24 (N, M(&[1])),
25 (P(&[1]), M(&[2])),
26 (P(&[2]), M(&[3])),
27 (P(&[!0 - 2]), M(&[!0 - 1])),
28 (P(&[!0 - 1]), M(&[!0])),
29 (P(&[!0]), M(&[0, 1])),
30 (P(&[0, 1]), M(&[1, 1])),
31 (P(&[1, 1]), M(&[2, 1])),
32 ];
33
34 // a, b, a & b, a | b, a ^ b
35 const BITWISE_VALUES: &[(ValueVec, ValueVec, ValueVec, ValueVec, ValueVec)] = &[
36 (N, N, N, N, N),
37 (N, P(&[1]), N, P(&[1]), P(&[1])),
38 (N, P(&[!0]), N, P(&[!0]), P(&[!0])),
39 (N, P(&[0, 1]), N, P(&[0, 1]), P(&[0, 1])),
40 (N, M(&[1]), N, M(&[1]), M(&[1])),
41 (N, M(&[!0]), N, M(&[!0]), M(&[!0])),
42 (N, M(&[0, 1]), N, M(&[0, 1]), M(&[0, 1])),
43 (P(&[1]), P(&[!0]), P(&[1]), P(&[!0]), P(&[!0 - 1])),
44 (P(&[!0]), P(&[!0]), P(&[!0]), P(&[!0]), N),
45 (P(&[!0]), P(&[1, 1]), P(&[1]), P(&[!0, 1]), P(&[!0 - 1, 1])),
46 (P(&[1]), M(&[!0]), P(&[1]), M(&[!0]), M(&[0, 1])),
47 (P(&[!0]), M(&[1]), P(&[!0]), M(&[1]), M(&[0, 1])),
48 (P(&[!0]), M(&[!0]), P(&[1]), M(&[1]), M(&[2])),
49 (P(&[!0]), M(&[1, 1]), P(&[!0]), M(&[1, 1]), M(&[0, 2])),
50 (P(&[1, 1]), M(&[!0]), P(&[1, 1]), M(&[!0]), M(&[0, 2])),
51 (M(&[1]), M(&[!0]), M(&[!0]), M(&[1]), P(&[!0 - 1])),
52 (M(&[!0]), M(&[!0]), M(&[!0]), M(&[!0]), N),
53 (M(&[!0]), M(&[1, 1]), M(&[!0, 1]), M(&[1]), P(&[!0 - 1, 1])),
54 ];
55
56 const I32_MIN: i64 = i32::MIN as i64;
57 const I32_MAX: i64 = i32::MAX as i64;
58 const U32_MAX: i64 = u32::MAX as i64;
59
60 // some corner cases
61 const I64_VALUES: &[i64] = &[
62 i64::MIN,
63 i64::MIN + 1,
64 i64::MIN + 2,
65 i64::MIN + 3,
66 -U32_MAX - 3,
67 -U32_MAX - 2,
68 -U32_MAX - 1,
69 -U32_MAX,
70 -U32_MAX + 1,
71 -U32_MAX + 2,
72 -U32_MAX + 3,
73 I32_MIN - 3,
74 I32_MIN - 2,
75 I32_MIN - 1,
76 I32_MIN,
77 I32_MIN + 1,
78 I32_MIN + 2,
79 I32_MIN + 3,
80 -3,
81 -2,
82 -1,
83 0,
84 1,
85 2,
86 3,
87 I32_MAX - 3,
88 I32_MAX - 2,
89 I32_MAX - 1,
90 I32_MAX,
91 I32_MAX + 1,
92 I32_MAX + 2,
93 I32_MAX + 3,
94 U32_MAX - 3,
95 U32_MAX - 2,
96 U32_MAX - 1,
97 U32_MAX,
98 U32_MAX + 1,
99 U32_MAX + 2,
100 U32_MAX + 3,
101 i64::MAX - 3,
102 i64::MAX - 2,
103 i64::MAX - 1,
104 i64::MAX,
105 ];
106
107 #[test]
test_not()108 fn test_not() {
109 for &(ref a, ref not) in NOT_VALUES.iter() {
110 let a = a.to_bigint().unwrap();
111 let not = not.to_bigint().unwrap();
112
113 // sanity check for tests that fit in i64
114 if let (Some(prim_a), Some(prim_not)) = (a.to_i64(), not.to_i64()) {
115 assert_eq!(!prim_a, prim_not);
116 }
117
118 assert_eq!(!a.clone(), not, "!{:x}", a);
119 assert_eq!(!not.clone(), a, "!{:x}", not);
120 }
121 }
122
123 #[test]
test_not_i64()124 fn test_not_i64() {
125 for &prim_a in I64_VALUES.iter() {
126 let a = prim_a.to_bigint().unwrap();
127 let not = (!prim_a).to_bigint().unwrap();
128 assert_eq!(!a.clone(), not, "!{:x}", a);
129 }
130 }
131
132 #[test]
test_bitwise()133 fn test_bitwise() {
134 for &(ref a, ref b, ref and, ref or, ref xor) in BITWISE_VALUES.iter() {
135 let a = a.to_bigint().unwrap();
136 let b = b.to_bigint().unwrap();
137 let and = and.to_bigint().unwrap();
138 let or = or.to_bigint().unwrap();
139 let xor = xor.to_bigint().unwrap();
140
141 // sanity check for tests that fit in i64
142 if let (Some(prim_a), Some(prim_b)) = (a.to_i64(), b.to_i64()) {
143 if let Some(prim_and) = and.to_i64() {
144 assert_eq!(prim_a & prim_b, prim_and);
145 }
146 if let Some(prim_or) = or.to_i64() {
147 assert_eq!(prim_a | prim_b, prim_or);
148 }
149 if let Some(prim_xor) = xor.to_i64() {
150 assert_eq!(prim_a ^ prim_b, prim_xor);
151 }
152 }
153
154 assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b);
155 assert_eq!(b.clone() & &a, and, "{:x} & {:x}", b, a);
156 assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b);
157 assert_eq!(b.clone() | &a, or, "{:x} | {:x}", b, a);
158 assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b);
159 assert_eq!(b.clone() ^ &a, xor, "{:x} ^ {:x}", b, a);
160 }
161 }
162
163 #[test]
test_bitwise_i64()164 fn test_bitwise_i64() {
165 for &prim_a in I64_VALUES.iter() {
166 let a = prim_a.to_bigint().unwrap();
167 for &prim_b in I64_VALUES.iter() {
168 let b = prim_b.to_bigint().unwrap();
169 let and = (prim_a & prim_b).to_bigint().unwrap();
170 let or = (prim_a | prim_b).to_bigint().unwrap();
171 let xor = (prim_a ^ prim_b).to_bigint().unwrap();
172 assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b);
173 assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b);
174 assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b);
175 }
176 }
177 }
178