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
This commit is contained in:
Matt Stancliff 2015-01-20 10:58:35 -05:00
parent 802456def1
commit 195aca3427
2 changed files with 17 additions and 16 deletions

View File

@ -186,23 +186,23 @@ static void *createNilObject(const redisReadTask *task) {
return r; return r;
} }
/* Calculate the number of bytes needed to represent an integer as string. */ /* Return the number of digits of 'v' when converted to string in radix 10.
static int intlen(int i) { * Implementation borrowed from link in redis/src/util.c:string2ll(). */
int len = 0; static uint32_t countDigits(uint64_t v) {
if (i < 0) { uint32_t result = 1;
len++; for (;;) {
i = -i; if (v < 10) return result;
} if (v < 100) return result + 1;
do { if (v < 1000) return result + 2;
len++; if (v < 10000) return result + 3;
i /= 10; v /= 10000U;
} while(i); result += 4;
return len; }
} }
/* Helper that calculates the bulk length given a certain string length. */ /* Helper that calculates the bulk length given a certain string length. */
static size_t bulklen(size_t len) { 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) { 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; curarg = NULL;
/* Add bytes needed to hold multi bulk count */ /* Add bytes needed to hold multi bulk count */
totlen += 1+intlen(argc)+2; totlen += 1+countDigits(argc)+2;
/* Build the command at protocol level */ /* Build the command at protocol level */
cmd = malloc(totlen+1); cmd = malloc(totlen+1);
@ -485,7 +485,7 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
return -1; return -1;
/* Calculate our total size */ /* Calculate our total size */
totlen = 1+intlen(argc)+2; totlen = 1+countDigits(argc)+2;
for (j = 0; j < argc; j++) { for (j = 0; j < argc; j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]); len = argvlen ? argvlen[j] : strlen(argv[j]);
totlen += bulklen(len); totlen += bulklen(len);
@ -536,7 +536,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
return -1; return -1;
/* Calculate number of bytes needed for the command */ /* Calculate number of bytes needed for the command */
totlen = 1+intlen(argc)+2; totlen = 1+countDigits(argc)+2;
for (j = 0; j < argc; j++) { for (j = 0; j < argc; j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]); len = argvlen ? argvlen[j] : strlen(argv[j]);
totlen += bulklen(len); totlen += bulklen(len);

View File

@ -34,6 +34,7 @@
#include "read.h" #include "read.h"
#include <stdarg.h> /* for va_list */ #include <stdarg.h> /* for va_list */
#include <sys/time.h> /* for struct timeval */ #include <sys/time.h> /* for struct timeval */
#include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for sds */ #include "sds.h" /* for sds */
#define HIREDIS_MAJOR 0 #define HIREDIS_MAJOR 0