pdep_pext/
lib.rs

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    //          1   0  1 0  0 1 0   1    0    0 0  0
140    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}