]> granicus.if.org Git - json-c/commitdiff
json_tokener: optimize parsing of integer values
authorRamiro Polla <ramiro.polla@gmail.com>
Sat, 8 Dec 2018 18:28:46 +0000 (19:28 +0100)
committerRamiro Polla <ramiro.polla@gmail.com>
Thu, 20 Dec 2018 23:30:21 +0000 (00:30 +0100)
speedup for 32-bit: ~8%
speedup for 64-bit: ~9%

json_tokener.c
json_util.c
json_util.h

index b5fb21043910b0a50e5c3ac3a4e0bbe72a2fd465..6fc4937f97b54478b81a2984bffeea6b1512694b 100644 (file)
@@ -824,7 +824,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
       {
        int64_t num64;
        double  numd;
-       if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
+       if (!tok->is_double && json_parse_sanitized_int64(tok->pb->buf, tok->pb->bpos, &num64) == 0) {
                if (num64 && tok->pb->buf[0]=='0' &&
                    (tok->flags & JSON_TOKENER_STRICT)) {
                        /* in strict mode, number must not start with 0 */
index ad7704a945881f420e58ec8a7dbf425f34850da3..d36ef6f83e32b0946a245aa9207e233c990b8c37 100644 (file)
 #endif /* HAVE_UNISTD_H */
 
 #ifdef WIN32
-# if MSC_VER < 1800
-/* strtoll is available only since Visual Studio 2013 */
-#  define strtoll _strtoi64
-# endif
 # define WIN32_LEAN_AND_MEAN
 # include <windows.h>
 # include <io.h>
@@ -195,16 +191,48 @@ int json_parse_double(const char *buf, double *retval)
   return end == buf ? 1 : 0;
 }
 
+// The input buffer 'buf' must contain only digits (0 to 9), except
+// for the first character, which may be a negative sign '-'.
+int json_parse_sanitized_int64(const char *buf, size_t len, int64_t *retval)
+{
+       uint64_t uval = 0;
+       int is_negative = (*buf == '-');
+       size_t ii = is_negative ? 1 : 0;
+
+       if (ii == len || buf[ii] == '\0')
+               return 1;
+
+       while (ii < len)
+       {
+               uint64_t tmp = (uval * 10) + buf[ii++] - '0';
+               // Check for overflow.
+               if ((int64_t) uval > (int64_t) tmp)
+               {
+                       *retval = is_negative ? INT64_MIN : INT64_MAX;
+                       return 0;
+               }
+               uval = tmp;
+       }
+
+       *retval = is_negative ? -uval : uval;
+
+       return 0;
+}
+
 int json_parse_int64(const char *buf, int64_t *retval)
 {
-       char *end = NULL;
-       int64_t val;
-
-       errno = 0;
-       val = strtoll(buf, &end, 10);
-       if (end != buf)
-               *retval = val;
-       return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0;
+       size_t len = 0;
+       // Skip leading white spaces.
+       while (isspace(*buf))
+               buf++;
+       // Calculate length of valid input.
+       if (buf[len] == '-')
+               len++;
+       while (buf[len] >= '0' && buf[len] <= '9')
+               len++;
+       if (len == 0)
+               return 1;
+       return json_parse_sanitized_int64(buf, len, retval);
 }
 
 #ifndef HAVE_REALLOC
index 3e1b29478bd875b1d5475c25bd21aa3fc72ef6a1..bd7f970d5bf8da2cfb20c06ed29b9b697622603d 100644 (file)
@@ -90,6 +90,7 @@ extern int json_object_to_fd(int fd, struct json_object *obj, int flags);
 const char *json_util_get_last_err(void);
 
 
+extern int json_parse_sanitized_int64(const char *buf, size_t len, int64_t *retval);
 extern int json_parse_int64(const char *buf, int64_t *retval);
 extern int json_parse_double(const char *buf, double *retval);