X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/96ffb2fe97c3e77879e7a4f6f7457397a18bf233..3ea204e1031a94dafca7f7e4eed2f79ec3bd7fd0:/src/util.c diff --git a/src/util.c b/src/util.c index cc2794f6..5cffa072 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,7 @@ #include "redis.h" #include #include +#include /* Glob-style pattern matching. */ int stringmatchlen(const char *pattern, int patternLen, @@ -200,24 +201,83 @@ int ll2string(char *s, size_t len, long long value) { return l; } -/* Check if the nul-terminated string 's' can be represented by a long +/* Convert a double to a string representation. Returns the number of bytes + * required. The representation should always be parsable by stdtod(3). */ +int d2string(char *buf, size_t len, double value) { + if (isnan(value)) { + len = snprintf(buf,len,"nan"); + } else if (isinf(value)) { + if (value < 0) + len = snprintf(buf,len,"-inf"); + else + len = snprintf(buf,len,"inf"); + } else if (value == 0) { + /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */ + if (1.0/value < 0) + len = snprintf(buf,len,"-0"); + else + len = snprintf(buf,len,"0"); + } else { +#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL) + /* Check if the float is in a safe range to be casted into a + * long long. We are assuming that long long is 64 bit here. + * Also we are assuming that there are no implementations around where + * double has precision < 52 bit. + * + * Under this assumptions we test if a double is inside an interval + * where casting to long long is safe. Then using two castings we + * make sure the decimal part is zero. If all this is true we use + * integer printing function that is much faster. */ + double min = -4503599627370495; /* (2^52)-1 */ + double max = 4503599627370496; /* -(2^52) */ + if (val > min && val < max && value == ((double)((long long)value))) + len = ll2string(buf,len,(long long)value); + else +#endif + len = snprintf(buf,len,"%.17g",value); + } + + return len; +} + +/* Check if the sds string 's' can be represented by a long long * (that is, is a number that fits into long without any other space or - * character before or after the digits). + * character before or after the digits, so that converting this number + * back to a string will result in the same bytes as the original string). * - * If so, the function returns REDIS_OK and *longval is set to the value + * If so, the function returns REDIS_OK and *llongval is set to the value * of the number. Otherwise REDIS_ERR is returned */ -int isStringRepresentableAsLong(sds s, long *longval) { +int isStringRepresentableAsLongLong(sds s, long long *llongval) { char buf[32], *endptr; - long value; + long long value; int slen; - value = strtol(s, &endptr, 10); + value = strtoll(s, &endptr, 10); if (endptr[0] != '\0') return REDIS_ERR; slen = ll2string(buf,32,value); /* If the number converted back into a string is not identical * then it's not possible to encode the string as integer */ if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR; - if (longval) *longval = value; + if (llongval) *llongval = value; return REDIS_OK; } + +int isStringRepresentableAsLong(sds s, long *longval) { + long long ll; + + if (isStringRepresentableAsLongLong(s,&ll) == REDIS_ERR) return REDIS_ERR; + if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR; + *longval = (long)ll; + return REDIS_OK; +} + +int isObjectRepresentableAsLongLong(robj *o, long long *llongval) { + redisAssert(o->type == REDIS_STRING); + if (o->encoding == REDIS_ENCODING_INT) { + if (llongval) *llongval = (long) o->ptr; + return REDIS_OK; + } else { + return isStringRepresentableAsLongLong(o->ptr,llongval); + } +}