@@ -198,6 +198,107 @@ impl_cmov_with_loop!(
198198 "Implementation for `u128` slices where we can just loop."
199199) ;
200200
201+ macro_rules! assert_size_and_alignment_eq {
202+ ( $signed: ty, $unsigned: ty) => {
203+ const {
204+ assert!(
205+ size_of:: <$signed>( ) == size_of:: <$unsigned>( ) ,
206+ "integers are of unequal size"
207+ ) ;
208+
209+ assert!(
210+ align_of:: <$signed>( ) == align_of:: <$unsigned>( ) ,
211+ "integers have unequal alignment"
212+ ) ;
213+ }
214+ } ;
215+ }
216+
217+ /// Implement [`Cmov`] for a signed type by invoking the corresponding unsigned impl.
218+ macro_rules! impl_cmov_for_signed_with_unsigned {
219+ ( $signed: ty, $unsigned: ty) => {
220+ impl_cmov_for_signed_with_unsigned!(
221+ $signed,
222+ $unsigned,
223+ "Delegating implementation of `Cmov` for signed type which delegates to unsigned."
224+ ) ;
225+ } ;
226+ ( $signed: ty, $unsigned: ty, $doc: expr) => {
227+ #[ doc = $doc]
228+ #[ doc = "# Panics" ]
229+ #[ doc = "- if slices have unequal lengths" ]
230+ impl Cmov for [ $signed] {
231+ #[ inline]
232+ #[ track_caller]
233+ fn cmovnz( & mut self , value: & Self , condition: Condition ) {
234+ assert_size_and_alignment_eq!( $signed, $unsigned) ;
235+
236+ // SAFETY:
237+ // - Slices being constructed are of same-sized integers as asserted above.
238+ // - We source the slice length directly from the other valid slice.
239+ #[ allow( unsafe_code) ]
240+ let ( self_unsigned, value_unsigned) = unsafe {
241+ (
242+ slice:: from_raw_parts_mut( self . as_mut_ptr( ) as * mut $unsigned, self . len( ) ) ,
243+ slice:: from_raw_parts( value. as_ptr( ) as * const $unsigned, value. len( ) ) ,
244+ )
245+ } ;
246+
247+ self_unsigned. cmovnz( value_unsigned, condition) ;
248+ }
249+ }
250+ } ;
251+ }
252+
253+ /// Implement [`CmovEq`] for a signed type by invoking the corresponding unsigned impl.
254+ macro_rules! impl_cmoveq_for_signed_with_unsigned {
255+ ( $signed: ty, $unsigned: ty) => {
256+ impl_cmoveq_for_signed_with_unsigned!(
257+ $signed,
258+ $unsigned,
259+ "Delegating implementation of `CmovEq` for signed type which delegates to unsigned."
260+ ) ;
261+ } ;
262+ ( $signed: ty, $unsigned: ty, $doc: expr) => {
263+ #[ doc = $doc]
264+ #[ doc = "# Panics" ]
265+ #[ doc = "- if slices have unequal lengths" ]
266+ impl CmovEq for [ $signed] {
267+ #[ inline]
268+ fn cmovne( & self , rhs: & Self , input: Condition , output: & mut Condition ) {
269+ assert_size_and_alignment_eq!( $signed, $unsigned) ;
270+
271+ // SAFETY:
272+ // - Slices being constructed are of same-sized integers as asserted above.
273+ // - We source the slice length directly from the other valid slice.
274+ #[ allow( unsafe_code) ]
275+ let ( self_unsigned, rhs_unsigned) = unsafe {
276+ (
277+ slice:: from_raw_parts( self . as_ptr( ) as * const $unsigned, self . len( ) ) ,
278+ slice:: from_raw_parts( rhs. as_ptr( ) as * const $unsigned, rhs. len( ) ) ,
279+ )
280+ } ;
281+
282+ self_unsigned. cmovne( rhs_unsigned, input, output) ;
283+ }
284+ }
285+ } ;
286+ }
287+
288+ /// Implement [`Cmov`] and [`CmovEq`] for the given signed/unsigned type pair.
289+ macro_rules! impl_cmov_traits_for_signed_with_unsigned {
290+ ( $signed: ty, $unsigned: ty) => {
291+ impl_cmov_for_signed_with_unsigned!( $signed, $unsigned) ;
292+ impl_cmoveq_for_signed_with_unsigned!( $signed, $unsigned) ;
293+ } ;
294+ }
295+
296+ impl_cmov_traits_for_signed_with_unsigned ! ( i8 , u8 ) ;
297+ impl_cmov_traits_for_signed_with_unsigned ! ( i16 , u16 ) ;
298+ impl_cmov_traits_for_signed_with_unsigned ! ( i32 , u32 ) ;
299+ impl_cmov_traits_for_signed_with_unsigned ! ( i64 , u64 ) ;
300+ impl_cmov_traits_for_signed_with_unsigned ! ( i128 , u128 ) ;
301+
201302/// Optimized implementation for byte slices which coalesces them into word-sized chunks first,
202303/// then performs [`CmovEq`] at the word-level to cut down on the total number of instructions.
203304///
0 commit comments