mirror of
https://github.com/fluencelabs/redis
synced 2025-03-31 14:51:04 +00:00
INCRBYFLOAT implementation
This commit is contained in:
parent
64c7499eb8
commit
5574b53eae
59
src/object.c
59
src/object.c
@ -44,6 +44,21 @@ robj *createStringObjectFromLongLong(long long value) {
|
|||||||
return 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),"%.17Lg", value);
|
||||||
|
return createStringObject(buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
robj *dupStringObject(robj *o) {
|
robj *dupStringObject(robj *o) {
|
||||||
redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
|
redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
|
||||||
return createStringObject(o->ptr,sdslen(o->ptr));
|
return createStringObject(o->ptr,sdslen(o->ptr));
|
||||||
@ -350,8 +365,10 @@ int getDoubleFromObject(robj *o, double *target) {
|
|||||||
} else {
|
} else {
|
||||||
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
|
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
|
||||||
if (o->encoding == REDIS_ENCODING_RAW) {
|
if (o->encoding == REDIS_ENCODING_RAW) {
|
||||||
|
errno = 0;
|
||||||
value = strtod(o->ptr, &eptr);
|
value = strtod(o->ptr, &eptr);
|
||||||
if (eptr[0] != '\0' || isnan(value)) return REDIS_ERR;
|
if (eptr[0] != '\0' || errno == ERANGE || isnan(value))
|
||||||
|
return REDIS_ERR;
|
||||||
} else if (o->encoding == REDIS_ENCODING_INT) {
|
} else if (o->encoding == REDIS_ENCODING_INT) {
|
||||||
value = (long)o->ptr;
|
value = (long)o->ptr;
|
||||||
} else {
|
} else {
|
||||||
@ -369,7 +386,45 @@ int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const ch
|
|||||||
if (msg != NULL) {
|
if (msg != NULL) {
|
||||||
addReplyError(c,(char*)msg);
|
addReplyError(c,(char*)msg);
|
||||||
} else {
|
} 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 (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;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,7 @@ struct redisCommand redisCommandTable[] = {
|
|||||||
{"hexists",hexistsCommand,3,"r",0,NULL,1,1,1,0,0},
|
{"hexists",hexistsCommand,3,"r",0,NULL,1,1,1,0,0},
|
||||||
{"incrby",incrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
|
{"incrby",incrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
|
||||||
{"decrby",decrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
|
{"decrby",decrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
|
||||||
|
{"incrbyfloat",incrbyfloatCommand,3,"wm",0,NULL,1,1,1,0,0},
|
||||||
{"getset",getsetCommand,3,"wm",0,NULL,1,1,1,0,0},
|
{"getset",getsetCommand,3,"wm",0,NULL,1,1,1,0,0},
|
||||||
{"mset",msetCommand,-3,"wm",0,NULL,1,-1,2,0,0},
|
{"mset",msetCommand,-3,"wm",0,NULL,1,-1,2,0,0},
|
||||||
{"msetnx",msetnxCommand,-3,"wm",0,NULL,1,-1,2,0,0},
|
{"msetnx",msetnxCommand,-3,"wm",0,NULL,1,-1,2,0,0},
|
||||||
|
@ -811,6 +811,7 @@ robj *tryObjectEncoding(robj *o);
|
|||||||
robj *getDecodedObject(robj *o);
|
robj *getDecodedObject(robj *o);
|
||||||
size_t stringObjectLen(robj *o);
|
size_t stringObjectLen(robj *o);
|
||||||
robj *createStringObjectFromLongLong(long long value);
|
robj *createStringObjectFromLongLong(long long value);
|
||||||
|
robj *createStringObjectFromLongDouble(long double value);
|
||||||
robj *createListObject(void);
|
robj *createListObject(void);
|
||||||
robj *createZiplistObject(void);
|
robj *createZiplistObject(void);
|
||||||
robj *createSetObject(void);
|
robj *createSetObject(void);
|
||||||
@ -823,6 +824,8 @@ int checkType(redisClient *c, robj *o, int type);
|
|||||||
int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg);
|
int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg);
|
||||||
int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg);
|
int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg);
|
||||||
int getLongLongFromObject(robj *o, long long *target);
|
int getLongLongFromObject(robj *o, long long *target);
|
||||||
|
int getLongDoubleFromObject(robj *o, long double *target);
|
||||||
|
int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg);
|
||||||
char *strEncoding(int encoding);
|
char *strEncoding(int encoding);
|
||||||
int compareStringObjects(robj *a, robj *b);
|
int compareStringObjects(robj *a, robj *b);
|
||||||
int equalStringObjects(robj *a, robj *b);
|
int equalStringObjects(robj *a, robj *b);
|
||||||
@ -1004,6 +1007,7 @@ void incrCommand(redisClient *c);
|
|||||||
void decrCommand(redisClient *c);
|
void decrCommand(redisClient *c);
|
||||||
void incrbyCommand(redisClient *c);
|
void incrbyCommand(redisClient *c);
|
||||||
void decrbyCommand(redisClient *c);
|
void decrbyCommand(redisClient *c);
|
||||||
|
void incrbyfloatCommand(redisClient *c);
|
||||||
void selectCommand(redisClient *c);
|
void selectCommand(redisClient *c);
|
||||||
void randomkeyCommand(redisClient *c);
|
void randomkeyCommand(redisClient *c);
|
||||||
void keysCommand(redisClient *c);
|
void keysCommand(redisClient *c);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "redis.h"
|
#include "redis.h"
|
||||||
|
#include <math.h> /* isnan(), isinf() */
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* String Commands
|
* String Commands
|
||||||
@ -382,6 +383,31 @@ void decrbyCommand(redisClient *c) {
|
|||||||
incrDecrCommand(c,-incr);
|
incrDecrCommand(c,-incr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void incrbyfloatCommand(redisClient *c) {
|
||||||
|
long double incr, value;
|
||||||
|
robj *o, *new;
|
||||||
|
|
||||||
|
o = lookupKeyWrite(c->db,c->argv[1]);
|
||||||
|
if (o != NULL && checkType(c,o,REDIS_STRING)) return;
|
||||||
|
if (getLongDoubleFromObjectOrReply(c,o,&value,NULL) != REDIS_OK ||
|
||||||
|
getLongDoubleFromObjectOrReply(c,c->argv[2],&incr,NULL) != REDIS_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
value += incr;
|
||||||
|
if (isnan(value) || isinf(value)) {
|
||||||
|
addReplyError(c,"increment would produce NaN or Infinity");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new = createStringObjectFromLongDouble(value);
|
||||||
|
if (o)
|
||||||
|
dbOverwrite(c->db,c->argv[1],new);
|
||||||
|
else
|
||||||
|
dbAdd(c->db,c->argv[1],new);
|
||||||
|
signalModifiedKey(c->db,c->argv[1]);
|
||||||
|
server.dirty++;
|
||||||
|
addReplyBulk(c,new);
|
||||||
|
}
|
||||||
|
|
||||||
void appendCommand(redisClient *c) {
|
void appendCommand(redisClient *c) {
|
||||||
size_t totlen;
|
size_t totlen;
|
||||||
robj *o, *append;
|
robj *o, *append;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user