summaryrefslogtreecommitdiff
path: root/lib/strtoul.c
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2019-02-25 23:28:36 +0100
committerMaria Matejka <mq@ucw.cz>2019-02-25 23:28:36 +0100
commit2915e711f77d68dff756babd19af8da1677c4549 (patch)
tree3fb2f8b5decbc9db40c5b9b00847dc49c0703f21 /lib/strtoul.c
parent99911873a196975f5221aad89ae5eac42e1330e0 (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.c61
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;
+}