summaryrefslogtreecommitdiff
path: root/src/util/sort.c
blob: 8d306a8518d40cf953b0efc008453c1ddf8ca880 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <al/str.h>

static inline u32 find_number(str *s)
{
    u32 i = 0;
    while (i < s->length && !al_isnumber(al_str_at(s, i))) { i++; }
    return (i == s->length) ? AL_STR_NO_POS : i;
}

static inline u32 find_non_number(str *s)
{
    u32 i = 0;
    while (i < s->length && al_isnumber(al_str_at(s, i))) { i++; }
    return i;
}

s32 nn_numerical_compare(const void *a, const void *b)
{
    str s1 = *(str *)a, s2 = *(str *)b;
    s32 ret;
    str sub1, sub2;
    bool error;
    s64 n1, n2;
    u32 nn1 = find_number(&s1);
    u32 nn2 = find_number(&s2);
    if (nn1 != nn2) {
        goto compare_remainder;
    }
    s1 = al_str_substr(&s1, nn1, s1.length);
    s2 = al_str_substr(&s2, nn2, s2.length);
    do {
        nn1 = find_non_number(&s1);
        nn2 = find_non_number(&s2);
        sub1 = al_str_substr(&s1, 0, nn1);
        sub2 = al_str_substr(&s2, 0, nn2);
        n1 = al_str_to_long(&sub1, 10, &error);
        al_assert(!error);
        n2 = al_str_to_long(&sub2, 10, &error);
        al_assert(!error);
        if (n1 > n2) return 1;
        else if (n1 < n2) return -1;
        s1 = al_str_substr(&s1, nn1, s1.length);
        s2 = al_str_substr(&s2, nn2, s2.length);
        nn1 = find_number(&s1);
        nn2 = find_number(&s2);
        if (nn1 == AL_STR_NO_POS || nn2 == AL_STR_NO_POS) {
            goto compare_remainder;
        }
        sub1 = al_str_substr(&s1, 0, nn1);
        sub2 = al_str_substr(&s2, 0, nn2);
        if (!al_str_eq(&sub1, &sub2)) {
            goto compare_remainder;
        }
        s1 = al_str_substr(&s1, nn1, s1.length);
        s2 = al_str_substr(&s2, nn2, s2.length);
    } while (1);
compare_remainder:
    ret = al_str_cmp(&s1, &s2, 0, MIN(s1.length, s2.length));
    if (ret == 0) return s1.length - s2.length;
    return ret;
}