Tests for string2ll; move isObject* to object.c
This commit is contained in:
parent
af0e51f2e1
commit
5d08193126
@ -125,8 +125,7 @@ t_string.o: t_string.c redis.h fmacros.h config.h ae.h sds.h dict.h \
|
|||||||
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
||||||
t_zset.o: t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
|
t_zset.o: t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
|
||||||
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
||||||
util.o: util.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
|
util.o: util.c util.h
|
||||||
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
|
||||||
cluster.o: redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
|
cluster.o: redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
|
||||||
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h
|
||||||
ziplist.o: ziplist.c zmalloc.h ziplist.h
|
ziplist.o: ziplist.c zmalloc.h ziplist.h
|
||||||
|
12
src/object.c
12
src/object.c
@ -202,6 +202,16 @@ int checkType(redisClient *c, robj *o, int type) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
|
||||||
|
redisAssert(o->type == REDIS_STRING);
|
||||||
|
if (o->encoding == REDIS_ENCODING_INT) {
|
||||||
|
if (llval) *llval = (long) o->ptr;
|
||||||
|
return REDIS_OK;
|
||||||
|
} else {
|
||||||
|
return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to encode a string object in order to save space */
|
/* Try to encode a string object in order to save space */
|
||||||
robj *tryObjectEncoding(robj *o) {
|
robj *tryObjectEncoding(robj *o) {
|
||||||
long value;
|
long value;
|
||||||
@ -219,7 +229,7 @@ robj *tryObjectEncoding(robj *o) {
|
|||||||
redisAssert(o->type == REDIS_STRING);
|
redisAssert(o->type == REDIS_STRING);
|
||||||
|
|
||||||
/* Check if we can represent this string as a long integer */
|
/* Check if we can represent this string as a long integer */
|
||||||
if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o;
|
if (!string2l(s,sdslen(s),&value)) return o;
|
||||||
|
|
||||||
/* Ok, this object can be encoded...
|
/* Ok, this object can be encoded...
|
||||||
*
|
*
|
||||||
|
14
src/redis.h
14
src/redis.h
@ -30,6 +30,7 @@
|
|||||||
#include "ziplist.h" /* Compact list data structure */
|
#include "ziplist.h" /* Compact list data structure */
|
||||||
#include "intset.h" /* Compact integer set structure */
|
#include "intset.h" /* Compact integer set structure */
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
#define REDIS_OK 0
|
#define REDIS_OK 0
|
||||||
@ -852,6 +853,7 @@ void freeHashObject(robj *o);
|
|||||||
robj *createObject(int type, void *ptr);
|
robj *createObject(int type, void *ptr);
|
||||||
robj *createStringObject(char *ptr, size_t len);
|
robj *createStringObject(char *ptr, size_t len);
|
||||||
robj *dupStringObject(robj *o);
|
robj *dupStringObject(robj *o);
|
||||||
|
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
|
||||||
robj *tryObjectEncoding(robj *o);
|
robj *tryObjectEncoding(robj *o);
|
||||||
robj *getDecodedObject(robj *o);
|
robj *getDecodedObject(robj *o);
|
||||||
size_t stringObjectLen(robj *o);
|
size_t stringObjectLen(robj *o);
|
||||||
@ -1028,18 +1030,6 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify);
|
|||||||
void freePubsubPattern(void *p);
|
void freePubsubPattern(void *p);
|
||||||
int listMatchPubsubPattern(void *a, void *b);
|
int listMatchPubsubPattern(void *a, void *b);
|
||||||
|
|
||||||
/* Utility functions */
|
|
||||||
int stringmatchlen(const char *pattern, int patternLen,
|
|
||||||
const char *string, int stringLen, int nocase);
|
|
||||||
int stringmatch(const char *pattern, const char *string, int nocase);
|
|
||||||
long long memtoll(const char *p, int *err);
|
|
||||||
int ll2string(char *s, size_t len, long long value);
|
|
||||||
int string2ll(char *s, size_t len, long long *value);
|
|
||||||
int d2string(char *s, size_t len, double value);
|
|
||||||
int isStringRepresentableAsLong(sds s, long *longval);
|
|
||||||
int isStringRepresentableAsLongLong(sds s, long long *longval);
|
|
||||||
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
|
|
||||||
|
|
||||||
/* Configuration */
|
/* Configuration */
|
||||||
void loadServerConfig(char *filename);
|
void loadServerConfig(char *filename);
|
||||||
void appendServerSaveParams(time_t seconds, int changes);
|
void appendServerSaveParams(time_t seconds, int changes);
|
||||||
|
159
src/util.c
159
src/util.c
@ -1,7 +1,10 @@
|
|||||||
#include "redis.h"
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
/* Glob-style pattern matching. */
|
/* Glob-style pattern matching. */
|
||||||
int stringmatchlen(const char *pattern, int patternLen,
|
int stringmatchlen(const char *pattern, int patternLen,
|
||||||
@ -213,6 +216,12 @@ int string2ll(char *s, size_t slen, long long *value) {
|
|||||||
if (plen == slen)
|
if (plen == slen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Special case: first and only digit is 0. */
|
||||||
|
if (slen == 1 && p[0] == '0') {
|
||||||
|
if (value != NULL) *value = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (p[0] == '-') {
|
if (p[0] == '-') {
|
||||||
negative = 1;
|
negative = 1;
|
||||||
p++; plen++;
|
p++; plen++;
|
||||||
@ -250,7 +259,7 @@ int string2ll(char *s, size_t slen, long long *value) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (negative) {
|
if (negative) {
|
||||||
if (v > (-(unsigned long long)LLONG_MIN)) /* Overflow. */
|
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
|
||||||
return 0;
|
return 0;
|
||||||
if (value != NULL) *value = -v;
|
if (value != NULL) *value = -v;
|
||||||
} else {
|
} else {
|
||||||
@ -261,6 +270,22 @@ int string2ll(char *s, size_t slen, long long *value) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert a string into a long. Returns 1 if the string could be parsed into a
|
||||||
|
* (non-overflowing) long, 0 otherwise. The value will be set to the parsed
|
||||||
|
* value when appropriate. */
|
||||||
|
int string2l(char *s, size_t slen, long *lval) {
|
||||||
|
long long llval;
|
||||||
|
|
||||||
|
if (!string2ll(s,slen,&llval))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (llval < LONG_MIN || llval > LONG_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*lval = (long)llval;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert a double to a string representation. Returns the number of bytes
|
/* Convert a double to a string representation. Returns the number of bytes
|
||||||
* required. The representation should always be parsable by stdtod(3). */
|
* required. The representation should always be parsable by stdtod(3). */
|
||||||
int d2string(char *buf, size_t len, double value) {
|
int d2string(char *buf, size_t len, double value) {
|
||||||
@ -300,44 +325,108 @@ int d2string(char *buf, size_t len, double value) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the sds string 's' can be represented by a long long
|
#ifdef UTIL_TEST_MAIN
|
||||||
* (that is, is a number that fits into long without any other space or
|
#include <assert.h>
|
||||||
* 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 *llongval is set to the value
|
|
||||||
* of the number. Otherwise REDIS_ERR is returned */
|
|
||||||
int isStringRepresentableAsLongLong(sds s, long long *llongval) {
|
|
||||||
char buf[32], *endptr;
|
|
||||||
long long value;
|
|
||||||
int slen;
|
|
||||||
|
|
||||||
value = strtoll(s, &endptr, 10);
|
void test_string2ll(void) {
|
||||||
if (endptr[0] != '\0') return REDIS_ERR;
|
char buf[32];
|
||||||
slen = ll2string(buf,32,value);
|
long long v;
|
||||||
|
|
||||||
/* If the number converted back into a string is not identical
|
/* May not start with +. */
|
||||||
* then it's not possible to encode the string as integer */
|
strcpy(buf,"+1");
|
||||||
if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
|
assert(string2ll(buf,strlen(buf),&v) == 0);
|
||||||
if (llongval) *llongval = value;
|
|
||||||
return REDIS_OK;
|
/* May not start with 0. */
|
||||||
|
strcpy(buf,"01");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"-1");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == -1);
|
||||||
|
|
||||||
|
strcpy(buf,"0");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"1");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 1);
|
||||||
|
|
||||||
|
strcpy(buf,"99");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 99);
|
||||||
|
|
||||||
|
strcpy(buf,"-99");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == -99);
|
||||||
|
|
||||||
|
strcpy(buf,"-9223372036854775808");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == LLONG_MIN);
|
||||||
|
|
||||||
|
strcpy(buf,"-9223372036854775809"); /* overflow */
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"9223372036854775807");
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == LLONG_MAX);
|
||||||
|
|
||||||
|
strcpy(buf,"9223372036854775808"); /* overflow */
|
||||||
|
assert(string2ll(buf,strlen(buf),&v) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int isStringRepresentableAsLong(sds s, long *longval) {
|
void test_string2l(void) {
|
||||||
long long ll;
|
char buf[32];
|
||||||
|
long v;
|
||||||
|
|
||||||
if (isStringRepresentableAsLongLong(s,&ll) == REDIS_ERR) return REDIS_ERR;
|
/* May not start with +. */
|
||||||
if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR;
|
strcpy(buf,"+1");
|
||||||
*longval = (long)ll;
|
assert(string2l(buf,strlen(buf),&v) == 0);
|
||||||
return REDIS_OK;
|
|
||||||
|
/* May not start with 0. */
|
||||||
|
strcpy(buf,"01");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"-1");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == -1);
|
||||||
|
|
||||||
|
strcpy(buf,"0");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"1");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 1);
|
||||||
|
|
||||||
|
strcpy(buf,"99");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == 99);
|
||||||
|
|
||||||
|
strcpy(buf,"-99");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == -99);
|
||||||
|
|
||||||
|
#if LONG_MAX != LLONG_MAX
|
||||||
|
strcpy(buf,"-2147483648");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == LONG_MIN);
|
||||||
|
|
||||||
|
strcpy(buf,"-2147483649"); /* overflow */
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 0);
|
||||||
|
|
||||||
|
strcpy(buf,"2147483647");
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 1);
|
||||||
|
assert(v == LONG_MAX);
|
||||||
|
|
||||||
|
strcpy(buf,"2147483648"); /* overflow */
|
||||||
|
assert(string2l(buf,strlen(buf),&v) == 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int isObjectRepresentableAsLongLong(robj *o, long long *llongval) {
|
int main(int argc, char **argv) {
|
||||||
redisAssert(o->type == REDIS_STRING);
|
test_string2ll();
|
||||||
if (o->encoding == REDIS_ENCODING_INT) {
|
test_string2l();
|
||||||
if (llongval) *llongval = (long) o->ptr;
|
return 0;
|
||||||
return REDIS_OK;
|
|
||||||
} else {
|
|
||||||
return isStringRepresentableAsLongLong(o->ptr,llongval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
12
src/util.h
Normal file
12
src/util.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __REDIS_UTIL_H
|
||||||
|
#define __REDIS_UTIL_H
|
||||||
|
|
||||||
|
int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase);
|
||||||
|
int stringmatch(const char *p, const char *s, int nocase);
|
||||||
|
long long memtoll(const char *p, int *err);
|
||||||
|
int ll2string(char *s, size_t len, long long value);
|
||||||
|
int string2ll(char *s, size_t slen, long long *value);
|
||||||
|
int string2l(char *s, size_t slen, long *value);
|
||||||
|
int d2string(char *buf, size_t len, double value);
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user