SDS refcounted type
Former-commit-id: 361d0308febd5da0c7291469ea7e922e7147c1d6
This commit is contained in:
parent
7cc892284f
commit
4d7b05baf3
41
src/sds.c
41
src/sds.c
@ -53,11 +53,18 @@ static inline int sdsHdrSize(char type) {
|
||||
return sizeof(struct sdshdr32);
|
||||
case SDS_TYPE_64:
|
||||
return sizeof(struct sdshdr64);
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
return sizeof(struct sdshdrrefcount);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char sdsReqType(size_t string_size) {
|
||||
static inline char sdsReqType(ssize_t string_size) {
|
||||
if (string_size < 0){
|
||||
string_size = -string_size;
|
||||
if (string_size < 1<<16)
|
||||
return SDS_TYPE_REFCOUNTED;
|
||||
}
|
||||
if (string_size < 1<<5)
|
||||
return SDS_TYPE_5;
|
||||
if (string_size < 1<<8)
|
||||
@ -86,10 +93,12 @@ static inline char sdsReqType(size_t string_size) {
|
||||
* You can print the string with printf() as there is an implicit \0 at the
|
||||
* 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. */
|
||||
sds sdsnewlen(const void *init, size_t initlen) {
|
||||
sds sdsnewlen(const void *init, ssize_t initlen) {
|
||||
void *sh;
|
||||
sds s;
|
||||
char type = sdsReqType(initlen);
|
||||
if (initlen < 0)
|
||||
initlen = -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;
|
||||
@ -137,6 +146,13 @@ sds sdsnewlen(const void *init, size_t initlen) {
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_REFCOUNTED: {
|
||||
SDS_HDR_VAR_REFCOUNTED(s);
|
||||
sh->len = initlen;
|
||||
sh->refcount = 1;
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (initlen && init)
|
||||
memcpy(s, init, initlen);
|
||||
@ -161,9 +177,25 @@ sds sdsdup(const char *s) {
|
||||
return sdsnewlen(s, sdslen(s));
|
||||
}
|
||||
|
||||
sds sdsdupshared(const char *s) {
|
||||
unsigned char flags = s[-1];
|
||||
if ((flags & SDS_TYPE_MASK) != SDS_TYPE_REFCOUNTED)
|
||||
return sdsnewlen(s, -sdslen(s));
|
||||
SDS_HDR_VAR_REFCOUNTED(s);
|
||||
__atomic_fetch_add(&sh->refcount, 1, __ATOMIC_RELAXED);
|
||||
return (sds)s;
|
||||
}
|
||||
|
||||
/* Free an sds string. No operation is performed if 's' is NULL. */
|
||||
void sdsfree(const char *s) {
|
||||
if (s == NULL) return;
|
||||
unsigned char flags = s[-1];
|
||||
if ((flags & SDS_TYPE_MASK) == SDS_TYPE_REFCOUNTED)
|
||||
{
|
||||
SDS_HDR_VAR_REFCOUNTED(s);
|
||||
if (__atomic_fetch_sub(&sh->refcount, 1, __ATOMIC_RELAXED) > 1)
|
||||
return;
|
||||
}
|
||||
s_free((char*)s-sdsHdrSize(s[-1]));
|
||||
}
|
||||
|
||||
@ -368,6 +400,11 @@ void sdsIncrLen(sds s, ssize_t incr) {
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_REFCOUNTED: {
|
||||
SDS_HDR_VAR_REFCOUNTED(s);
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
default: len = 0; /* Just to avoid compilation warnings. */
|
||||
}
|
||||
s[len] = '\0';
|
||||
|
36
src/sds.h
36
src/sds.h
@ -91,15 +91,27 @@ struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct __attribute__ ((__packed__)) sdshdrrefcount {
|
||||
uint64_t len; /* used */
|
||||
uint16_t refcount;
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
#ifndef __cplusplus
|
||||
char buf[];
|
||||
#endif
|
||||
};
|
||||
|
||||
#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_REFCOUNTED 5
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)(((void*)((s)-(sizeof(struct sdshdr##T)))));
|
||||
#define SDS_HDR_VAR_REFCOUNTED(s) struct sdshdrrefcount *sh = (struct sdshdrrefcount *)(((void*)((s)-(sizeof(struct sdshdrrefcount)))));
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_HDR_REFCOUNTED(s) ((struct sdshdrrefcount *)((s)-(sizeof(struct sdshdrrefcount))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const char *s) {
|
||||
@ -121,6 +133,8 @@ static inline size_t sdslen(const char *s) {
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
return SDS_HDR_REFCOUNTED(s)->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -148,6 +162,9 @@ static inline size_t sdsavail(const char * s) {
|
||||
SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_REFCOUNTED: {
|
||||
return 0; // immutable
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -173,6 +190,9 @@ static inline void sdssetlen(sds s, size_t newlen) {
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
SDS_HDR_REFCOUNTED(s)->len = newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,6 +218,9 @@ static inline void sdsinclen(sds s, size_t inc) {
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
SDS_HDR_REFCOUNTED(s)->len += inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,6 +238,8 @@ static inline size_t sdsalloc(const sds s) {
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
return SDS_HDR_REFCOUNTED(s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -237,13 +262,22 @@ static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_REFCOUNTED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
static inline int sdsisshared(const char *s)
|
||||
{
|
||||
unsigned char flags = s[-1];
|
||||
return ((flags & SDS_TYPE_MASK) == SDS_TYPE_REFCOUNTED);
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, ssize_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const char *s);
|
||||
sds sdsdupshared(const char *s);
|
||||
void sdsfree(const char *s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
|
Loading…
x
Reference in New Issue
Block a user