1#![deny(missing_docs)]
2
3use core::cmp::Ordering;
4use core::mem::{self, ManuallyDrop};
5use core::ptr;
6
7use crate::util;
8
9#[inline]
23pub fn cycle_sort<T>(slice: &mut [T]) -> usize
24where
25 T: Ord,
26{
27 cycle_impl(slice, &|a, b| a.lt(b))
28}
29
30#[inline]
45pub fn cycle_sort_by<T, F>(slice: &mut [T], compare: &F) -> usize
46where
47 F: Fn(&T, &T) -> Ordering,
48{
49 cycle_impl(slice, &|a, b| compare(a, b) == Ordering::Less)
50}
51
52#[inline]
67pub fn cycle_sort_by_key<T, F, U>(slice: &mut [T], key: &F) -> usize
68where
69 F: Fn(&T) -> U,
70 U: Ord,
71{
72 cycle_impl(slice, &|a, b| key(a).lt(&key(b)))
73}
74
75fn cycle_impl<T, F>(slice: &mut [T], is_less: &F) -> usize
76where
77 F: Fn(&T, &T) -> bool,
78{
79 let length = slice.len();
80
81 if mem::size_of::<T>() == 0 || length < 2 {
83 return 0;
84 }
85
86 let mut writes = 0;
87
88 for src in 0..length - 1 {
89 let mut tmp = unsafe { ManuallyDrop::new(ptr::read(&slice[src])) };
90 let mut dst = src;
91
92 for i in src + 1..length {
94 if is_less(&slice[i], &tmp) {
95 dst += 1;
96 }
97 }
98
99 if dst == src {
101 continue;
102 }
103
104 while util::are_equal(&*tmp, &slice[dst], is_less) {
106 dst += 1;
107 }
108
109 mem::swap(&mut *tmp, &mut slice[dst]);
111 writes += 1;
112
113 while dst != src {
116 dst = src;
117
118 for i in src + 1..length {
119 if is_less(&slice[i], &tmp) {
120 dst += 1;
121 }
122 }
123
124 while util::are_equal(&*tmp, &slice[dst], is_less) {
125 dst += 1;
126 }
127
128 mem::swap(&mut *tmp, &mut slice[dst]);
129 writes += 1;
130 }
131 }
132
133 writes
134}
135
136#[cfg(test)]
137mod tests {
138 use crate::cycle_sort;
139
140 extern crate std;
141 use std::string::String;
142 use std::vec::Vec;
143
144 use rand::{distributions::Alphanumeric, seq::SliceRandom, thread_rng, Rng};
145
146 macro_rules! assert_sorted {
147 ($x:expr) => {
148 assert!($x.windows(2).all(|w| w[0] <= w[1]))
149 };
150 }
151
152 #[test]
153 fn zero_sized_elements() {
154 const SIZE: usize = 1100;
155
156 let mut array = [(); SIZE];
157
158 for length in (0..10).chain(1000..SIZE + 1) {
159 let mut slice = &mut array[..length];
160 let writes = cycle_sort(&mut slice);
161
162 assert_eq!(writes, 0);
163 }
164 }
165
166 #[test]
167 fn basic_sort() {
168 const SIZE: usize = 110;
169
170 let mut array = [0_i32; SIZE];
171 let mut rng = thread_rng();
172
173 for length in (0..20).chain(100..SIZE + 1) {
174 let mut slice = &mut array[..length];
175
176 for _ in 0..10 {
177 rng.fill(slice);
178 cycle_sort(&mut slice);
179
180 assert_sorted!(slice);
181 }
182 }
183 }
184
185 #[test]
186 fn sort_strings() {
187 const SIZE: usize = 128;
188 const LENGTH: usize = 128;
189
190 let mut rng = thread_rng();
191 let mut vec: Vec<String> = Vec::with_capacity(SIZE);
192
193 for _ in 0..10 {
194 vec.clear();
195
196 for _ in 0..SIZE {
198 vec.push(rng.sample_iter(&Alphanumeric).take(LENGTH).collect());
199 }
200
201 vec.as_mut_slice().shuffle(&mut rng);
203 cycle_sort(vec.as_mut_slice());
204
205 assert_sorted!(vec.as_slice());
206 }
207 }
208
209 #[test]
210 fn many_duplicates() {
211 const SIZE: usize = 100;
212
213 let mut array = [0_u8; SIZE];
214 let mut rng = thread_rng();
215
216 for length in 80..SIZE {
217 let mut slice = &mut array[..length];
218
219 for divisor in &[11, 13, 17, 19] {
220 for _ in 0..10 {
221 rng.fill(slice);
222 for x in slice.iter_mut() {
223 *x %= divisor;
224 }
225
226 cycle_sort(&mut slice);
227
228 assert_sorted!(slice);
229 }
230 }
231 }
232 }
233
234 #[test]
235 fn correct_writes() {
236 const SIZE: usize = 25;
237
238 let mut array = [0; SIZE];
239
240 for i in 0..SIZE {
241 array[i] = i;
242 }
243
244 let mut rng = thread_rng();
245
246 for length in 1..SIZE + 1 {
247 let mut slice = &mut array[..length];
248
249 for _ in 0..10 {
250 slice.shuffle(&mut rng);
251
252 let expect = slice.iter().enumerate().filter(|&(i, v)| i != *v).count();
253 let writes = cycle_sort(&mut slice);
254
255 assert_sorted!(slice);
256 assert_eq!(writes, expect);
257 }
258 }
259 }
260}