1pub trait Pdep<Mask> {
2 fn pdep(self, mask: Mask) -> Self;
3}
4
5pub trait Pext<Mask> {
6 fn pext(self, mask: Mask) -> Self;
7}
8
9macro_rules! pext_loop {
10 ( $mk:ident, $m:ident, $sh:expr ) => {{
11 let mp = Self::mp($mk);
12 let mv = mp & $m;
13 $m = $m ^ mv | (mv >> (1 << $sh));
14 $mk &= !mp;
15 mv
16 }};
17}
18
19macro_rules! impl_pdep_pext_mask {
20 ( ($maskty:ident, $basety:ident, [$($i:literal),*], $lg:literal) ) => {
21 #[derive(Clone, Copy)]
22 pub struct $maskty($basety, [$basety; $lg]);
23 impl $maskty {
24 pub const LG_W: $basety = $lg;
25 pub const fn new(mut m: $basety) -> Self {
26 let m0 = m;
27 let mut res = [0; $lg];
28 let mut mk = !m << 1;
29 $( res[$i] = pext_loop!(mk, m, $i) );*;
30 res[$lg - 1] = Self::mp(mk) & m;
31 Self(m0, res)
32 }
33 const fn mp(mk: $basety) -> $basety {
34 let mut mp = mk ^ (mk << 1);
35 $( mp ^= mp << (1 << (1 + $i)) );*;
36 mp
37 }
38 pub const fn get(self) -> $basety { self.0 }
39 }
40 };
41 ( $( ( $($tt:tt)* ), )* ) => { $( impl_pdep_pext_mask!( ( $($tt)* ) ); )* };
42}
43
44impl_pdep_pext_mask! {
45 (PdepPextMaskU8, u8, [0, 1], 3),
46 (PdepPextMaskU16, u16, [0, 1, 2], 4),
47 (PdepPextMaskU32, u32, [0, 1, 2, 3], 5),
48 (PdepPextMaskU64, u64, [0, 1, 2, 3, 4], 6),
49 (PdepPextMaskU128, u128, [0, 1, 2, 3, 4, 5], 7),
50}
51
52#[cfg(target_pointer_width = "32")]
53impl_pdep_pext_mask! { (PdepPextMaskUsize, usize, [0, 1, 2, 3], 5) }
54#[cfg(target_pointer_width = "64")]
55impl_pdep_pext_mask! { (PdepPextMaskUsize, usize, [0, 1, 2, 3, 4], 6) }
56
57macro_rules! impl_pext {
58 ( ($maskty:ident, $basety:ident, $lg:literal) ) => {
59 impl Pext<$basety> for $basety {
60 fn pext(self, mut m: $basety) -> $basety {
61 let mut x = self & m;
62 let mut mk = !m << 1;
63 for i in 0..$lg {
64 let mut mp = mk ^ (mk << 1);
65 for j in 1..$lg {
66 mp ^= mp << (1 << j);
67 }
68 let mv = mp & m;
69 m = m ^ mv | (mv >> (1 << i));
70 let t = x & mv;
71 x = (x ^ t) | (t >> (1 << i));
72 mk &= !mp;
73 }
74 x
75 }
76 }
77 impl Pext<$maskty> for $basety {
78 fn pext(self, mask: $maskty) -> $basety {
79 let mut x = self & mask.0;
80 for i in 0..$lg {
81 let mv = mask.1[i];
82 let t = x & mv;
83 x = (x ^ t) | (t >> (1 << i));
84 }
85 x
86 }
87 }
88 };
89 ( $( ( $($tt:tt)* ), )* ) => { $( impl_pext!( ( $($tt)* ) ); )* };
90}
91
92impl_pext! {
93 (PdepPextMaskU8, u8, 3),
94 (PdepPextMaskU16, u16, 4),
95 (PdepPextMaskU32, u32, 5),
96 (PdepPextMaskU64, u64, 6),
97 (PdepPextMaskU128, u128, 7),
98}
99
100#[cfg(target_pointer_width = "32")]
101impl_pext! { (PdepPextMaskUsize, usize, 5) }
102#[cfg(target_pointer_width = "64")]
103impl_pext! { (PdepPextMaskUsize, usize, 6) }
104
105macro_rules! impl_pdep {
106 ( ($maskty:ident, $basety:ident, $lg:literal) ) => {
107 impl Pdep<$basety> for $basety {
108 fn pdep(self, m: $basety) -> $basety {
109 self.pdep(<$maskty>::new(m))
110 }
111 }
112 impl Pdep<$maskty> for $basety {
113 fn pdep(self, mask: $maskty) -> $basety {
114 let mut x = self;
115 for i in (0..$lg).rev() {
116 let mv = mask.1[i];
117 let t = x << (1 << i);
118 x = (x & !mv) | (t & mv);
119 }
120 x & mask.0
121 }
122 }
123 };
124 ( $( ( $($tt:tt)* ), )* ) => { $( impl_pdep!( ( $($tt)* ) ); )* };
125}
126
127impl_pdep! {
128 (PdepPextMaskU8, u8, 3),
129 (PdepPextMaskU16, u16, 4),
130 (PdepPextMaskU32, u32, 5),
131 (PdepPextMaskU64, u64, 6),
132 (PdepPextMaskU128, u128, 7),
133}
134
135#[test]
136fn sanity_check() {
137 let x = 0b_0101_0111_0000_1001_1110_1010_0000_0010_u32;
138 let m = 0b_0100_1001_1001_1010_0100_0100_0101_0100_u32;
139 let ext = 0b_1010_0101_0000;
141
142 assert_eq!(x.pext(m), ext);
143 assert_eq!(x.pext(PdepPextMaskU32::new(m)), ext);
144 assert_eq!(ext.pdep(m), x & m);
145}