13
0

Add a numerically_less compare operator

This is similar to sort(1) --human-numeric-sort,
as opposed to naturally_less() negative numbers, hex-prefixes
and SI metric prefixes are taken into account.
This commit is contained in:
Robin Gareus 2019-12-29 19:47:48 +01:00
parent ed67f465fb
commit 04a409df6f
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -24,6 +24,91 @@
namespace PBD {
inline bool
is_integer (const char* i)
{
return isdigit (*i) || (*i == '-' && isdigit (i[1]));
}
/* return scale factor for SI metric prefix x 1000
* (to allow milli for integers)
*/
inline int64_t
order_of_magnitude (const char* i)
{
if (!is_integer (i)) {
return 0;
}
while (isdigit (*++i)) ;
if (!*i) {
return 1e3;
}
switch (*i) {
case 'm':
return 1;
case 'c':
return 10;
case 'd':
return 100;
case 'k':
/* fallthrough */
case 'K':
return 1e6;
case 'M':
return 1e9;
case 'G':
return 1e12;
case 'T':
return 1e15;
}
return 1e3;
}
/* this method sorts negative integers before
* positive ones, and also handles hexadecimal
* numbers when prefixed with "0x" or "0X".
* SI metric prefixes for integers are handled.
* (floating point, and rational numbers are
* not directy handled)
*/
inline bool
numerically_less (const char* a, const char* b)
{
const char* d_a = NULL;
const char* d_b = NULL;
for (;*a && *b; ++a, ++b) {
if (is_integer (a) && is_integer (b) && !d_a) {
d_a = a; d_b = b;
continue;
}
if (d_a) {
const int64_t ia = strtoll (d_a, NULL, 0) * order_of_magnitude (d_a);
const int64_t ib = strtoll (d_b, NULL, 0) * order_of_magnitude (d_b);
if (ia != ib) {
return ia < ib;
}
}
d_a = d_b = NULL;
if (*a == *b) {
continue;
}
return *a < *b;
}
if (d_a) {
return strtoll (d_a, NULL, 0) * order_of_magnitude (d_a) < strtoll (d_b, NULL, 0) * order_of_magnitude (d_b);
}
/* if we reach here, either strings are same length and equal
* or one is longer than the other.
*/
if (*a) { return false; }
if (*b) { return true; }
return false; // equal
}
inline bool
naturally_less (const char* a, const char* b)
{
@ -45,7 +130,7 @@ naturally_less (const char* a, const char* b)
d_a = d_b = NULL;
if (*a == *b) {
continue;
}
}
return *a < *b;
}