1#![cfg_attr(
30 feature = "sort_slices",
31 doc = r"```
32use compile_time_sort::sort_i32_slice;
33
34const SORTED_ARRAY: [i32; 5] = {
35 let mut arr = [5, i32::MIN, 0, -2, 0];
36 sort_i32_slice(&mut arr);
37 arr
38};
39
40assert_eq!(SORTED_ARRAY, [i32::MIN, -2, 0, 0, 5]);
41```"
42)]
43#![no_std]
49#![cfg_attr(docsrs, feature(doc_auto_cfg))]
50
51#[cfg(feature = "sort_slices")]
52macro_rules! const_slice_quicksort {
55 ($name:ident, $tpe:ty) => {
56 const fn $name(slice: &mut [$tpe], left: usize, right: usize) {
57 let pivot_candidate_1 = left;
58 let pivot_candidate_2 = left + (right - left) / 2;
59 let pivot_candidate_3 = right;
60 let mut pivot_index = if slice[pivot_candidate_1] < slice[pivot_candidate_2] {
61 if slice[pivot_candidate_3] < slice[pivot_candidate_2] {
62 if slice[pivot_candidate_1] < slice[pivot_candidate_3] {
63 pivot_candidate_3
64 } else {
65 pivot_candidate_1
66 }
67 } else {
68 pivot_candidate_2
69 }
70 } else {
71 if slice[pivot_candidate_3] < slice[pivot_candidate_1] {
72 if slice[pivot_candidate_2] < slice[pivot_candidate_3] {
73 pivot_candidate_3
74 } else {
75 pivot_candidate_2
76 }
77 } else {
78 pivot_candidate_1
79 }
80 };
81
82 let mut l = left;
83 let mut r = right;
84
85 while l < r {
86 while (slice[pivot_index] < slice[r]) && (l < r) {
87 r -= 1;
88 }
89 if l != r {
90 (slice[pivot_index], slice[r]) = (slice[r], slice[pivot_index]);
91 pivot_index = r;
92 }
93 while (slice[l] < slice[pivot_index]) && (l < r) {
94 l += 1;
95 }
96 if l != r {
97 (slice[pivot_index], slice[l]) = (slice[l], slice[pivot_index]);
98 pivot_index = l;
99 }
100 if l != r && slice[l] == slice[r] {
101 break;
104 }
105 }
106 if left < l {
107 $name(slice, left, l - 1);
108 }
109 if right > l {
110 $name(slice, l + 1, right);
111 }
112 }
113 };
114}
115
116macro_rules! const_array_quicksort {
118 ($name:ident, $tpe:ty) => {
119 const fn $name<const N: usize>(
120 mut array: [$tpe; N],
121 left: usize,
122 right: usize,
123 ) -> [$tpe; N] {
124 let pivot_candidate_1 = left;
125 let pivot_candidate_2 = left + (right - left) / 2;
126 let pivot_candidate_3 = right;
127 let mut pivot_index = if array[pivot_candidate_1] < array[pivot_candidate_2] {
128 if array[pivot_candidate_3] < array[pivot_candidate_2] {
129 if array[pivot_candidate_1] < array[pivot_candidate_3] {
130 pivot_candidate_3
131 } else {
132 pivot_candidate_1
133 }
134 } else {
135 pivot_candidate_2
136 }
137 } else {
138 if array[pivot_candidate_3] < array[pivot_candidate_1] {
139 if array[pivot_candidate_2] < array[pivot_candidate_3] {
140 pivot_candidate_3
141 } else {
142 pivot_candidate_2
143 }
144 } else {
145 pivot_candidate_1
146 }
147 };
148
149 let mut l = left;
150 let mut r = right;
151
152 while l < r {
153 while (array[pivot_index] < array[r]) && (l < r) {
154 r -= 1;
155 }
156 if l != r {
157 (array[pivot_index], array[r]) = (array[r], array[pivot_index]);
158 pivot_index = r;
159 }
160 while (array[l] < array[pivot_index]) && (l < r) {
161 l += 1;
162 }
163 if l != r {
164 (array[pivot_index], array[l]) = (array[l], array[pivot_index]);
165 pivot_index = l;
166 }
167 if l != r && array[l] == array[r] {
168 break;
169 }
170 }
171 if left < l {
172 array = $name(array, left, l - 1);
173 }
174 if right > l {
175 array = $name(array, l + 1, right);
176 }
177 array
178 }
179 };
180}
181
182macro_rules! impl_const_quicksort {
183 ($pub_name_array:ident, $pub_name_slice:ident, $qsort_slice_name:ident, $qsort_array_name:ident, $tpe:ty, $tpe_name: literal) => {
184 #[cfg(feature = "sort_slices")]
185 const_slice_quicksort!{$qsort_slice_name, $tpe}
186
187 const_array_quicksort!{$qsort_array_name, $tpe}
188
189 #[doc = concat!("Sorts the given array of `", $tpe_name, "`s using the quicksort algorithm")]
190 pub const fn $pub_name_array<const N: usize>(array: [$tpe; N]) -> [$tpe; N] {
191 if N == 0 || N == 1 {
192 return array;
193 }
194 $qsort_array_name(array, 0, N - 1)
195 }
196
197 #[cfg(feature = "sort_slices")]
198 #[doc = concat!("Sorts the given slice of `", $tpe_name, "`s using the quicksort algorithm")]
199 pub const fn $pub_name_slice(slice: &mut [$tpe]) {
200 if slice.is_empty() || slice.len() == 1 {
201 return;
202 }
203 let last = slice.len() - 1;
204 $qsort_slice_name(slice, 0, last);
205 }
206 };
207}
208
209impl_const_quicksort!(
210 into_sorted_char_array,
211 sort_char_slice,
212 qsort_char_slice,
213 qsort_char_array,
214 char,
215 "char"
216);
217impl_const_quicksort!(
218 into_sorted_u16_array,
219 sort_u16_slice,
220 qsort_u16_slice,
221 qsort_u16_array,
222 u16,
223 "u16"
224);
225impl_const_quicksort!(
226 into_sorted_i16_array,
227 sort_i16_slice,
228 qsort_i16_slice,
229 qsort_i16_array,
230 i16,
231 "i16"
232);
233impl_const_quicksort!(
234 into_sorted_u32_array,
235 sort_u32_slice,
236 qsort_u32_slice,
237 qsort_u32_array,
238 u32,
239 "u32"
240);
241impl_const_quicksort!(
242 into_sorted_i32_array,
243 sort_i32_slice,
244 qsort_i32_slice,
245 qsort_i32_array,
246 i32,
247 "i32"
248);
249impl_const_quicksort!(
250 into_sorted_u64_array,
251 sort_u64_slice,
252 qsort_u64_slice,
253 qsort_u64_array,
254 u64,
255 "u64"
256);
257impl_const_quicksort!(
258 into_sorted_i64_array,
259 sort_i64_slice,
260 qsort_i64_slice,
261 qsort_i64_array,
262 i64,
263 "i64"
264);
265impl_const_quicksort!(
266 into_sorted_u128_array,
267 sort_u128_slice,
268 qsort_u128_slice,
269 qsort_u128_array,
270 u128,
271 "u128"
272);
273impl_const_quicksort!(
274 into_sorted_i128_array,
275 sort_i128_slice,
276 qsort_i128_slice,
277 qsort_i128_array,
278 i128,
279 "i128"
280);
281impl_const_quicksort!(
282 into_sorted_usize_array,
283 sort_usize_slice,
284 qsort_usize_slice,
285 qsort_usize_array,
286 usize,
287 "usize"
288);
289impl_const_quicksort!(
290 into_sorted_isize_array,
291 sort_isize_slice,
292 qsort_isize_slice,
293 qsort_isize_array,
294 isize,
295 "isize"
296);
297
298#[cfg(feature = "sort_slices")]
299pub const fn sort_i8_slice(slice: &mut [i8]) {
301 if slice.is_empty() || slice.len() == 1 {
302 return;
303 }
304 let mut counts = [0_usize; u8::MAX as usize + 1];
305 let mut i = 0;
306 let n = slice.len();
307 while i < n {
308 counts[(slice[i] as i16 + i8::MIN.unsigned_abs() as i16) as usize] += 1;
309 i += 1;
310 }
311 i = 0;
312 let mut j = 0;
313 'outer: while i < n {
314 while counts[j] == 0 {
315 if j + 1 > u8::MAX as usize {
316 break 'outer;
317 }
318 j += 1;
319 }
320 slice[i] = (j as i16 + i8::MIN.unsigned_abs() as i16) as i8;
321 counts[j] -= 1;
322 i += 1;
323 }
324}
325
326pub const fn into_sorted_i8_array<const N: usize>(mut array: [i8; N]) -> [i8; N] {
328 if N == 0 || N == 1 {
329 return array;
330 }
331 let mut counts = [0_usize; u8::MAX as usize + 1];
332 let mut i = 0;
333 while i < N {
334 counts[(array[i] as i16 + i8::MIN.unsigned_abs() as i16) as usize] += 1;
335 i += 1;
336 }
337
338 i = 0;
339 let mut j = 0;
340 'outer: while i < N {
341 while counts[j] == 0 {
342 if j + 1 > u8::MAX as usize {
343 break 'outer;
344 }
345 j += 1;
346 }
347 array[i] = (j as i16 + i8::MIN.unsigned_abs() as i16) as i8;
348 counts[j] -= 1;
349 i += 1;
350 }
351
352 array
353}
354
355#[cfg(feature = "sort_slices")]
356pub const fn sort_u8_slice(slice: &mut [u8]) {
358 if slice.is_empty() || slice.len() == 1 {
359 return;
360 }
361 let mut counts = [0_usize; u8::MAX as usize + 1];
362 let mut i = 0;
363 let n = slice.len();
364 while i < n {
365 counts[slice[i] as usize] += 1;
366 i += 1;
367 }
368 i = 0;
369 let mut j = 0;
370 'outer: while i < n {
371 while counts[j] == 0 {
372 if j + 1 > u8::MAX as usize {
373 break 'outer;
374 }
375 j += 1;
376 }
377 slice[i] = j as u8;
378 counts[j] -= 1;
379 i += 1;
380 }
381}
382
383pub const fn into_sorted_u8_array<const N: usize>(mut array: [u8; N]) -> [u8; N] {
385 if N == 0 || N == 1 {
386 return array;
387 }
388 let mut counts = [0_usize; u8::MAX as usize + 1];
389 let mut i = 0;
390 while i < N {
391 counts[array[i] as usize] += 1;
392 i += 1;
393 }
394 i = 0;
395 let mut j = 0;
396 'outer: while i < N {
397 while counts[j] == 0 {
398 if j + 1 > u8::MAX as usize {
399 break 'outer;
400 }
401 j += 1;
402 }
403 array[i] = j as u8;
404 counts[j] -= 1;
405 i += 1;
406 }
407 array
408}
409
410#[cfg(feature = "sort_slices")]
411pub const fn sort_bool_slice(slice: &mut [bool]) {
413 if slice.is_empty() || slice.len() == 1 {
414 return;
415 }
416 let mut falses = 0;
417 let mut i = 0;
418 let n = slice.len();
419 while i < n {
420 if !slice[i] {
421 falses += 1;
422 }
423 i += 1;
424 }
425
426 i = 0;
427 while i < n {
428 if falses > 0 {
429 slice[i] = false;
430 falses -= 1;
431 } else {
432 slice[i] = true;
433 }
434 i += 1;
435 }
436}
437
438pub const fn into_sorted_bool_array<const N: usize>(mut array: [bool; N]) -> [bool; N] {
440 if N == 0 || N == 1 {
441 return array;
442 }
443 let mut falses = 0;
444 let mut i = 0;
445 while i < N {
446 if !array[i] {
447 falses += 1;
448 }
449 i += 1;
450 }
451
452 i = 0;
453 while i < N {
454 if falses > 0 {
455 array[i] = false;
456 falses -= 1;
457 } else {
458 array[i] = true;
459 }
460 i += 1;
461 }
462
463 array
464}