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 @@
#include "ziplist.h" /* Compact list data structure */
#include "intset.h" /* Compact integer set structure */
#include "version.h"
#include "util.h"
/* Error codes */
#define REDIS_OK 0
......@@ -719,6 +720,7 @@ void freeHashObject(robj *o);
robj *createObject(int type, void *ptr);
robj *createStringObject(char *ptr, size_t len);
robj *dupStringObject(robj *o);
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
robj *tryObjectEncoding(robj *o);
robj *getDecodedObject(robj *o);
size_t stringObjectLen(robj *o);
......@@ -872,18 +874,6 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify);
void freePubsubPattern(void *p);
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 */
void loadServerConfig(char *filename);
void appendServerSaveParams(time_t seconds, int changes);
......
......@@ -36,11 +36,11 @@
#define SDS_ABORT_ON_OOM
#include "sds.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sds.h"
#include "zmalloc.h"
static void sdsOomAbort(void) {
......@@ -76,11 +76,6 @@ sds sdsnew(const char *init) {
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) {
return sdsnewlen(s, sdslen(s));
}
......@@ -90,11 +85,6 @@ void sdsfree(sds s) {
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) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
int reallen = strlen(s);
......@@ -306,12 +296,17 @@ int sdscmp(sds s1, sds s2) {
*/
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
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
if (tokens == NULL) sdsOomAbort();
#else
if (tokens == NULL) return NULL;
#endif
if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
if (len == 0) {
*count = 0;
return tokens;
......@@ -401,11 +396,11 @@ sds sdscatrepr(sds s, char *p, size_t len) {
case '"':
s = sdscatprintf(s,"\\%c",*p);
break;
case '\n': s = sdscatlen(s,"\\n",1); break;
case '\r': s = sdscatlen(s,"\\r",1); break;
case '\t': s = sdscatlen(s,"\\t",1); break;
case '\a': s = sdscatlen(s,"\\a",1); break;
case '\b': s = sdscatlen(s,"\\b",1); break;
case '\n': s = sdscatlen(s,"\\n",2); break;
case '\r': s = sdscatlen(s,"\\r",2); break;
case '\t': s = sdscatlen(s,"\\t",2); break;
case '\a': s = sdscatlen(s,"\\a",2); break;
case '\b': s = sdscatlen(s,"\\b",2); break;
default:
if (isprint(*p))
s = sdscatprintf(s,"%c",*p);
......
......@@ -42,6 +42,16 @@ struct sdshdr {
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 sdsnew(const char *init);
sds sdsempty();
......
#include "redis.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include "util.h"
/* Glob-style pattern matching. */
int stringmatchlen(const char *pattern, int patternLen,
......@@ -213,6 +216,12 @@ int string2ll(char *s, size_t slen, long long *value) {
if (plen == slen)
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] == '-') {
negative = 1;
p++; plen++;
......@@ -250,7 +259,7 @@ int string2ll(char *s, size_t slen, long long *value) {
return 0;
if (negative) {
if (v > (-(unsigned long long)LLONG_MIN)) /* Overflow. */
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
return 0;
if (value != NULL) *value = -v;
} else {
......@@ -261,6 +270,22 @@ int string2ll(char *s, size_t slen, long long *value) {
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
* required. The representation should always be parsable by stdtod(3). */
int d2string(char *buf, size_t len, double value) {
......@@ -300,44 +325,116 @@ int d2string(char *buf, size_t len, double 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, 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);
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 (llongval) *llongval = value;
return REDIS_OK;
#ifdef UTIL_TEST_MAIN
#include <assert.h>
void test_string2ll(void) {
char buf[32];
long long v;
/* May not start with +. */
strcpy(buf,"+1");
assert(string2ll(buf,strlen(buf),&v) == 0);
/* Leading space. */
strcpy(buf," 1");
assert(string2ll(buf,strlen(buf),&v) == 0);
/* Trailing space. */
strcpy(buf,"1 ");
assert(string2ll(buf,strlen(buf),&v) == 0);
/* 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) {
long long ll;
void test_string2l(void) {
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;
if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR;
*longval = (long)ll;
return REDIS_OK;
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) {
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);
}
int main(int argc, char **argv) {
test_string2ll();
test_string2l();
return 0;
}
#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 @@
#include <assert.h>
#include <limits.h>
#include "zmalloc.h"
#include "util.h"
#include "ziplist.h"
int ll2string(char *s, size_t len, long long value);
#define ZIP_END 255
#define ZIP_BIGLEN 254
......@@ -248,22 +247,9 @@ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
* 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) {
long long value;
char *eptr;
char buf[32];
if (entrylen >= 32 || entrylen == 0) return 0;
if (entry[0] == '-' || (entry[0] >= '0' && entry[0] <= '9')) {
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;
if (string2ll((char*)entry,entrylen,&value)) {
/* Great, the string can be encoded. Check what's the smallest
* of our encoding types that can hold this value. */
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