@@ -251,30 +251,35 @@ impl Stack {
251
251
/// # Panics
252
252
///
253
253
/// Panics if `n` is 0.
254
- #[ inline]
254
+ #[ inline( always ) ]
255
255
#[ cfg_attr( debug_assertions, track_caller) ]
256
256
pub fn swap ( & mut self , n : usize ) -> Result < ( ) , InstructionResult > {
257
- assume ! ( n > 0 , "attempted to swap with 0" ) ;
258
- let len = self . data . len ( ) ;
259
- if n >= len {
260
- return Err ( InstructionResult :: StackUnderflow ) ;
261
- }
262
- let last_index = len - 1 ;
263
- self . data . swap ( last_index, last_index - n) ;
264
- Ok ( ( ) )
257
+ self . exchange ( 0 , n)
265
258
}
266
259
267
- /// Exchange two values on the stack. where `N` is first index and second index
268
- /// is calculated as N+M
260
+ /// Exchange two values on the stack.
261
+ ///
262
+ /// `n` is the first index, and the second index is calculated as `n + m`.
263
+ ///
264
+ /// # Panics
265
+ ///
266
+ /// Panics if `m` is zero.
269
267
#[ inline]
268
+ #[ cfg_attr( not( debug_assertions) , track_caller) ]
270
269
pub fn exchange ( & mut self , n : usize , m : usize ) -> Result < ( ) , InstructionResult > {
270
+ assume ! ( m > 0 , "overlapping exchange" ) ;
271
271
let len = self . data . len ( ) ;
272
272
let n_m_index = n + m;
273
273
if n_m_index >= len {
274
274
return Err ( InstructionResult :: StackUnderflow ) ;
275
275
}
276
- let last_index = len - 1 ;
277
- self . data . swap ( last_index - n, last_index - n_m_index) ;
276
+ // SAFETY: `n` and `n_m` are checked to be within bounds, and they don't overlap.
277
+ unsafe {
278
+ // NOTE: `mem::swap` performs better than `slice::swap`/`ptr::swap`, as they cannot
279
+ // assume that the pointers are non-overlapping when we know they are not.
280
+ let top = self . data . as_mut_ptr ( ) . add ( len - 1 ) ;
281
+ core:: mem:: swap ( & mut * top. sub ( n) , & mut * top. sub ( n_m_index) ) ;
282
+ }
278
283
Ok ( ( ) )
279
284
}
280
285
0 commit comments