diff options
author | Maria Matejka <mq@ucw.cz> | 2019-02-25 23:28:36 +0100 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2019-02-25 23:28:36 +0100 |
commit | 2915e711f77d68dff756babd19af8da1677c4549 (patch) | |
tree | 3fb2f8b5decbc9db40c5b9b00847dc49c0703f21 /lib/strtoul.c | |
parent | 99911873a196975f5221aad89ae5eac42e1330e0 (diff) |
Custom number parser to speed up config parsing
The glibc's generic parser is slow due to its versatility. Specialized
parsers for base-10 and base-16 are much faster and we don't use other
bases.
Diffstat (limited to 'lib/strtoul.c')
-rw-r--r-- | lib/strtoul.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/strtoul.c b/lib/strtoul.c new file mode 100644 index 00000000..44a1bb1d --- /dev/null +++ b/lib/strtoul.c @@ -0,0 +1,61 @@ +/* + * BIRD Library -- Parse numbers + * + * (c) 2019 Maria Matejka <mq@jmq.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "lib/string.h" + +#include <errno.h> + +#define ULI_MAX_DIV10 (UINT64_MAX / 10) +#define ULI_MAX_MOD10 (UINT64_MAX % 10) + +u64 +bstrtoul10(const char *str, char **end) +{ + u64 out = 0; + for (*end = (char *) str; (**end >= '0') && (**end <= '9'); (*end)++) { + u64 digit = **end - '0'; + if ((out > ULI_MAX_DIV10) || + (out == ULI_MAX_DIV10) && (digit > ULI_MAX_MOD10)) { + errno = ERANGE; + return UINT64_MAX; + } + + out *= 10; + out += (**end) - '0'; + } + return out; +} + +u64 +bstrtoul16(const char *str, char **end) +{ + u64 out = 0; + for (int i=0; i<=(64/4); i++) { + switch (str[i]) { + case '0' ... '9': + out *= 16; + out += str[i] - '0'; + break; + case 'a' ... 'f': + out *= 16; + out += str[i] + 10 - 'a'; + break; + case 'A' ... 'F': + out *= 16; + out += str[i] + 10 - 'A'; + break; + default: + *end = (char *) &(str[i]); + return out; + } + } + + errno = ERANGE; + return UINT64_MAX; +} |