Skip to main content

alphanumeric_sort/
std_functions.rs

1use core::cmp::Ordering;
2use std::{
3    ffi::{CStr, OsStr},
4    path::Path,
5};
6
7use crate::compare_str;
8
9/// Compare two `OsStr`.
10///
11/// The alphanumeric algorithm is used only when both values can be converted to UTF-8
12/// with `OsStr::to_str`. If either value cannot be converted, this falls back to the
13/// native `OsStr` ordering.
14#[inline]
15pub fn compare_os_str<A: AsRef<OsStr>, B: AsRef<OsStr>>(a: A, b: B) -> Ordering {
16    let sa = match a.as_ref().to_str() {
17        Some(s) => s,
18        None => {
19            return compare_os_str_fallback(a, b);
20        },
21    };
22
23    let sb = match b.as_ref().to_str() {
24        Some(s) => s,
25        None => {
26            return compare_os_str_fallback(a, b);
27        },
28    };
29
30    compare_str(sa, sb)
31}
32
33#[inline]
34fn compare_os_str_fallback<A: AsRef<OsStr>, B: AsRef<OsStr>>(a: A, b: B) -> Ordering {
35    a.as_ref().cmp(b.as_ref())
36}
37
38/// Compare two `CStr`.
39///
40/// The alphanumeric algorithm is used only when both values can be converted to UTF-8
41/// with `CStr::to_str`. If either value cannot be converted, this falls back to the
42/// native `CStr` ordering.
43#[inline]
44pub fn compare_c_str<A: AsRef<CStr>, B: AsRef<CStr>>(a: A, b: B) -> Ordering {
45    let sa = match a.as_ref().to_str() {
46        Ok(s) => s,
47        Err(_) => {
48            return compare_c_str_fallback(a, b);
49        },
50    };
51
52    let sb = match b.as_ref().to_str() {
53        Ok(s) => s,
54        Err(_) => {
55            return compare_c_str_fallback(a, b);
56        },
57    };
58
59    compare_str(sa, sb)
60}
61
62#[inline]
63fn compare_c_str_fallback<A: AsRef<CStr>, B: AsRef<CStr>>(a: A, b: B) -> Ordering {
64    a.as_ref().cmp(b.as_ref())
65}
66
67/// Compare two `Path`.
68///
69/// The alphanumeric algorithm is used only when both paths can be converted to UTF-8
70/// through their `OsStr` representations. If either path cannot be converted, this
71/// falls back to the native `OsStr` ordering.
72#[inline]
73pub fn compare_path<A: AsRef<Path>, B: AsRef<Path>>(a: A, b: B) -> Ordering {
74    compare_os_str(a.as_ref(), b.as_ref())
75}
76
77/// Sort a slice by an `OsStr` key, but may not preserve the order of equal elements.
78///
79/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
80/// If any key cannot be converted, the whole slice is sorted by native `OsStr` key
81/// ordering.
82#[inline]
83pub fn sort_slice_unstable_by_os_str_key<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
84    slice: &mut [A],
85    f: F,
86) {
87    sort_slice_by_os_str_key_inner(
88        slice,
89        f,
90        ref_index_str_pairs_to_ref_indexes_unstable,
91        sort_slice_unstable_by_os_str_key_fallback,
92    )
93}
94
95/// Sort a slice by an `OsStr` key.
96///
97/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
98/// If any key cannot be converted, the whole slice is sorted by native `OsStr` key
99/// ordering.
100#[inline]
101pub fn sort_slice_by_os_str_key<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
102    slice: &mut [A],
103    f: F,
104) {
105    sort_slice_by_os_str_key_inner(
106        slice,
107        f,
108        ref_index_str_pairs_to_ref_indexes,
109        sort_slice_by_os_str_key_fallback,
110    )
111}
112
113/// Reversely sort a slice by an `OsStr` key, but may not preserve the order of equal elements.
114///
115/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
116/// If any key cannot be converted, the whole slice is sorted by native `OsStr` key
117/// ordering.
118#[inline]
119pub fn sort_slice_rev_unstable_by_os_str_key<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
120    slice: &mut [A],
121    f: F,
122) {
123    sort_slice_by_os_str_key_inner(
124        slice,
125        f,
126        ref_index_str_pairs_to_ref_indexes_rev_unstable,
127        sort_slice_rev_unstable_by_os_str_key_fallback,
128    )
129}
130
131/// Reversely sort a slice by an `OsStr` key.
132///
133/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
134/// If any key cannot be converted, the whole slice is sorted by native `OsStr` key
135/// ordering.
136#[inline]
137pub fn sort_slice_rev_by_os_str_key<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
138    slice: &mut [A],
139    f: F,
140) {
141    sort_slice_by_os_str_key_inner(
142        slice,
143        f,
144        ref_index_str_pairs_to_ref_indexes_rev,
145        sort_slice_rev_by_os_str_key_fallback,
146    )
147}
148
149fn sort_slice_by_os_str_key_inner<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
150    slice: &mut [A],
151    mut f: F,
152    ref_index_str_pairs_to_ref_indexes: impl Fn(Vec<(usize, &str)>) -> Vec<usize>,
153    fallback: impl Fn(&mut [A], F),
154) {
155    let mut use_str = true;
156
157    let mut ref_index_str_pairs = Vec::with_capacity(slice.len());
158
159    for (i, p) in slice.iter().enumerate() {
160        let s = match f(p).as_ref().to_str() {
161            Some(s) => s,
162            None => {
163                use_str = false;
164                break;
165            },
166        };
167
168        ref_index_str_pairs.push((i, s));
169    }
170
171    if use_str {
172        let ref_indexes = ref_index_str_pairs_to_ref_indexes(ref_index_str_pairs);
173
174        sort_slice_ref_indexes(slice, ref_indexes);
175    } else {
176        fallback(slice, f);
177    }
178}
179
180#[inline]
181fn sort_slice_unstable_by_os_str_key_fallback<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
182    slice: &mut [A],
183    mut f: F,
184) {
185    slice.sort_unstable_by(|a, b| compare_os_str_fallback(f(a), f(b)));
186}
187
188#[inline]
189fn sort_slice_by_os_str_key_fallback<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
190    slice: &mut [A],
191    mut f: F,
192) {
193    slice.sort_by(|a, b| compare_os_str_fallback(f(a), f(b)));
194}
195
196#[inline]
197fn sort_slice_rev_unstable_by_os_str_key_fallback<
198    A,
199    T: ?Sized + AsRef<OsStr>,
200    F: FnMut(&A) -> &T,
201>(
202    slice: &mut [A],
203    mut f: F,
204) {
205    slice.sort_unstable_by(|a, b| compare_os_str_fallback(f(b), f(a)));
206}
207
208#[inline]
209fn sort_slice_rev_by_os_str_key_fallback<A, T: ?Sized + AsRef<OsStr>, F: FnMut(&A) -> &T>(
210    slice: &mut [A],
211    mut f: F,
212) {
213    slice.sort_by(|a, b| compare_os_str_fallback(f(b), f(a)));
214}
215
216/// Sort a slice by a `CStr` key, but may not preserve the order of equal elements.
217///
218/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
219/// If any key cannot be converted, the whole slice is sorted by native `CStr` key
220/// ordering.
221#[inline]
222pub fn sort_slice_unstable_by_c_str_key<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
223    slice: &mut [A],
224    f: F,
225) {
226    sort_slice_by_c_str_key_inner(
227        slice,
228        f,
229        ref_index_str_pairs_to_ref_indexes_unstable,
230        sort_slice_unstable_by_c_str_key_fallback,
231    )
232}
233
234/// Sort a slice by a `CStr` key.
235///
236/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
237/// If any key cannot be converted, the whole slice is sorted by native `CStr` key
238/// ordering.
239#[inline]
240pub fn sort_slice_by_c_str_key<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
241    slice: &mut [A],
242    f: F,
243) {
244    sort_slice_by_c_str_key_inner(
245        slice,
246        f,
247        ref_index_str_pairs_to_ref_indexes,
248        sort_slice_by_c_str_key_fallback,
249    )
250}
251
252/// Reversely sort a slice by a `CStr` key, but may not preserve the order of equal elements.
253///
254/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
255/// If any key cannot be converted, the whole slice is sorted by native `CStr` key
256/// ordering.
257#[inline]
258pub fn sort_slice_rev_unstable_by_c_str_key<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
259    slice: &mut [A],
260    f: F,
261) {
262    sort_slice_by_c_str_key_inner(
263        slice,
264        f,
265        ref_index_str_pairs_to_ref_indexes_rev_unstable,
266        sort_slice_rev_unstable_by_c_str_key_fallback,
267    )
268}
269
270/// Reversely sort a slice by a `CStr` key.
271///
272/// The alphanumeric algorithm is used only if every key can be converted to UTF-8.
273/// If any key cannot be converted, the whole slice is sorted by native `CStr` key
274/// ordering.
275#[inline]
276pub fn sort_slice_rev_by_c_str_key<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
277    slice: &mut [A],
278    f: F,
279) {
280    sort_slice_by_c_str_key_inner(
281        slice,
282        f,
283        ref_index_str_pairs_to_ref_indexes_rev,
284        sort_slice_rev_by_c_str_key_fallback,
285    )
286}
287
288fn sort_slice_by_c_str_key_inner<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
289    slice: &mut [A],
290    mut f: F,
291    ref_index_str_pairs_to_ref_indexes: impl Fn(Vec<(usize, &str)>) -> Vec<usize>,
292    fallback: impl Fn(&mut [A], F),
293) {
294    let mut use_str = true;
295
296    let mut ref_index_str_pairs = Vec::with_capacity(slice.len());
297
298    for (i, p) in slice.iter().enumerate() {
299        let s = match f(p).as_ref().to_str() {
300            Ok(s) => s,
301            Err(_) => {
302                use_str = false;
303                break;
304            },
305        };
306
307        ref_index_str_pairs.push((i, s));
308    }
309
310    if use_str {
311        let ref_indexes = ref_index_str_pairs_to_ref_indexes(ref_index_str_pairs);
312
313        sort_slice_ref_indexes(slice, ref_indexes);
314    } else {
315        fallback(slice, f);
316    }
317}
318
319#[inline]
320fn sort_slice_unstable_by_c_str_key_fallback<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
321    slice: &mut [A],
322    mut f: F,
323) {
324    slice.sort_unstable_by(|a, b| compare_c_str_fallback(f(a), f(b)));
325}
326
327#[inline]
328fn sort_slice_by_c_str_key_fallback<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
329    slice: &mut [A],
330    mut f: F,
331) {
332    slice.sort_by(|a, b| compare_c_str_fallback(f(a), f(b)));
333}
334
335#[inline]
336fn sort_slice_rev_unstable_by_c_str_key_fallback<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
337    slice: &mut [A],
338    mut f: F,
339) {
340    slice.sort_unstable_by(|a, b| compare_c_str_fallback(f(b), f(a)));
341}
342
343#[inline]
344fn sort_slice_rev_by_c_str_key_fallback<A, T: ?Sized + AsRef<CStr>, F: FnMut(&A) -> &T>(
345    slice: &mut [A],
346    mut f: F,
347) {
348    slice.sort_by(|a, b| compare_c_str_fallback(f(b), f(a)));
349}
350
351/// Sort a slice by a `Path` key, but may not preserve the order of equal elements.
352///
353/// The alphanumeric algorithm is used only if every key can be converted to UTF-8
354/// through its `OsStr` representation. If any key cannot be converted, the whole
355/// slice is sorted by native `OsStr` key ordering.
356#[inline]
357pub fn sort_slice_unstable_by_path_key<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
358    slice: &mut [A],
359    f: F,
360) {
361    sort_slice_by_path_key_inner(
362        slice,
363        f,
364        ref_index_str_pairs_to_ref_indexes_unstable,
365        sort_slice_unstable_by_path_key_fallback,
366    )
367}
368
369/// Sort a slice by a `Path` key.
370///
371/// The alphanumeric algorithm is used only if every key can be converted to UTF-8
372/// through its `OsStr` representation. If any key cannot be converted, the whole
373/// slice is sorted by native `OsStr` key ordering.
374#[inline]
375pub fn sort_slice_by_path_key<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
376    slice: &mut [A],
377    f: F,
378) {
379    sort_slice_by_path_key_inner(
380        slice,
381        f,
382        ref_index_str_pairs_to_ref_indexes,
383        sort_slice_by_path_key_fallback,
384    )
385}
386
387/// Reversely sort a slice by a `Path` key, but may not preserve the order of equal elements.
388///
389/// The alphanumeric algorithm is used only if every key can be converted to UTF-8
390/// through its `OsStr` representation. If any key cannot be converted, the whole
391/// slice is sorted by native `OsStr` key ordering.
392#[inline]
393pub fn sort_slice_rev_unstable_by_path_key<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
394    slice: &mut [A],
395    f: F,
396) {
397    sort_slice_by_path_key_inner(
398        slice,
399        f,
400        ref_index_str_pairs_to_ref_indexes_rev_unstable,
401        sort_slice_rev_unstable_by_path_key_fallback,
402    )
403}
404
405/// Reversely sort a slice by a `Path` key.
406///
407/// The alphanumeric algorithm is used only if every key can be converted to UTF-8
408/// through its `OsStr` representation. If any key cannot be converted, the whole
409/// slice is sorted by native `OsStr` key ordering.
410#[inline]
411pub fn sort_slice_rev_by_path_key<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
412    slice: &mut [A],
413    f: F,
414) {
415    sort_slice_by_path_key_inner(
416        slice,
417        f,
418        ref_index_str_pairs_to_ref_indexes_rev,
419        sort_slice_rev_by_path_key_fallback,
420    )
421}
422
423fn sort_slice_by_path_key_inner<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
424    slice: &mut [A],
425    mut f: F,
426    ref_index_str_pairs_to_ref_indexes: impl Fn(Vec<(usize, &str)>) -> Vec<usize>,
427    fallback: impl Fn(&mut [A], F),
428) {
429    let mut use_str = true;
430
431    let mut ref_index_str_pairs = Vec::with_capacity(slice.len());
432
433    for (i, p) in slice.iter().enumerate() {
434        let s = match f(p).as_ref().to_str() {
435            Some(s) => s,
436            None => {
437                use_str = false;
438                break;
439            },
440        };
441
442        ref_index_str_pairs.push((i, s));
443    }
444
445    if use_str {
446        let ref_indexes = ref_index_str_pairs_to_ref_indexes(ref_index_str_pairs);
447
448        sort_slice_ref_indexes(slice, ref_indexes);
449    } else {
450        fallback(slice, f);
451    }
452}
453
454#[inline]
455fn sort_slice_unstable_by_path_key_fallback<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
456    slice: &mut [A],
457    mut f: F,
458) {
459    slice.sort_unstable_by(|a, b| {
460        compare_os_str_fallback(f(a).as_ref().as_os_str(), f(b).as_ref().as_os_str())
461    });
462}
463
464#[inline]
465fn sort_slice_by_path_key_fallback<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
466    slice: &mut [A],
467    mut f: F,
468) {
469    slice.sort_by(|a, b| {
470        compare_os_str_fallback(f(a).as_ref().as_os_str(), f(b).as_ref().as_os_str())
471    });
472}
473
474#[inline]
475fn sort_slice_rev_unstable_by_path_key_fallback<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
476    slice: &mut [A],
477    mut f: F,
478) {
479    slice.sort_unstable_by(|a, b| {
480        compare_os_str_fallback(f(b).as_ref().as_os_str(), f(a).as_ref().as_os_str())
481    });
482}
483
484#[inline]
485fn sort_slice_rev_by_path_key_fallback<A, T: ?Sized + AsRef<Path>, F: FnMut(&A) -> &T>(
486    slice: &mut [A],
487    mut f: F,
488) {
489    slice.sort_by(|a, b| {
490        compare_os_str_fallback(f(b).as_ref().as_os_str(), f(a).as_ref().as_os_str())
491    });
492}
493
494// Direct std slice sorting
495
496/// Sort an `OsStr` slice.
497///
498/// The alphanumeric algorithm is used only if every item can be converted to UTF-8.
499/// If any item cannot be converted, the whole slice is sorted by native `OsStr`
500/// ordering.
501#[inline]
502pub fn sort_os_str_slice<S: AsRef<OsStr>>(slice: &mut [S]) {
503    sort_slice_unstable_by_os_str_key(slice, |e| e.as_ref())
504}
505
506/// Reversely sort an `OsStr` slice.
507///
508/// The alphanumeric algorithm is used only if every item can be converted to UTF-8.
509/// If any item cannot be converted, the whole slice is sorted by native `OsStr`
510/// ordering.
511#[inline]
512pub fn sort_os_str_slice_rev<S: AsRef<OsStr>>(slice: &mut [S]) {
513    sort_slice_rev_unstable_by_os_str_key(slice, |e| e.as_ref())
514}
515
516/// Sort a `CStr` slice.
517///
518/// The alphanumeric algorithm is used only if every item can be converted to UTF-8.
519/// If any item cannot be converted, the whole slice is sorted by native `CStr`
520/// ordering.
521#[inline]
522pub fn sort_c_str_slice<S: AsRef<CStr>>(slice: &mut [S]) {
523    sort_slice_unstable_by_c_str_key(slice, |e| e.as_ref())
524}
525
526/// Reversely sort a `CStr` slice.
527///
528/// The alphanumeric algorithm is used only if every item can be converted to UTF-8.
529/// If any item cannot be converted, the whole slice is sorted by native `CStr`
530/// ordering.
531#[inline]
532pub fn sort_c_str_slice_rev<S: AsRef<CStr>>(slice: &mut [S]) {
533    sort_slice_rev_unstable_by_c_str_key(slice, |e| e.as_ref())
534}
535
536/// Sort a `Path` slice.
537///
538/// The alphanumeric algorithm is used only if every item can be converted to UTF-8
539/// through its `OsStr` representation. If any item cannot be converted, the whole
540/// slice is sorted by native `OsStr` ordering.
541#[inline]
542pub fn sort_path_slice<P: AsRef<Path>>(slice: &mut [P]) {
543    sort_slice_unstable_by_path_key(slice, |e| e.as_ref())
544}
545
546/// Reversely sort a `Path` slice.
547///
548/// The alphanumeric algorithm is used only if every item can be converted to UTF-8
549/// through its `OsStr` representation. If any item cannot be converted, the whole
550/// slice is sorted by native `OsStr` ordering.
551#[inline]
552pub fn sort_path_slice_rev<P: AsRef<Path>>(slice: &mut [P]) {
553    sort_slice_rev_unstable_by_path_key(slice, |e| e.as_ref())
554}
555
556// Permutation helpers
557
558#[inline]
559fn ref_index_str_pairs_to_ref_indexes_unstable(
560    mut ref_index_str_pairs: Vec<(usize, &str)>,
561) -> Vec<usize> {
562    ref_index_str_pairs.sort_unstable_by(|a, b| compare_str(a.1, b.1));
563
564    ref_index_str_pairs_to_ref_indexes_inner(ref_index_str_pairs)
565}
566
567#[inline]
568fn ref_index_str_pairs_to_ref_indexes(mut ref_index_str_pairs: Vec<(usize, &str)>) -> Vec<usize> {
569    ref_index_str_pairs.sort_by(|a, b| compare_str(a.1, b.1));
570
571    ref_index_str_pairs_to_ref_indexes_inner(ref_index_str_pairs)
572}
573
574#[inline]
575fn ref_index_str_pairs_to_ref_indexes_rev_unstable(
576    mut ref_index_str_pairs: Vec<(usize, &str)>,
577) -> Vec<usize> {
578    ref_index_str_pairs.sort_unstable_by(|a, b| compare_str(b.1, a.1));
579
580    ref_index_str_pairs_to_ref_indexes_inner(ref_index_str_pairs)
581}
582
583#[inline]
584fn ref_index_str_pairs_to_ref_indexes_rev(
585    mut ref_index_str_pairs: Vec<(usize, &str)>,
586) -> Vec<usize> {
587    ref_index_str_pairs.sort_by(|a, b| compare_str(b.1, a.1));
588
589    ref_index_str_pairs_to_ref_indexes_inner(ref_index_str_pairs)
590}
591
592#[inline]
593fn ref_index_str_pairs_to_ref_indexes_inner(ref_index_str_pairs: Vec<(usize, &str)>) -> Vec<usize> {
594    ref_index_str_pairs.into_iter().map(|(i, _)| i).collect()
595}
596
597#[inline]
598fn sort_slice_ref_indexes<S>(slice: &mut [S], mut permutation: Vec<usize>) {
599    // Cycle Decomposition
600    for i in 0..permutation.len() {
601        let mut current = i;
602
603        while permutation[current] != i {
604            let next = permutation[current];
605
606            slice.swap(current, next);
607
608            permutation[current] = current;
609            current = next;
610        }
611
612        permutation[current] = current;
613    }
614}