mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-23 08:38:27 -05:00
Merge branch 'sds' into unstable
This commit is contained in:
commit
935251259f
@ -120,9 +120,9 @@ REDIS_SENTINEL_NAME=redis-sentinel
|
|||||||
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o geo.o
|
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o geo.o
|
||||||
REDIS_GEOHASH_OBJ=../deps/geohash-int/geohash.o ../deps/geohash-int/geohash_helper.o
|
REDIS_GEOHASH_OBJ=../deps/geohash-int/geohash.o ../deps/geohash-int/geohash_helper.o
|
||||||
REDIS_CLI_NAME=redis-cli
|
REDIS_CLI_NAME=redis-cli
|
||||||
REDIS_CLI_OBJ=anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
|
REDIS_CLI_OBJ=anet.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
|
||||||
REDIS_BENCHMARK_NAME=redis-benchmark
|
REDIS_BENCHMARK_NAME=redis-benchmark
|
||||||
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o redis-benchmark.o
|
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o zmalloc.o redis-benchmark.o
|
||||||
REDIS_CHECK_RDB_NAME=redis-check-rdb
|
REDIS_CHECK_RDB_NAME=redis-check-rdb
|
||||||
REDIS_CHECK_AOF_NAME=redis-check-aof
|
REDIS_CHECK_AOF_NAME=redis-check-aof
|
||||||
REDIS_CHECK_AOF_OBJ=redis-check-aof.o
|
REDIS_CHECK_AOF_OBJ=redis-check-aof.o
|
||||||
|
12
src/debug.c
12
src/debug.c
@ -420,10 +420,14 @@ void debugCommand(redisClient *c) {
|
|||||||
addReplySds(c,errstr);
|
addReplySds(c,errstr);
|
||||||
} else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) {
|
} else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) {
|
||||||
sds sizes = sdsempty();
|
sds sizes = sdsempty();
|
||||||
sizes = sdscatprintf(sizes,"bits:%d ", (sizeof(void*) == 8)?64:32);
|
sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
|
||||||
sizes = sdscatprintf(sizes,"robj:%d ", (int)sizeof(robj));
|
sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
|
||||||
sizes = sdscatprintf(sizes,"dictentry:%d ", (int)sizeof(dictEntry));
|
sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry));
|
||||||
sizes = sdscatprintf(sizes,"sdshdr:%d", (int)sizeof(struct sdshdr));
|
sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
|
||||||
|
sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
|
||||||
|
sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
|
||||||
|
sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32));
|
||||||
|
sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64));
|
||||||
addReplyBulkSds(c,sizes);
|
addReplyBulkSds(c,sizes);
|
||||||
} else if (!strcasecmp(c->argv[1]->ptr,"htstats") && c->argc == 3) {
|
} else if (!strcasecmp(c->argv[1]->ptr,"htstats") && c->argc == 3) {
|
||||||
long dbid;
|
long dbid;
|
||||||
|
@ -33,21 +33,14 @@
|
|||||||
|
|
||||||
static void setProtocolError(redisClient *c, int pos);
|
static void setProtocolError(redisClient *c, int pos);
|
||||||
|
|
||||||
/* To evaluate the output buffer size of a client we need to get size of
|
|
||||||
* allocated objects, however we can't used zmalloc_size() directly on sds
|
|
||||||
* strings because of the trick they use to work (the header is before the
|
|
||||||
* returned pointer), so we use this helper function. */
|
|
||||||
size_t zmalloc_size_sds(sds s) {
|
|
||||||
return zmalloc_size(s-sizeof(struct sdshdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the amount of memory used by the sds string at object->ptr
|
/* Return the amount of memory used by the sds string at object->ptr
|
||||||
* for a string object. */
|
* for a string object. */
|
||||||
size_t getStringObjectSdsUsedMemory(robj *o) {
|
size_t getStringObjectSdsUsedMemory(robj *o) {
|
||||||
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
|
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
|
||||||
switch(o->encoding) {
|
switch(o->encoding) {
|
||||||
case REDIS_ENCODING_RAW: return zmalloc_size_sds(o->ptr);
|
case REDIS_ENCODING_RAW: return sdsZmallocSize(o->ptr);
|
||||||
case REDIS_ENCODING_EMBSTR: return sdslen(o->ptr);
|
case REDIS_ENCODING_EMBSTR: return zmalloc_size(o)-sizeof(robj);
|
||||||
default: return 0; /* Just integer encoding for now. */
|
default: return 0; /* Just integer encoding for now. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,10 +228,10 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
|
|||||||
tail->encoding == REDIS_ENCODING_RAW &&
|
tail->encoding == REDIS_ENCODING_RAW &&
|
||||||
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
|
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
{
|
{
|
||||||
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
|
c->reply_bytes -= sdsZmallocSize(tail->ptr);
|
||||||
tail = dupLastObjectIfNeeded(c->reply);
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
|
tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
|
||||||
c->reply_bytes += zmalloc_size_sds(tail->ptr);
|
c->reply_bytes += sdsZmallocSize(tail->ptr);
|
||||||
} else {
|
} else {
|
||||||
incrRefCount(o);
|
incrRefCount(o);
|
||||||
listAddNodeTail(c->reply,o);
|
listAddNodeTail(c->reply,o);
|
||||||
@ -260,7 +253,7 @@ void _addReplySdsToList(redisClient *c, sds s) {
|
|||||||
|
|
||||||
if (listLength(c->reply) == 0) {
|
if (listLength(c->reply) == 0) {
|
||||||
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
||||||
c->reply_bytes += zmalloc_size_sds(s);
|
c->reply_bytes += sdsZmallocSize(s);
|
||||||
} else {
|
} else {
|
||||||
tail = listNodeValue(listLast(c->reply));
|
tail = listNodeValue(listLast(c->reply));
|
||||||
|
|
||||||
@ -268,14 +261,14 @@ void _addReplySdsToList(redisClient *c, sds s) {
|
|||||||
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
|
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
|
||||||
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
|
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
{
|
{
|
||||||
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
|
c->reply_bytes -= sdsZmallocSize(tail->ptr);
|
||||||
tail = dupLastObjectIfNeeded(c->reply);
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
|
tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
|
||||||
c->reply_bytes += zmalloc_size_sds(tail->ptr);
|
c->reply_bytes += sdsZmallocSize(tail->ptr);
|
||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
} else {
|
} else {
|
||||||
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
||||||
c->reply_bytes += zmalloc_size_sds(s);
|
c->reply_bytes += sdsZmallocSize(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asyncCloseClientOnOutputBufferLimitReached(c);
|
asyncCloseClientOnOutputBufferLimitReached(c);
|
||||||
@ -298,10 +291,10 @@ void _addReplyStringToList(redisClient *c, const char *s, size_t len) {
|
|||||||
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
|
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
|
||||||
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
|
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
{
|
{
|
||||||
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
|
c->reply_bytes -= sdsZmallocSize(tail->ptr);
|
||||||
tail = dupLastObjectIfNeeded(c->reply);
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
tail->ptr = sdscatlen(tail->ptr,s,len);
|
tail->ptr = sdscatlen(tail->ptr,s,len);
|
||||||
c->reply_bytes += zmalloc_size_sds(tail->ptr);
|
c->reply_bytes += sdsZmallocSize(tail->ptr);
|
||||||
} else {
|
} else {
|
||||||
robj *o = createStringObject(s,len);
|
robj *o = createStringObject(s,len);
|
||||||
|
|
||||||
@ -440,16 +433,16 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
|
|||||||
len = listNodeValue(ln);
|
len = listNodeValue(ln);
|
||||||
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
|
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
|
||||||
len->encoding = REDIS_ENCODING_RAW; /* in case it was an EMBSTR. */
|
len->encoding = REDIS_ENCODING_RAW; /* in case it was an EMBSTR. */
|
||||||
c->reply_bytes += zmalloc_size_sds(len->ptr);
|
c->reply_bytes += sdsZmallocSize(len->ptr);
|
||||||
if (ln->next != NULL) {
|
if (ln->next != NULL) {
|
||||||
next = listNodeValue(ln->next);
|
next = listNodeValue(ln->next);
|
||||||
|
|
||||||
/* Only glue when the next node is non-NULL (an sds in this case) */
|
/* Only glue when the next node is non-NULL (an sds in this case) */
|
||||||
if (next->ptr != NULL) {
|
if (next->ptr != NULL) {
|
||||||
c->reply_bytes -= zmalloc_size_sds(len->ptr);
|
c->reply_bytes -= sdsZmallocSize(len->ptr);
|
||||||
c->reply_bytes -= getStringObjectSdsUsedMemory(next);
|
c->reply_bytes -= getStringObjectSdsUsedMemory(next);
|
||||||
len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
|
len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
|
||||||
c->reply_bytes += zmalloc_size_sds(len->ptr);
|
c->reply_bytes += sdsZmallocSize(len->ptr);
|
||||||
listDelNode(c->reply,ln->next);
|
listDelNode(c->reply,ln->next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@ robj *createRawStringObject(const char *ptr, size_t len) {
|
|||||||
* an object where the sds string is actually an unmodifiable string
|
* an object where the sds string is actually an unmodifiable string
|
||||||
* allocated in the same chunk as the object itself. */
|
* allocated in the same chunk as the object itself. */
|
||||||
robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
||||||
robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
|
robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1);
|
||||||
struct sdshdr *sh = (void*)(o+1);
|
struct sdshdr8 *sh = (void*)(o+1);
|
||||||
|
|
||||||
o->type = REDIS_STRING;
|
o->type = REDIS_STRING;
|
||||||
o->encoding = REDIS_ENCODING_EMBSTR;
|
o->encoding = REDIS_ENCODING_EMBSTR;
|
||||||
@ -68,7 +68,8 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
|||||||
o->lru = LRU_CLOCK();
|
o->lru = LRU_CLOCK();
|
||||||
|
|
||||||
sh->len = len;
|
sh->len = len;
|
||||||
sh->free = 0;
|
sh->alloc = len;
|
||||||
|
sh->flags = SDS_TYPE_8;
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
memcpy(sh->buf,ptr,len);
|
memcpy(sh->buf,ptr,len);
|
||||||
sh->buf[len] = '\0';
|
sh->buf[len] = '\0';
|
||||||
@ -84,7 +85,7 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
|
|||||||
*
|
*
|
||||||
* The current limit of 39 is chosen so that the biggest string object
|
* The current limit of 39 is chosen so that the biggest string object
|
||||||
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
|
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
|
||||||
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
|
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 44
|
||||||
robj *createStringObject(const char *ptr, size_t len) {
|
robj *createStringObject(const char *ptr, size_t len) {
|
||||||
if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
|
if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
|
||||||
return createEmbeddedStringObject(ptr,len);
|
return createEmbeddedStringObject(ptr,len);
|
||||||
|
@ -40,9 +40,9 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <sds.h> /* Use hiredis sds. */
|
||||||
#include "ae.h"
|
#include "ae.h"
|
||||||
#include "hiredis.h"
|
#include "hiredis.h"
|
||||||
#include "sds.h"
|
|
||||||
#include "adlist.h"
|
#include "adlist.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "hiredis.h"
|
#include <hiredis.h>
|
||||||
#include "sds.h"
|
#include <sds.h> /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
#include "linenoise.h"
|
#include "linenoise.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
@ -265,14 +265,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
|||||||
if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
|
if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
|
||||||
cached_objects_len[j] >= obj_len)
|
cached_objects_len[j] >= obj_len)
|
||||||
{
|
{
|
||||||
char *s = cached_objects[j]->ptr;
|
sds s = cached_objects[j]->ptr;
|
||||||
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
|
||||||
|
|
||||||
argv[j] = cached_objects[j];
|
argv[j] = cached_objects[j];
|
||||||
cached_objects[j] = NULL;
|
cached_objects[j] = NULL;
|
||||||
memcpy(s,obj_s,obj_len+1);
|
memcpy(s,obj_s,obj_len+1);
|
||||||
sh->free += sh->len - obj_len;
|
sdssetlen(s, obj_len);
|
||||||
sh->len = obj_len;
|
|
||||||
} else {
|
} else {
|
||||||
argv[j] = createStringObject(obj_s, obj_len);
|
argv[j] = createStringObject(obj_s, obj_len);
|
||||||
}
|
}
|
||||||
@ -422,11 +419,10 @@ cleanup:
|
|||||||
o->encoding == REDIS_ENCODING_EMBSTR) &&
|
o->encoding == REDIS_ENCODING_EMBSTR) &&
|
||||||
sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
|
sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
|
||||||
{
|
{
|
||||||
struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));
|
sds s = o->ptr;
|
||||||
|
|
||||||
if (cached_objects[j]) decrRefCount(cached_objects[j]);
|
if (cached_objects[j]) decrRefCount(cached_objects[j]);
|
||||||
cached_objects[j] = o;
|
cached_objects[j] = o;
|
||||||
cached_objects_len[j] = sh->free + sh->len;
|
cached_objects_len[j] = sdsalloc(s);
|
||||||
} else {
|
} else {
|
||||||
decrRefCount(o);
|
decrRefCount(o);
|
||||||
}
|
}
|
||||||
|
338
src/sds.c
338
src/sds.c
@ -36,6 +36,34 @@
|
|||||||
#include "sds.h"
|
#include "sds.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
|
static inline int sdsHdrSize(char type) {
|
||||||
|
switch(type&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
return sizeof(struct sdshdr5);
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
return sizeof(struct sdshdr8);
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
return sizeof(struct sdshdr16);
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
return sizeof(struct sdshdr32);
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
return sizeof(struct sdshdr64);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char sdsReqType(size_t string_size) {
|
||||||
|
if (string_size < 32)
|
||||||
|
return SDS_TYPE_5;
|
||||||
|
if (string_size < 0xff)
|
||||||
|
return SDS_TYPE_8;
|
||||||
|
if (string_size < 0xffff)
|
||||||
|
return SDS_TYPE_16;
|
||||||
|
if (string_size < 0xffffffff)
|
||||||
|
return SDS_TYPE_32;
|
||||||
|
return SDS_TYPE_64;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a new sds string with the content specified by the 'init' pointer
|
/* Create a new sds string with the content specified by the 'init' pointer
|
||||||
* and 'initlen'.
|
* and 'initlen'.
|
||||||
* If NULL is used for 'init' the string is initialized with zero bytes.
|
* If NULL is used for 'init' the string is initialized with zero bytes.
|
||||||
@ -49,20 +77,59 @@
|
|||||||
* end of the string. However the string is binary safe and can contain
|
* end of the string. However the string is binary safe and can contain
|
||||||
* \0 characters in the middle, as the length is stored in the sds header. */
|
* \0 characters in the middle, as the length is stored in the sds header. */
|
||||||
sds sdsnewlen(const void *init, size_t initlen) {
|
sds sdsnewlen(const void *init, size_t initlen) {
|
||||||
struct sdshdr *sh;
|
void *sh;
|
||||||
|
sds s;
|
||||||
|
char type = sdsReqType(initlen);
|
||||||
|
/* Empty strings are usually created in order to append. Use type 8
|
||||||
|
* since type 5 is not good at this. */
|
||||||
|
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
|
||||||
|
int hdrlen = sdsHdrSize(type);
|
||||||
|
unsigned char *fp; /* flags pointer. */
|
||||||
|
|
||||||
if (init) {
|
sh = zmalloc(hdrlen+initlen+1);
|
||||||
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
|
if (!init)
|
||||||
} else {
|
memset(sh, 0, hdrlen+initlen+1);
|
||||||
sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
|
|
||||||
}
|
|
||||||
if (sh == NULL) return NULL;
|
if (sh == NULL) return NULL;
|
||||||
sh->len = initlen;
|
s = (char*)sh+hdrlen;
|
||||||
sh->free = 0;
|
fp = ((unsigned char*)s)-1;
|
||||||
|
switch(type) {
|
||||||
|
case SDS_TYPE_5: {
|
||||||
|
*fp = type | (initlen << SDS_TYPE_BITS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_8: {
|
||||||
|
SDS_HDR_VAR(8,s);
|
||||||
|
sh->len = initlen;
|
||||||
|
sh->alloc = initlen;
|
||||||
|
*fp = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_16: {
|
||||||
|
SDS_HDR_VAR(16,s);
|
||||||
|
sh->len = initlen;
|
||||||
|
sh->alloc = initlen;
|
||||||
|
*fp = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_32: {
|
||||||
|
SDS_HDR_VAR(32,s);
|
||||||
|
sh->len = initlen;
|
||||||
|
sh->alloc = initlen;
|
||||||
|
*fp = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_64: {
|
||||||
|
SDS_HDR_VAR(64,s);
|
||||||
|
sh->len = initlen;
|
||||||
|
sh->alloc = initlen;
|
||||||
|
*fp = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (initlen && init)
|
if (initlen && init)
|
||||||
memcpy(sh->buf, init, initlen);
|
memcpy(s, init, initlen);
|
||||||
sh->buf[initlen] = '\0';
|
s[initlen] = '\0';
|
||||||
return (char*)sh->buf;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create an empty (zero length) sds string. Even in this case the string
|
/* Create an empty (zero length) sds string. Even in this case the string
|
||||||
@ -85,7 +152,7 @@ sds sdsdup(const sds s) {
|
|||||||
/* Free an sds string. No operation is performed if 's' is NULL. */
|
/* Free an sds string. No operation is performed if 's' is NULL. */
|
||||||
void sdsfree(sds s) {
|
void sdsfree(sds s) {
|
||||||
if (s == NULL) return;
|
if (s == NULL) return;
|
||||||
zfree(s-sizeof(struct sdshdr));
|
zfree((char*)s-sdsHdrSize(s[-1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the sds string length to the length as obtained with strlen(), so
|
/* Set the sds string length to the length as obtained with strlen(), so
|
||||||
@ -103,10 +170,8 @@ void sdsfree(sds s) {
|
|||||||
* the output will be "6" as the string was modified but the logical length
|
* the output will be "6" as the string was modified but the logical length
|
||||||
* remains 6 bytes. */
|
* remains 6 bytes. */
|
||||||
void sdsupdatelen(sds s) {
|
void sdsupdatelen(sds s) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
int reallen = strlen(s);
|
int reallen = strlen(s);
|
||||||
sh->free += (sh->len-reallen);
|
sdssetlen(s, reallen);
|
||||||
sh->len = reallen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modify an sds string in-place to make it empty (zero length).
|
/* Modify an sds string in-place to make it empty (zero length).
|
||||||
@ -114,10 +179,8 @@ void sdsupdatelen(sds s) {
|
|||||||
* so that next append operations will not require allocations up to the
|
* so that next append operations will not require allocations up to the
|
||||||
* number of bytes previously available. */
|
* number of bytes previously available. */
|
||||||
void sdsclear(sds s) {
|
void sdsclear(sds s) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
sdssetlen(s, 0);
|
||||||
sh->free += sh->len;
|
s[0] = '\0';
|
||||||
sh->len = 0;
|
|
||||||
sh->buf[0] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enlarge the free space at the end of the sds string so that the caller
|
/* Enlarge the free space at the end of the sds string so that the caller
|
||||||
@ -127,23 +190,48 @@ void sdsclear(sds s) {
|
|||||||
* Note: this does not change the *length* of the sds string as returned
|
* Note: this does not change the *length* of the sds string as returned
|
||||||
* by sdslen(), but only the free buffer space we have. */
|
* by sdslen(), but only the free buffer space we have. */
|
||||||
sds sdsMakeRoomFor(sds s, size_t addlen) {
|
sds sdsMakeRoomFor(sds s, size_t addlen) {
|
||||||
struct sdshdr *sh, *newsh;
|
void *sh, *newsh;
|
||||||
size_t free = sdsavail(s);
|
size_t avail = sdsavail(s);
|
||||||
size_t len, newlen;
|
size_t len, newlen;
|
||||||
|
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
||||||
|
int hdrlen;
|
||||||
|
|
||||||
|
/* Return ASAP if there is enough space left. */
|
||||||
|
if (avail >= addlen) return s;
|
||||||
|
|
||||||
if (free >= addlen) return s;
|
|
||||||
len = sdslen(s);
|
len = sdslen(s);
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
sh = (char*)s-sdsHdrSize(oldtype);
|
||||||
newlen = (len+addlen);
|
newlen = (len+addlen);
|
||||||
if (newlen < SDS_MAX_PREALLOC)
|
if (newlen < SDS_MAX_PREALLOC)
|
||||||
newlen *= 2;
|
newlen *= 2;
|
||||||
else
|
else
|
||||||
newlen += SDS_MAX_PREALLOC;
|
newlen += SDS_MAX_PREALLOC;
|
||||||
newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
|
|
||||||
if (newsh == NULL) return NULL;
|
|
||||||
|
|
||||||
newsh->free = newlen - len;
|
type = sdsReqType(newlen);
|
||||||
return newsh->buf;
|
|
||||||
|
/* Don't use type 5: the user is appending to the string and type 5 is
|
||||||
|
* not able to remember empty space, so sdsMakeRoomFor() must be called
|
||||||
|
* at every appending operation. */
|
||||||
|
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
|
||||||
|
|
||||||
|
hdrlen = sdsHdrSize(type);
|
||||||
|
if (oldtype==type) {
|
||||||
|
newsh = zrealloc(sh, hdrlen+newlen+1);
|
||||||
|
if (newsh == NULL) return NULL;
|
||||||
|
s = (char*)newsh+hdrlen;
|
||||||
|
} else {
|
||||||
|
/* Since the header size changes, need to move the string forward,
|
||||||
|
* and can't use realloc */
|
||||||
|
newsh = zmalloc(hdrlen+newlen+1);
|
||||||
|
if (newsh == NULL) return NULL;
|
||||||
|
memcpy((char*)newsh+hdrlen, s, len+1);
|
||||||
|
zfree(sh);
|
||||||
|
s = (char*)newsh+hdrlen;
|
||||||
|
s[-1] = type;
|
||||||
|
sdssetlen(s, len);
|
||||||
|
}
|
||||||
|
sdssetalloc(s, newlen);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reallocate the sds string so that it has no free space at the end. The
|
/* Reallocate the sds string so that it has no free space at the end. The
|
||||||
@ -153,12 +241,29 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
|
|||||||
* After the call, the passed sds string is no longer valid and all the
|
* After the call, the passed sds string is no longer valid and all the
|
||||||
* references must be substituted with the new pointer returned by the call. */
|
* references must be substituted with the new pointer returned by the call. */
|
||||||
sds sdsRemoveFreeSpace(sds s) {
|
sds sdsRemoveFreeSpace(sds s) {
|
||||||
struct sdshdr *sh;
|
void *sh, *newsh;
|
||||||
|
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
||||||
|
int hdrlen;
|
||||||
|
size_t len = sdslen(s);
|
||||||
|
sh = (char*)s-sdsHdrSize(oldtype);
|
||||||
|
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
type = sdsReqType(len);
|
||||||
sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
|
hdrlen = sdsHdrSize(type);
|
||||||
sh->free = 0;
|
if (oldtype==type) {
|
||||||
return sh->buf;
|
newsh = zrealloc(sh, hdrlen+len+1);
|
||||||
|
if (newsh == NULL) return NULL;
|
||||||
|
s = (char*)newsh+hdrlen;
|
||||||
|
} else {
|
||||||
|
newsh = zmalloc(hdrlen+len+1);
|
||||||
|
if (newsh == NULL) return NULL;
|
||||||
|
memcpy((char*)newsh+hdrlen, s, len+1);
|
||||||
|
zfree(sh);
|
||||||
|
s = (char*)newsh+hdrlen;
|
||||||
|
s[-1] = type;
|
||||||
|
sdssetlen(s, len);
|
||||||
|
}
|
||||||
|
sdssetalloc(s, len);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the total size of the allocation of the specifed sds string,
|
/* Return the total size of the allocation of the specifed sds string,
|
||||||
@ -169,9 +274,15 @@ sds sdsRemoveFreeSpace(sds s) {
|
|||||||
* 4) The implicit null term.
|
* 4) The implicit null term.
|
||||||
*/
|
*/
|
||||||
size_t sdsAllocSize(sds s) {
|
size_t sdsAllocSize(sds s) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
size_t alloc = sdsalloc(s);
|
||||||
|
return sdsHdrSize(s[-1])+alloc+1;
|
||||||
|
}
|
||||||
|
|
||||||
return sizeof(*sh)+sh->len+sh->free+1;
|
/* Return the size consumed from the allocator,
|
||||||
|
* including internal fragmentation */
|
||||||
|
size_t sdsZmallocSize(sds s) {
|
||||||
|
struct sdshdr *sh = (void*) (s-sdsHdrSize(s[-1]));
|
||||||
|
return zmalloc_size(sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Increment the sds length and decrements the left free space at the
|
/* Increment the sds length and decrements the left free space at the
|
||||||
@ -198,15 +309,43 @@ size_t sdsAllocSize(sds s) {
|
|||||||
* sdsIncrLen(s, nread);
|
* sdsIncrLen(s, nread);
|
||||||
*/
|
*/
|
||||||
void sdsIncrLen(sds s, int incr) {
|
void sdsIncrLen(sds s, int incr) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
unsigned char flags = s[-1];
|
||||||
|
size_t len;
|
||||||
if (incr >= 0)
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
assert(sh->free >= (unsigned int)incr);
|
case SDS_TYPE_5: {
|
||||||
else
|
unsigned char *fp = ((unsigned char*)s)-1;
|
||||||
assert(sh->len >= (unsigned int)(-incr));
|
unsigned char oldlen = SDS_TYPE_5_LEN(flags);
|
||||||
sh->len += incr;
|
assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
|
||||||
sh->free -= incr;
|
*fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
|
||||||
s[sh->len] = '\0';
|
len = oldlen+incr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_8: {
|
||||||
|
SDS_HDR_VAR(8,s);
|
||||||
|
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||||
|
len = (sh->len += incr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_16: {
|
||||||
|
SDS_HDR_VAR(16,s);
|
||||||
|
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||||
|
len = (sh->len += incr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_32: {
|
||||||
|
SDS_HDR_VAR(32,s);
|
||||||
|
assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||||
|
len = (sh->len += incr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_64: {
|
||||||
|
SDS_HDR_VAR(64,s);
|
||||||
|
assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
|
||||||
|
len = (sh->len += incr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grow the sds to have the specified length. Bytes that were not part of
|
/* Grow the sds to have the specified length. Bytes that were not part of
|
||||||
@ -215,19 +354,15 @@ void sdsIncrLen(sds s, int incr) {
|
|||||||
* if the specified length is smaller than the current length, no operation
|
* if the specified length is smaller than the current length, no operation
|
||||||
* is performed. */
|
* is performed. */
|
||||||
sds sdsgrowzero(sds s, size_t len) {
|
sds sdsgrowzero(sds s, size_t len) {
|
||||||
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
size_t curlen = sdslen(s);
|
||||||
size_t totlen, curlen = sh->len;
|
|
||||||
|
|
||||||
if (len <= curlen) return s;
|
if (len <= curlen) return s;
|
||||||
s = sdsMakeRoomFor(s,len-curlen);
|
s = sdsMakeRoomFor(s,len-curlen);
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
|
|
||||||
/* Make sure added region doesn't contain garbage */
|
/* Make sure added region doesn't contain garbage */
|
||||||
sh = (void*)(s-(sizeof(struct sdshdr)));
|
|
||||||
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
|
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
|
||||||
totlen = sh->len+sh->free;
|
sdssetlen(s, len);
|
||||||
sh->len = len;
|
|
||||||
sh->free = totlen-sh->len;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,15 +372,12 @@ sds sdsgrowzero(sds s, size_t len) {
|
|||||||
* After the call, the passed sds string is no longer valid and all the
|
* After the call, the passed sds string is no longer valid and all the
|
||||||
* references must be substituted with the new pointer returned by the call. */
|
* references must be substituted with the new pointer returned by the call. */
|
||||||
sds sdscatlen(sds s, const void *t, size_t len) {
|
sds sdscatlen(sds s, const void *t, size_t len) {
|
||||||
struct sdshdr *sh;
|
|
||||||
size_t curlen = sdslen(s);
|
size_t curlen = sdslen(s);
|
||||||
|
|
||||||
s = sdsMakeRoomFor(s,len);
|
s = sdsMakeRoomFor(s,len);
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
memcpy(s+curlen, t, len);
|
memcpy(s+curlen, t, len);
|
||||||
sh->len = curlen+len;
|
sdssetlen(s, curlen+len);
|
||||||
sh->free = sh->free-len;
|
|
||||||
s[curlen+len] = '\0';
|
s[curlen+len] = '\0';
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -269,19 +401,13 @@ sds sdscatsds(sds s, const sds t) {
|
|||||||
/* Destructively modify the sds string 's' to hold the specified binary
|
/* Destructively modify the sds string 's' to hold the specified binary
|
||||||
* safe string pointed by 't' of length 'len' bytes. */
|
* safe string pointed by 't' of length 'len' bytes. */
|
||||||
sds sdscpylen(sds s, const char *t, size_t len) {
|
sds sdscpylen(sds s, const char *t, size_t len) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
if (sdsalloc(s) < len) {
|
||||||
size_t totlen = sh->free+sh->len;
|
s = sdsMakeRoomFor(s,len-sdslen(s));
|
||||||
|
|
||||||
if (totlen < len) {
|
|
||||||
s = sdsMakeRoomFor(s,len-sh->len);
|
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
totlen = sh->free+sh->len;
|
|
||||||
}
|
}
|
||||||
memcpy(s, t, len);
|
memcpy(s, t, len);
|
||||||
s[len] = '\0';
|
s[len] = '\0';
|
||||||
sh->len = len;
|
sdssetlen(s, len);
|
||||||
sh->free = totlen-len;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +575,6 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
|
|||||||
* %% - Verbatim "%" character.
|
* %% - Verbatim "%" character.
|
||||||
*/
|
*/
|
||||||
sds sdscatfmt(sds s, char const *fmt, ...) {
|
sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
size_t initlen = sdslen(s);
|
size_t initlen = sdslen(s);
|
||||||
const char *f = fmt;
|
const char *f = fmt;
|
||||||
int i;
|
int i;
|
||||||
@ -460,14 +585,13 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|||||||
i = initlen; /* Position of the next byte to write to dest str. */
|
i = initlen; /* Position of the next byte to write to dest str. */
|
||||||
while(*f) {
|
while(*f) {
|
||||||
char next, *str;
|
char next, *str;
|
||||||
unsigned int l;
|
size_t l;
|
||||||
long long num;
|
long long num;
|
||||||
unsigned long long unum;
|
unsigned long long unum;
|
||||||
|
|
||||||
/* Make sure there is always space for at least 1 char. */
|
/* Make sure there is always space for at least 1 char. */
|
||||||
if (sh->free == 0) {
|
if (sdsavail(s)==0) {
|
||||||
s = sdsMakeRoomFor(s,1);
|
s = sdsMakeRoomFor(s,1);
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(*f) {
|
switch(*f) {
|
||||||
@ -479,13 +603,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|||||||
case 'S':
|
case 'S':
|
||||||
str = va_arg(ap,char*);
|
str = va_arg(ap,char*);
|
||||||
l = (next == 's') ? strlen(str) : sdslen(str);
|
l = (next == 's') ? strlen(str) : sdslen(str);
|
||||||
if (sh->free < l) {
|
if (sdsavail(s) < l) {
|
||||||
s = sdsMakeRoomFor(s,l);
|
s = sdsMakeRoomFor(s,l);
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
}
|
}
|
||||||
memcpy(s+i,str,l);
|
memcpy(s+i,str,l);
|
||||||
sh->len += l;
|
sdsinclen(s,l);
|
||||||
sh->free -= l;
|
|
||||||
i += l;
|
i += l;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
@ -497,13 +619,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|||||||
{
|
{
|
||||||
char buf[SDS_LLSTR_SIZE];
|
char buf[SDS_LLSTR_SIZE];
|
||||||
l = sdsll2str(buf,num);
|
l = sdsll2str(buf,num);
|
||||||
if (sh->free < l) {
|
if (sdsavail(s) < l) {
|
||||||
s = sdsMakeRoomFor(s,l);
|
s = sdsMakeRoomFor(s,l);
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
}
|
}
|
||||||
memcpy(s+i,buf,l);
|
memcpy(s+i,buf,l);
|
||||||
sh->len += l;
|
sdsinclen(s,l);
|
||||||
sh->free -= l;
|
|
||||||
i += l;
|
i += l;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -516,27 +636,23 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|||||||
{
|
{
|
||||||
char buf[SDS_LLSTR_SIZE];
|
char buf[SDS_LLSTR_SIZE];
|
||||||
l = sdsull2str(buf,unum);
|
l = sdsull2str(buf,unum);
|
||||||
if (sh->free < l) {
|
if (sdsavail(s) < l) {
|
||||||
s = sdsMakeRoomFor(s,l);
|
s = sdsMakeRoomFor(s,l);
|
||||||
sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
}
|
}
|
||||||
memcpy(s+i,buf,l);
|
memcpy(s+i,buf,l);
|
||||||
sh->len += l;
|
sdsinclen(s,l);
|
||||||
sh->free -= l;
|
|
||||||
i += l;
|
i += l;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: /* Handle %% and generally %<unknown>. */
|
default: /* Handle %% and generally %<unknown>. */
|
||||||
s[i++] = next;
|
s[i++] = next;
|
||||||
sh->len += 1;
|
sdsinclen(s,1);
|
||||||
sh->free -= 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
s[i++] = *f;
|
s[i++] = *f;
|
||||||
sh->len += 1;
|
sdsinclen(s,1);
|
||||||
sh->free -= 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f++;
|
f++;
|
||||||
@ -563,7 +679,6 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|||||||
* Output will be just "Hello World".
|
* Output will be just "Hello World".
|
||||||
*/
|
*/
|
||||||
sds sdstrim(sds s, const char *cset) {
|
sds sdstrim(sds s, const char *cset) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
char *start, *end, *sp, *ep;
|
char *start, *end, *sp, *ep;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@ -572,10 +687,9 @@ sds sdstrim(sds s, const char *cset) {
|
|||||||
while(sp <= end && strchr(cset, *sp)) sp++;
|
while(sp <= end && strchr(cset, *sp)) sp++;
|
||||||
while(ep > sp && strchr(cset, *ep)) ep--;
|
while(ep > sp && strchr(cset, *ep)) ep--;
|
||||||
len = (sp > ep) ? 0 : ((ep-sp)+1);
|
len = (sp > ep) ? 0 : ((ep-sp)+1);
|
||||||
if (sh->buf != sp) memmove(sh->buf, sp, len);
|
if (s != sp) memmove(s, sp, len);
|
||||||
sh->buf[len] = '\0';
|
s[len] = '\0';
|
||||||
sh->free = sh->free+(sh->len-len);
|
sdssetlen(s,len);
|
||||||
sh->len = len;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +710,6 @@ sds sdstrim(sds s, const char *cset) {
|
|||||||
* sdsrange(s,1,-1); => "ello World"
|
* sdsrange(s,1,-1); => "ello World"
|
||||||
*/
|
*/
|
||||||
void sdsrange(sds s, int start, int end) {
|
void sdsrange(sds s, int start, int end) {
|
||||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
|
||||||
size_t newlen, len = sdslen(s);
|
size_t newlen, len = sdslen(s);
|
||||||
|
|
||||||
if (len == 0) return;
|
if (len == 0) return;
|
||||||
@ -619,10 +732,9 @@ void sdsrange(sds s, int start, int end) {
|
|||||||
} else {
|
} else {
|
||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
|
if (start && newlen) memmove(s, s+start, newlen);
|
||||||
sh->buf[newlen] = 0;
|
s[newlen] = 0;
|
||||||
sh->free = sh->free+(sh->len-newlen);
|
sdssetlen(s,newlen);
|
||||||
sh->len = newlen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply tolower() to every character of the sds string 's'. */
|
/* Apply tolower() to every character of the sds string 's'. */
|
||||||
@ -968,11 +1080,8 @@ sds sdsjoin(char **argv, int argc, char *sep) {
|
|||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
|
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
int sdsTest(int argc, char *argv[]) {
|
int sdsTest(void) {
|
||||||
UNUSED(argc);
|
|
||||||
UNUSED(argv);
|
|
||||||
{
|
{
|
||||||
struct sdshdr *sh;
|
|
||||||
sds x = sdsnew("foo"), y;
|
sds x = sdsnew("foo"), y;
|
||||||
|
|
||||||
test_cond("Create a string and obtain the length",
|
test_cond("Create a string and obtain the length",
|
||||||
@ -1008,6 +1117,7 @@ int sdsTest(int argc, char *argv[]) {
|
|||||||
sdslen(x) == 60 &&
|
sdslen(x) == 60 &&
|
||||||
memcmp(x,"--Hello Hi! World -9223372036854775808,"
|
memcmp(x,"--Hello Hi! World -9223372036854775808,"
|
||||||
"9223372036854775807--",60) == 0)
|
"9223372036854775807--",60) == 0)
|
||||||
|
printf("[%s]\n",x);
|
||||||
|
|
||||||
sdsfree(x);
|
sdsfree(x);
|
||||||
x = sdsnew("--");
|
x = sdsnew("--");
|
||||||
@ -1096,21 +1206,35 @@ int sdsTest(int argc, char *argv[]) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
unsigned int oldfree;
|
unsigned int oldfree;
|
||||||
|
char *p;
|
||||||
|
int step = 10, j, i;
|
||||||
|
|
||||||
sdsfree(x);
|
sdsfree(x);
|
||||||
sdsfree(y);
|
sdsfree(y);
|
||||||
x = sdsnew("0");
|
x = sdsnew("0");
|
||||||
sh = (void*) (x-(sizeof(struct sdshdr)));
|
test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
|
||||||
test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0);
|
|
||||||
x = sdsMakeRoomFor(x,1);
|
/* Run the test a few times in order to hit the first two
|
||||||
sh = (void*) (x-(sizeof(struct sdshdr)));
|
* SDS header types. */
|
||||||
test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0);
|
for (i = 0; i < 10; i++) {
|
||||||
oldfree = sh->free;
|
int oldlen = sdslen(x);
|
||||||
x[1] = '1';
|
x = sdsMakeRoomFor(x,step);
|
||||||
sdsIncrLen(x,1);
|
int type = x[-1]&SDS_TYPE_MASK;
|
||||||
test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1');
|
|
||||||
test_cond("sdsIncrLen() -- len", sh->len == 2);
|
test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
|
||||||
test_cond("sdsIncrLen() -- free", sh->free == oldfree-1);
|
if (type != SDS_TYPE_5) {
|
||||||
|
test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
|
||||||
|
oldfree = sdsavail(x);
|
||||||
|
}
|
||||||
|
p = x+oldlen;
|
||||||
|
for (j = 0; j < step; j++) {
|
||||||
|
p[j] = 'A'+j;
|
||||||
|
}
|
||||||
|
sdsIncrLen(x,step);
|
||||||
|
}
|
||||||
|
test_cond("sdsMakeRoomFor() content",
|
||||||
|
memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
|
||||||
|
test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
|
||||||
|
|
||||||
sdsfree(x);
|
sdsfree(x);
|
||||||
}
|
}
|
||||||
|
175
src/sds.h
175
src/sds.h
@ -35,32 +35,188 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef char *sds;
|
typedef char *sds;
|
||||||
|
|
||||||
struct sdshdr {
|
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||||
unsigned int len;
|
* However is here to document the layout of type 5 SDS strings. */
|
||||||
unsigned int free;
|
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||||
|
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||||
|
uint8_t len; /* used */
|
||||||
|
uint8_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||||
|
uint16_t len; /* used */
|
||||||
|
uint16_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||||
|
uint32_t len; /* used */
|
||||||
|
uint32_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||||
|
uint64_t len; /* used */
|
||||||
|
uint64_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
char buf[];
|
char buf[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SDS_TYPE_5 0
|
||||||
|
#define SDS_TYPE_8 1
|
||||||
|
#define SDS_TYPE_16 2
|
||||||
|
#define SDS_TYPE_32 3
|
||||||
|
#define SDS_TYPE_64 4
|
||||||
|
#define SDS_TYPE_MASK 7
|
||||||
|
#define SDS_TYPE_BITS 3
|
||||||
|
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
|
||||||
|
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||||
|
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||||
|
|
||||||
static inline size_t sdslen(const sds s) {
|
static inline size_t sdslen(const sds s) {
|
||||||
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
unsigned char flags = s[-1];
|
||||||
return sh->len;
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
return SDS_TYPE_5_LEN(flags);
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
return SDS_HDR(8,s)->len;
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
return SDS_HDR(16,s)->len;
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
return SDS_HDR(32,s)->len;
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
return SDS_HDR(64,s)->len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t sdsavail(const sds s) {
|
static inline size_t sdsavail(const sds s) {
|
||||||
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
unsigned char flags = s[-1];
|
||||||
return sh->free;
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_8: {
|
||||||
|
SDS_HDR_VAR(8,s);
|
||||||
|
return sh->alloc - sh->len;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_16: {
|
||||||
|
SDS_HDR_VAR(16,s);
|
||||||
|
return sh->alloc - sh->len;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_32: {
|
||||||
|
SDS_HDR_VAR(32,s);
|
||||||
|
return sh->alloc - sh->len;
|
||||||
|
}
|
||||||
|
case SDS_TYPE_64: {
|
||||||
|
SDS_HDR_VAR(64,s);
|
||||||
|
return sh->alloc - sh->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sdssetlen(sds s, size_t newlen) {
|
||||||
|
unsigned char flags = s[-1];
|
||||||
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
{
|
||||||
|
unsigned char *fp = ((unsigned char*)s)-1;
|
||||||
|
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
SDS_HDR(8,s)->len = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
SDS_HDR(16,s)->len = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
SDS_HDR(32,s)->len = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
SDS_HDR(64,s)->len = newlen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sdsinclen(sds s, size_t inc) {
|
||||||
|
unsigned char flags = s[-1];
|
||||||
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
{
|
||||||
|
unsigned char *fp = ((unsigned char*)s)-1;
|
||||||
|
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
|
||||||
|
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
SDS_HDR(8,s)->len += inc;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
SDS_HDR(16,s)->len += inc;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
SDS_HDR(32,s)->len += inc;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
SDS_HDR(64,s)->len += inc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sdsalloc() = sdsavail() + sdslen() */
|
||||||
|
static inline size_t sdsalloc(const sds s) {
|
||||||
|
unsigned char flags = s[-1];
|
||||||
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
return SDS_TYPE_5_LEN(flags);
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
return SDS_HDR(8,s)->alloc;
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
return SDS_HDR(16,s)->alloc;
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
return SDS_HDR(32,s)->alloc;
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
return SDS_HDR(64,s)->alloc;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||||
|
unsigned char flags = s[-1];
|
||||||
|
switch(flags&SDS_TYPE_MASK) {
|
||||||
|
case SDS_TYPE_5:
|
||||||
|
/* Nothing to do, this type has no total allocation info. */
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_8:
|
||||||
|
SDS_HDR(8,s)->alloc = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_16:
|
||||||
|
SDS_HDR(16,s)->alloc = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_32:
|
||||||
|
SDS_HDR(32,s)->alloc = newlen;
|
||||||
|
break;
|
||||||
|
case SDS_TYPE_64:
|
||||||
|
SDS_HDR(64,s)->alloc = newlen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(void);
|
sds sdsempty(void);
|
||||||
size_t sdslen(const sds s);
|
|
||||||
sds sdsdup(const sds s);
|
sds sdsdup(const sds s);
|
||||||
void sdsfree(sds s);
|
void sdsfree(sds s);
|
||||||
size_t sdsavail(const sds s);
|
|
||||||
sds sdsgrowzero(sds s, size_t len);
|
sds sdsgrowzero(sds s, size_t len);
|
||||||
sds sdscatlen(sds s, const void *t, size_t len);
|
sds sdscatlen(sds s, const void *t, size_t len);
|
||||||
sds sdscat(sds s, const char *t);
|
sds sdscat(sds s, const char *t);
|
||||||
@ -97,6 +253,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen);
|
|||||||
void sdsIncrLen(sds s, int incr);
|
void sdsIncrLen(sds s, int incr);
|
||||||
sds sdsRemoveFreeSpace(sds s);
|
sds sdsRemoveFreeSpace(sds s);
|
||||||
size_t sdsAllocSize(sds s);
|
size_t sdsAllocSize(sds s);
|
||||||
|
size_t sdsZmallocSize(sds s);
|
||||||
|
|
||||||
#ifdef REDIS_TEST
|
#ifdef REDIS_TEST
|
||||||
int sdsTest(int argc, char *argv[]);
|
int sdsTest(int argc, char *argv[]);
|
||||||
|
Loading…
Reference in New Issue
Block a user