diff options
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/sort.c | 61 | ||||
| -rw-r--r-- | src/util/sort.h | 1 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/util/sort.c b/src/util/sort.c new file mode 100644 index 0000000..8d306a8 --- /dev/null +++ b/src/util/sort.c @@ -0,0 +1,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; +} diff --git a/src/util/sort.h b/src/util/sort.h new file mode 100644 index 0000000..6c0cfc7 --- /dev/null +++ b/src/util/sort.h @@ -0,0 +1 @@ +s32 nn_numerical_compare(const void *a, const void *b); |