diff options
Diffstat (limited to 'src/util.rs')
-rw-r--r-- | src/util.rs | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/util.rs b/src/util.rs index 0a3de227..aa382560 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,5 @@ +use std::iter::Iterator; + /// Threading utilities pub mod thread { /// Like `thread::spawn`, but with a `name` argument @@ -10,3 +12,80 @@ pub mod thread { ::std::thread::Builder::new().name(name.into()).spawn(f).expect("thread spawn works") } } + +/// Types that can have their elements rotated +pub trait Rotate { + fn rotate(&mut self, positions: isize); +} + +impl<T> Rotate for [T] { + fn rotate(&mut self, positions: isize) { + // length is needed over and over + let len = self.len(); + + // Enforce positions in [0, len) and treat negative rotations as a + // posititive rotation of len - positions. + let positions = if positions > 0 { + positions as usize % len + } else { + len - (-positions as usize) % len + }; + + // If positions is 0 or the entire slice, it's a noop. + if positions == 0 || positions == len { + return; + } + + self[..positions].reverse(); + self[positions..].reverse(); + self.reverse(); + } +} + + +#[cfg(test)] +mod tests { + use super::Rotate; + + #[test] + fn rotate_forwards_works() { + let s = &mut [1, 2, 3, 4, 5]; + s.rotate(1); + assert_eq!(&[2, 3, 4, 5, 1], s); + } + + #[test] + fn rotate_backwards_works() { + let s = &mut [1, 2, 3, 4, 5]; + s.rotate(-1); + assert_eq!(&[5, 1, 2, 3, 4], s); + } + + #[test] + fn rotate_multiple_forwards() { + let s = &mut [1, 2, 3, 4, 5, 6, 7]; + s.rotate(2); + assert_eq!(&[3, 4, 5, 6, 7, 1, 2], s); + } + + #[test] + fn rotate_multiple_backwards() { + let s = &mut [1, 2, 3, 4, 5]; + s.rotate(-3); + assert_eq!(&[3, 4, 5, 1, 2], s); + } + + #[test] + fn rotate_forwards_overflow() { + let s = &mut [1, 2, 3, 4, 5]; + s.rotate(6); + assert_eq!(&[2, 3, 4, 5, 1], s); + } + + #[test] + fn rotate_backwards_overflow() { + let s = &mut [1, 2, 3, 4, 5]; + s.rotate(-6); + assert_eq!(&[5, 1, 2, 3, 4], s); + } +} |