Commit deff2338 authored by antirez's avatar antirez
Browse files

Merge remote branch 'pietern/2.4-misc' into 2.4

parents 2ee7dd36 01f36192
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,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
...@@ -719,6 +720,7 @@ void freeHashObject(robj *o); ...@@ -719,6 +720,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);
...@@ -872,18 +874,6 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify); ...@@ -872,18 +874,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);
......
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
#define SDS_ABORT_ON_OOM #define SDS_ABORT_ON_OOM
#include "sds.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "sds.h"
#include "zmalloc.h" #include "zmalloc.h"
static void sdsOomAbort(void) { static void sdsOomAbort(void) {
...@@ -76,11 +76,6 @@ sds sdsnew(const char *init) { ...@@ -76,11 +76,6 @@ sds sdsnew(const char *init) {
return sdsnewlen(init, initlen); return sdsnewlen(init, initlen);
} }
size_t sdslen(const sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sh->len;
}
sds sdsdup(const sds s) { sds sdsdup(const sds s) {
return sdsnewlen(s, sdslen(s)); return sdsnewlen(s, sdslen(s));
} }
...@@ -90,11 +85,6 @@ void sdsfree(sds s) { ...@@ -90,11 +85,6 @@ void sdsfree(sds s) {
zfree(s-sizeof(struct sdshdr)); zfree(s-sizeof(struct sdshdr));
} }
size_t sdsavail(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sh->free;
}
void sdsupdatelen(sds s) { void sdsupdatelen(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
int reallen = strlen(s); int reallen = strlen(s);
...@@ -306,12 +296,17 @@ int sdscmp(sds s1, sds s2) { ...@@ -306,12 +296,17 @@ int sdscmp(sds s1, sds s2) {
*/ */
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) { sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
int elements = 0, slots = 5, start = 0, j; int elements = 0, slots = 5, start = 0, j;
sds *tokens;
if (seplen < 1 || len < 0) return NULL;
sds *tokens = zmalloc(sizeof(sds)*slots); tokens = zmalloc(sizeof(sds)*slots);
#ifdef SDS_ABORT_ON_OOM #ifdef SDS_ABORT_ON_OOM
if (tokens == NULL) sdsOomAbort(); if (tokens == NULL) sdsOomAbort();
#else
if (tokens == NULL) return NULL;
#endif #endif
if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
if (len == 0) { if (len == 0) {
*count = 0; *count = 0;
return tokens; return tokens;
...@@ -401,11 +396,11 @@ sds sdscatrepr(sds s, char *p, size_t len) { ...@@ -401,11 +396,11 @@ sds sdscatrepr(sds s, char *p, size_t len) {
case '"': case '"':
s = sdscatprintf(s,"\\%c",*p); s = sdscatprintf(s,"\\%c",*p);
break; break;
case '\n': s = sdscatlen(s,"\\n",1); break; case '\n': s = sdscatlen(s,"\\n",2); break;
case '\r': s = sdscatlen(s,"\\r",1); break; case '\r': s = sdscatlen(s,"\\r",2); break;
case '\t': s = sdscatlen(s,"\\t",1); break; case '\t': s = sdscatlen(s,"\\t",2); break;
case '\a': s = sdscatlen(s,"\\a",1); break; case '\a': s = sdscatlen(s,"\\a",2); break;
case '\b': s = sdscatlen(s,"\\b",1); break; case '\b': s = sdscatlen(s,"\\b",2); break;
default: default:
if (isprint(*p)) if (isprint(*p))
s = sdscatprintf(s,"%c",*p); s = sdscatprintf(s,"%c",*p);
......
...@@ -42,6 +42,16 @@ struct sdshdr { ...@@ -42,6 +42,16 @@ struct sdshdr {
char buf[]; char buf[];
}; };
static inline size_t sdslen(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->len;
}
static inline size_t sdsavail(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->free;
}
sds sdsnewlen(const void *init, size_t initlen); sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init); sds sdsnew(const char *init);
sds sdsempty(); sds sdsempty();
......
#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) { ...@@ -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) { ...@@ -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) { ...@@ -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,116 @@ int d2string(char *buf, size_t len, double value) { ...@@ -300,44 +325,116 @@ 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). void test_string2ll(void) {
* char buf[32];
* If so, the function returns REDIS_OK and *llongval is set to the value long long v;
* of the number. Otherwise REDIS_ERR is returned */
int isStringRepresentableAsLongLong(sds s, long long *llongval) { /* May not start with +. */
char buf[32], *endptr; strcpy(buf,"+1");
long long value; assert(string2ll(buf,strlen(buf),&v) == 0);
int slen;
/* Leading space. */
value = strtoll(s, &endptr, 10); strcpy(buf," 1");
if (endptr[0] != '\0') return REDIS_ERR; assert(string2ll(buf,strlen(buf),&v) == 0);
slen = ll2string(buf,32,value);
/* Trailing space. */
/* If the number converted back into a string is not identical strcpy(buf,"1 ");
* then it's not possible to encode the string as integer */ assert(string2ll(buf,strlen(buf),&v) == 0);
if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
if (llongval) *llongval = value; /* May not start with 0. */
return REDIS_OK; 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;
/* May not start with +. */
strcpy(buf,"+1");
assert(string2l(buf,strlen(buf),&v) == 0);
/* 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);
if (isStringRepresentableAsLongLong(s,&ll) == REDIS_ERR) return REDIS_ERR; strcpy(buf,"99");
if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR; assert(string2l(buf,strlen(buf),&v) == 1);
*longval = (long)ll; assert(v == 99);
return REDIS_OK;
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
#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
...@@ -67,10 +67,9 @@ ...@@ -67,10 +67,9 @@
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include "zmalloc.h" #include "zmalloc.h"
#include "util.h"
#include "ziplist.h" #include "ziplist.h"
int ll2string(char *s, size_t len, long long value);
#define ZIP_END 255 #define ZIP_END 255
#define ZIP_BIGLEN 254 #define ZIP_BIGLEN 254
...@@ -248,22 +247,9 @@ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) { ...@@ -248,22 +247,9 @@ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
* Stores the integer value in 'v' and its encoding in 'encoding'. */ * Stores the integer value in 'v' and its encoding in 'encoding'. */
static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) { static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {
long long value; long long value;
char *eptr;
char buf[32];
if (entrylen >= 32 || entrylen == 0) return 0; if (entrylen >= 32 || entrylen == 0) return 0;
if (entry[0] == '-' || (entry[0] >= '0' && entry[0] <= '9')) { if (string2ll((char*)entry,entrylen,&value)) {
int slen;
/* Perform a back-and-forth conversion to make sure that
* the string turned into an integer is not losing any info. */
memcpy(buf,entry,entrylen);
buf[entrylen] = '\0';
value = strtoll(buf,&eptr,10);
if (eptr[0] != '\0') return 0;
slen = ll2string(buf,32,value);
if (entrylen != (unsigned)slen || memcmp(buf,entry,slen)) return 0;
/* Great, the string can be encoded. Check what's the smallest /* Great, the string can be encoded. Check what's the smallest
* of our encoding types that can hold this value. */ * of our encoding types that can hold this value. */
if (value >= INT16_MIN && value <= INT16_MAX) { if (value >= INT16_MIN && value <= INT16_MAX) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment