#include "redis.h"
#include <math.h>
+#include <ctype.h>
robj *createObject(int type, void *ptr) {
robj *o = zmalloc(sizeof(*o));
return o;
}
+/* Note: this function is defined into object.c since here it is where it
+ * belongs but it is actually designed to be used just for INCRBYFLOAT */
+robj *createStringObjectFromLongDouble(long double value) {
+ char buf[256];
+ int len;
+
+ /* We use 17 digits precision since with 128 bit floats that precision
+ * after rouding is able to represent most small decimal numbers in a way
+ * that is "non surprising" for the user (that is, most small decimal
+ * numbers will be represented in a way that when converted back into
+ * a string are exactly the same as what the user typed.) */
+ len = snprintf(buf,sizeof(buf),"%.17Lf", value);
+ /* Now remove trailing zeroes after the '.' */
+ if (strchr(buf,'.') != NULL) {
+ char *p = buf+len-1;
+ while(*p == '0') {
+ p--;
+ len--;
+ }
+ if (*p == '.') len--;
+ }
+ return createStringObject(buf,len);
+}
+
robj *dupStringObject(robj *o) {
redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
return createStringObject(o->ptr,sdslen(o->ptr));
}
robj *createHashObject(void) {
- /* All the Hashes start as zipmaps. Will be automatically converted
- * into hash tables if there are enough elements or big elements
- * inside. */
- unsigned char *zm = zipmapNew();
- robj *o = createObject(REDIS_HASH,zm);
- o->encoding = REDIS_ENCODING_ZIPMAP;
+ unsigned char *zl = ziplistNew();
+ robj *o = createObject(REDIS_HASH, zl);
+ o->encoding = REDIS_ENCODING_ZIPLIST;
return o;
}
case REDIS_ENCODING_HT:
dictRelease((dict*) o->ptr);
break;
- case REDIS_ENCODING_ZIPMAP:
+ case REDIS_ENCODING_ZIPLIST:
zfree(o->ptr);
break;
default:
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
+ errno = 0;
value = strtod(o->ptr, &eptr);
- if (eptr[0] != '\0' || isnan(value)) return REDIS_ERR;
+ if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
+ errno == ERANGE || isnan(value))
+ return REDIS_ERR;
} else if (o->encoding == REDIS_ENCODING_INT) {
value = (long)o->ptr;
} else {
redisPanic("Unknown string encoding");
}
}
-
*target = value;
return REDIS_OK;
}
if (msg != NULL) {
addReplyError(c,(char*)msg);
} else {
- addReplyError(c,"value is not a double");
+ addReplyError(c,"value is not a valid float");
}
return REDIS_ERR;
}
+ *target = value;
+ return REDIS_OK;
+}
+int getLongDoubleFromObject(robj *o, long double *target) {
+ long double value;
+ char *eptr;
+
+ if (o == NULL) {
+ value = 0;
+ } else {
+ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
+ if (o->encoding == REDIS_ENCODING_RAW) {
+ errno = 0;
+ value = strtold(o->ptr, &eptr);
+ if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
+ errno == ERANGE || isnan(value))
+ return REDIS_ERR;
+ } else if (o->encoding == REDIS_ENCODING_INT) {
+ value = (long)o->ptr;
+ } else {
+ redisPanic("Unknown string encoding");
+ }
+ }
+ *target = value;
+ return REDIS_OK;
+}
+
+int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg) {
+ long double value;
+ if (getLongDoubleFromObject(o, &value) != REDIS_OK) {
+ if (msg != NULL) {
+ addReplyError(c,(char*)msg);
+ } else {
+ addReplyError(c,"value is not a valid float");
+ }
+ return REDIS_ERR;
+ }
*target = value;
return REDIS_OK;
}
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
+ errno = 0;
value = strtoll(o->ptr, &eptr, 10);
- if (eptr[0] != '\0') return REDIS_ERR;
- if (errno == ERANGE && (value == LLONG_MIN || value == LLONG_MAX))
+ if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
+ errno == ERANGE)
return REDIS_ERR;
} else if (o->encoding == REDIS_ENCODING_INT) {
value = (long)o->ptr;
redisPanic("Unknown string encoding");
}
}
-
if (target) *target = value;
return REDIS_OK;
}
}
return REDIS_ERR;
}
-
*target = value;
return REDIS_OK;
}
}
return REDIS_ERR;
}
-
*target = value;
return REDIS_OK;
}
case REDIS_ENCODING_RAW: return "raw";
case REDIS_ENCODING_INT: return "int";
case REDIS_ENCODING_HT: return "hashtable";
- case REDIS_ENCODING_ZIPMAP: return "zipmap";
case REDIS_ENCODING_LINKEDLIST: return "linkedlist";
case REDIS_ENCODING_ZIPLIST: return "ziplist";
case REDIS_ENCODING_INTSET: return "intset";
dictEntry *de;
if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;
- return (robj*) dictGetEntryVal(de);
+ return (robj*) dictGetVal(de);
}
robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply) {