From 195aca34274bd633f6ecfca2e9a4e76ae669ae0e Mon Sep 17 00:00:00 2001 From: Matt Stancliff Date: Tue, 20 Jan 2015 10:58:35 -0500 Subject: Improve digit counting for multibulk creation This replaces the old intlen() implementation with a slightly faster way of counting digits. Implementation taken from the same place where digits10() in redis/src/util.c came from. The old 'intlen' allowed negative inputs, but no usage in hiredis was passing negative numbers, so that ability is removed. Also, the new implementation can count higher (uint64_t) instead of limited to just int as before. Fixes #295 by replacing implementation --- hiredis.c | 32 ++++++++++++++++---------------- hiredis.h | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/hiredis.c b/hiredis.c index 0297361..d2b6103 100644 --- a/hiredis.c +++ b/hiredis.c @@ -186,23 +186,23 @@ static void *createNilObject(const redisReadTask *task) { return r; } -/* Calculate the number of bytes needed to represent an integer as string. */ -static int intlen(int i) { - int len = 0; - if (i < 0) { - len++; - i = -i; - } - do { - len++; - i /= 10; - } while(i); - return len; +/* Return the number of digits of 'v' when converted to string in radix 10. + * Implementation borrowed from link in redis/src/util.c:string2ll(). */ +static uint32_t countDigits(uint64_t v) { + uint32_t result = 1; + for (;;) { + if (v < 10) return result; + if (v < 100) return result + 1; + if (v < 1000) return result + 2; + if (v < 10000) return result + 3; + v /= 10000U; + result += 4; + } } /* Helper that calculates the bulk length given a certain string length. */ static size_t bulklen(size_t len) { - return 1+intlen(len)+2+len+2; + return 1+countDigits(len)+2+len+2; } int redisvFormatCommand(char **target, const char *format, va_list ap) { @@ -392,7 +392,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { curarg = NULL; /* Add bytes needed to hold multi bulk count */ - totlen += 1+intlen(argc)+2; + totlen += 1+countDigits(argc)+2; /* Build the command at protocol level */ cmd = malloc(totlen+1); @@ -485,7 +485,7 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, return -1; /* Calculate our total size */ - totlen = 1+intlen(argc)+2; + totlen = 1+countDigits(argc)+2; for (j = 0; j < argc; j++) { len = argvlen ? argvlen[j] : strlen(argv[j]); totlen += bulklen(len); @@ -536,7 +536,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz return -1; /* Calculate number of bytes needed for the command */ - totlen = 1+intlen(argc)+2; + totlen = 1+countDigits(argc)+2; for (j = 0; j < argc; j++) { len = argvlen ? argvlen[j] : strlen(argv[j]); totlen += bulklen(len); diff --git a/hiredis.h b/hiredis.h index 0a603fd..e15a837 100644 --- a/hiredis.h +++ b/hiredis.h @@ -34,6 +34,7 @@ #include "read.h" #include /* for va_list */ #include /* for struct timeval */ +#include /* uintXX_t, etc */ #include "sds.h" /* for sds */ #define HIREDIS_MAJOR 0 -- cgit v1.2.3