
This is an attempt to use the refcount feature of the sds.c fork provided in the Pull Request #2509. A new type, SDS_TYPE_5 is introduced having a one byte header with just the string length, without information about the available additional length at the end of the string (this means that sdsMakeRoomFor() will be required each time we want to append something, since the string will always report to have 0 bytes available). More work needed in order to avoid common SDS functions will pay the cost of this type. For example both sdscatprintf() and sdscatfmt() should try to upgrade to SDS_TYPE_8 ASAP when appending chars.
263 lines
8.3 KiB
C
263 lines
8.3 KiB
C
/* SDSLib, A C dynamic strings library
|
|
*
|
|
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Redis nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef __SDS_H
|
|
#define __SDS_H
|
|
|
|
#define SDS_MAX_PREALLOC (1024*1024)
|
|
|
|
#include <sys/types.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
|
|
typedef char *sds;
|
|
|
|
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
|
* However is here to document the layout of type 5 SDS strings. */
|
|
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[];
|
|
};
|
|
|
|
#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) {
|
|
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)->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) {
|
|
unsigned char flags = s[-1];
|
|
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 sdsnew(const char *init);
|
|
sds sdsempty(void);
|
|
sds sdsdup(const sds s);
|
|
void sdsfree(sds s);
|
|
sds sdsgrowzero(sds s, size_t len);
|
|
sds sdscatlen(sds s, const void *t, size_t len);
|
|
sds sdscat(sds s, const char *t);
|
|
sds sdscatsds(sds s, const sds t);
|
|
sds sdscpylen(sds s, const char *t, size_t len);
|
|
sds sdscpy(sds s, const char *t);
|
|
|
|
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
|
#ifdef __GNUC__
|
|
sds sdscatprintf(sds s, const char *fmt, ...)
|
|
__attribute__((format(printf, 2, 3)));
|
|
#else
|
|
sds sdscatprintf(sds s, const char *fmt, ...);
|
|
#endif
|
|
|
|
sds sdscatfmt(sds s, char const *fmt, ...);
|
|
sds sdstrim(sds s, const char *cset);
|
|
void sdsrange(sds s, int start, int end);
|
|
void sdsupdatelen(sds s);
|
|
void sdsclear(sds s);
|
|
int sdscmp(const sds s1, const sds s2);
|
|
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
|
void sdsfreesplitres(sds *tokens, int count);
|
|
void sdstolower(sds s);
|
|
void sdstoupper(sds s);
|
|
sds sdsfromlonglong(long long value);
|
|
sds sdscatrepr(sds s, const char *p, size_t len);
|
|
sds *sdssplitargs(const char *line, int *argc);
|
|
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
|
sds sdsjoin(char **argv, int argc, char *sep);
|
|
|
|
/* Low level functions exposed to the user API */
|
|
sds sdsMakeRoomFor(sds s, size_t addlen);
|
|
void sdsIncrLen(sds s, int incr);
|
|
sds sdsRemoveFreeSpace(sds s);
|
|
size_t sdsAllocSize(sds s);
|
|
size_t sdsZmallocSize(sds s);
|
|
|
|
#ifdef REDIS_TEST
|
|
int sdsTest(int argc, char *argv[]);
|
|
#endif
|
|
|
|
#endif
|