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.
This commit is contained in:
parent
99911873a1
commit
2915e711f7
5 changed files with 74 additions and 9 deletions
|
@ -168,7 +168,7 @@ WHITE [ \t]
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(yytext, &e, 10);
|
l = bstrtoul(yytext, &e, 10);
|
||||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
|
if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
|
||||||
cf_error("ASN out of range");
|
cf_error("ASN out of range");
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ WHITE [ \t]
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(e+1, &e, 10);
|
l = bstrtoul(e+1, &e, 10);
|
||||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||||
cf_error("Number out of range");
|
cf_error("Number out of range");
|
||||||
cf_lval.i64 |= l;
|
cf_lval.i64 |= l;
|
||||||
|
@ -213,13 +213,13 @@ WHITE [ \t]
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(yytext+2, &e, 10);
|
l = bstrtoul(yytext+2, &e, 10);
|
||||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
|
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
|
||||||
cf_error("ASN out of range");
|
cf_error("ASN out of range");
|
||||||
cf_lval.i64 |= ((u64) l) << len2;
|
cf_lval.i64 |= ((u64) l) << len2;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(e+1, &e, 10);
|
l = bstrtoul(e+1, &e, 10);
|
||||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||||
cf_error("Number out of range");
|
cf_error("Number out of range");
|
||||||
cf_lval.i64 |= l;
|
cf_lval.i64 |= l;
|
||||||
|
@ -241,7 +241,7 @@ WHITE [ \t]
|
||||||
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
|
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(e, &e, 10);
|
l = bstrtoul(e, &e, 10);
|
||||||
if (e && *e || (errno == ERANGE) || (l >> 16))
|
if (e && *e || (errno == ERANGE) || (l >> 16))
|
||||||
cf_error("Number out of range");
|
cf_error("Number out of range");
|
||||||
cf_lval.i64 |= l;
|
cf_lval.i64 |= l;
|
||||||
|
@ -265,7 +265,7 @@ WHITE [ \t]
|
||||||
char *e;
|
char *e;
|
||||||
unsigned long int l;
|
unsigned long int l;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(yytext+2, &e, 16);
|
l = bstrtoul(yytext+2, &e, 16);
|
||||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||||
cf_error("Number out of range");
|
cf_error("Number out of range");
|
||||||
cf_lval.i = l;
|
cf_lval.i = l;
|
||||||
|
@ -276,7 +276,7 @@ WHITE [ \t]
|
||||||
char *e;
|
char *e;
|
||||||
unsigned long int l;
|
unsigned long int l;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
l = strtoul(yytext, &e, 10);
|
l = bstrtoul(yytext, &e, 10);
|
||||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||||
cf_error("Number out of range");
|
cf_error("Number out of range");
|
||||||
cf_lval.i = l;
|
cf_lval.i = l;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c timer.c xmalloc.c
|
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
|
|
||||||
|
|
2
lib/ip.c
2
lib/ip.c
|
@ -245,7 +245,7 @@ ip4_pton(const char *a, ip4_addr *o)
|
||||||
char *d, *c = strchr(a, '.');
|
char *d, *c = strchr(a, '.');
|
||||||
if (!c != !i)
|
if (!c != !i)
|
||||||
return 0;
|
return 0;
|
||||||
l = strtoul(a, &d, 10);
|
l = bstrtoul(a, &d, 10);
|
||||||
if (((d != c) && *d) || (l > 255))
|
if (((d != c) && *d) || (l > 255))
|
||||||
return 0;
|
return 0;
|
||||||
ia = (ia << 8) | l;
|
ia = (ia << 8) | l;
|
||||||
|
|
|
@ -24,6 +24,10 @@ int buffer_vprint(buffer *buf, const char *fmt, va_list args);
|
||||||
int buffer_print(buffer *buf, const char *fmt, ...);
|
int buffer_print(buffer *buf, const char *fmt, ...);
|
||||||
void buffer_puts(buffer *buf, const char *str);
|
void buffer_puts(buffer *buf, const char *str);
|
||||||
|
|
||||||
|
#define bstrtoul(str, end, base) bstrtoul##base(str, end)
|
||||||
|
u64 bstrtoul10(const char *str, char **end);
|
||||||
|
u64 bstrtoul16(const char *str, char **end);
|
||||||
|
|
||||||
int patmatch(const byte *pat, const byte *str);
|
int patmatch(const byte *pat, const byte *str);
|
||||||
|
|
||||||
static inline char *xbasename(const char *str)
|
static inline char *xbasename(const char *str)
|
||||||
|
|
61
lib/strtoul.c
Normal file
61
lib/strtoul.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue