nanvm_lib/common/
bit_subset64.rs1use core::marker::PhantomData;
2
3use super::cast::Cast;
4
5pub struct BitSubset64<T: Cast<u64> = u64>
26where
27 u64: Cast<T>,
28{
29 pub tag: u64,
33 pub mask: u64,
36 _0: PhantomData<T>,
37}
38
39impl<T: Cast<u64>> Clone for BitSubset64<T>
40where
41 u64: Cast<T>,
42{
43 #[inline(always)]
44 fn clone(&self) -> Self {
45 *self
46 }
47}
48
49impl<T: Cast<u64>> Copy for BitSubset64<T> where u64: Cast<T> {}
50
51impl BitSubset64<u64> {
52 #[inline(always)]
53 pub const fn cast<U: Cast<u64>>(self) -> BitSubset64<U>
54 where
55 u64: Cast<U>,
56 {
57 BitSubset64 {
58 tag: self.tag,
59 mask: self.mask,
60 _0: PhantomData,
61 }
62 }
63}
64
65impl<T: Cast<u64>> BitSubset64<T>
66where
67 u64: Cast<T>,
68{
69 #[inline(always)]
70 pub const fn from_tag_and_mask(tag: u64, mask: u64) -> Self {
71 assert!(mask & tag == tag);
72 Self {
73 tag,
74 mask,
75 _0: PhantomData,
76 }
77 }
78 #[inline(always)]
79 pub const fn from_tag_and_superposition(tag: u64, sup: u64) -> Self {
80 Self::from_tag_and_mask(tag, !sup)
81 }
82 #[inline(always)]
83 pub const fn from_tag_and_union(tag: u64, union: u64) -> Self {
84 Self::from_tag_and_superposition(tag, tag ^ union)
85 }
86 #[inline(always)]
87 pub const fn from_tag(tag: u64) -> Self {
88 Self::from_tag_and_mask(tag, tag)
89 }
90 #[inline(always)]
91 pub const fn has(self, value: u64) -> bool {
92 value & self.mask == self.tag
93 }
94 #[inline(always)]
95 pub const fn union(self) -> u64 {
96 self.tag ^ self.superposition()
97 }
98 #[inline(always)]
99 pub const fn superposition(self) -> u64 {
100 !self.mask
101 }
102 #[inline(always)]
103 pub const fn or_unchecked(self, b: Self) -> Self {
104 Self::from_tag_and_union(self.tag & b.tag, self.union() | b.union())
105 }
106 #[inline(always)]
107 pub const fn or(self, b: Self) -> Self {
108 assert!(self.superposition() == b.superposition());
109 self.or_unchecked(b)
110 }
111 #[inline(always)]
112 pub const fn and(self, b: Self) -> Self {
113 Self::from_tag_and_union(self.tag | b.tag, self.union() & b.union())
114 }
115 #[inline(always)]
116 pub const fn split(self, sub_mask: u64) -> (Self, Self) {
117 assert!(sub_mask != 0);
119 assert!(sub_mask & self.mask == 0);
121 let mask = self.mask | sub_mask;
122 (
124 Self::from_tag_and_mask(self.tag, mask),
125 Self::from_tag_and_mask(self.tag | sub_mask, mask),
126 )
127 }
128 #[inline(always)]
129 const fn subset_value_to_raw_value(self, set: u64) -> u64 {
130 self.superposition() & set
131 }
132 #[inline(always)]
133 pub const fn raw_value_to_subset_value(self, value: u64) -> u64 {
134 self.tag | value
135 }
136 #[inline(always)]
137 pub fn typed_value_to_subset_value(self, value: T) -> u64 {
138 self.raw_value_to_subset_value(value.cast())
139 }
140 #[inline(always)]
141 pub fn subset_value_to_typed_value(self, set: u64) -> T {
142 (self.subset_value_to_raw_value(set)).cast()
143 }
144}
145
146#[cfg(test)]
147mod test {
148 use wasm_bindgen_test::wasm_bindgen_test;
149
150 use super::BitSubset64;
151
152 const A: BitSubset64 = BitSubset64::from_tag_and_union(0b010, 0b011);
153 const _: () = assert!(A.superposition() == 0b001);
154 const _: () = assert!(A.tag == 0b010);
155 const _: () = assert!(!A.has(0b000));
156 const _: () = assert!(A.has(0b010));
157 const _: () = assert!(A.has(0b011));
158
159 const _AS: (BitSubset64, BitSubset64) = A.split(1);
160 const _: () = assert!(_AS.0.tag == 0b010);
161 const _: () = assert!(_AS.0.superposition() == 0);
162 const _: () = assert!(_AS.1.tag == 0b011);
163 const _: () = assert!(_AS.1.superposition() == 0);
164
165 #[test]
166 #[wasm_bindgen_test]
167 fn test_a() {
168 assert_eq!(A.superposition(), 0b001);
169 assert_eq!(A.tag, 0b010);
170 assert!(!A.has(0b000));
171 assert!(A.has(0b010));
172 assert!(A.has(0b011));
173 }
174
175 const B: BitSubset64 = BitSubset64::from_tag_and_union(0b000110, 0b000111);
176 const C: BitSubset64 = BitSubset64::from_tag_and_union(0b010100, 0b011111);
177 const UBC: BitSubset64 = B.or_unchecked(C);
178 const _: () = assert!(UBC.superposition() == 0b011011);
179 const _: () = assert!(UBC.tag == 0b000100);
180 const _: () = assert!(UBC.union() == 0b011111);
181
182 const _UBCS: (BitSubset64, BitSubset64) = UBC.split(0b1000);
183 const _: () = assert!(_UBCS.0.superposition() == 0b010011);
184 const _: () = assert!(_UBCS.0.tag == 0b000100);
185 const _: () = assert!(_UBCS.1.tag == 0b001100);
186
187 #[test]
188 #[wasm_bindgen_test]
189 fn test_ubc() {
190 assert_eq!(UBC.superposition(), 0b011011);
191 assert_eq!(UBC.tag, 0b000100);
192 assert_eq!(UBC.union(), 0b011111);
193 }
194
195 #[test]
196 #[wasm_bindgen_test]
197 #[should_panic]
198 fn test_ibc() {
199 B.and(C);
200 }
201
202 #[test]
203 #[wasm_bindgen_test]
204 #[should_panic]
205 fn test_split_fail() {
206 UBC.split(0b100);
207 }
208
209 const D: BitSubset64 = BitSubset64::from_tag_and_union(0b00110, 0b00111);
210 const E: BitSubset64 = BitSubset64::from_tag_and_union(0b00100, 0b01111);
211 const UDE: BitSubset64 = D.or_unchecked(E);
212 const _: () = assert!(UDE.superposition() == 0b01011);
213 const _: () = assert!(UDE.tag == 0b00100);
214 const _: () = assert!(UDE.union() == 0b01111);
215 const IDE: BitSubset64 = D.and(E);
216 const _: () = assert!(IDE.superposition() == 0b00001);
217 const _: () = assert!(IDE.tag == 0b00110);
218 const _: () = assert!(IDE.union() == 0b00111);
219
220 #[test]
221 #[wasm_bindgen_test]
222 fn test_ude() {
223 assert_eq!(UDE.superposition(), 0b01011);
224 assert_eq!(UDE.tag, 0b00100);
225 assert_eq!(UDE.union(), 0b01111);
226 }
227
228 #[test]
229 #[wasm_bindgen_test]
230 fn test_ide() {
231 assert_eq!(IDE.superposition(), 0b00001);
232 assert_eq!(IDE.tag, 0b00110);
233 assert_eq!(IDE.union(), 0b00111);
234 }
235}