SDS refcounted type

Former-commit-id: 361d0308febd5da0c7291469ea7e922e7147c1d6
This commit is contained in:
John Sully 2019-12-16 20:16:51 -05:00
parent 7cc892284f
commit 4d7b05baf3
2 changed files with 74 additions and 3 deletions

View File

@ -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';

View File

@ -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);