C++ wrapper classes for SDS

Former-commit-id: 45817db8c3a86815945359113dcbccfde4257ce5
This commit is contained in:
John Sully 2020-01-01 19:13:48 -05:00
parent 1790b02984
commit 20e529c441
2 changed files with 176 additions and 5 deletions

View File

@ -53,11 +53,18 @@ static inline int sdsHdrSize(char type) {
return sizeof(struct sdshdr32); return sizeof(struct sdshdr32);
case SDS_TYPE_64: case SDS_TYPE_64:
return sizeof(struct sdshdr64); return sizeof(struct sdshdr64);
case SDS_TYPE_REFCOUNTED:
return sizeof(struct sdshdrrefcount);
} }
return 0; 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) if (string_size < 1<<5)
return SDS_TYPE_5; return SDS_TYPE_5;
if (string_size < 1<<8) 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 * 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 * 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, ssize_t initlen) {
void *sh; void *sh;
sds s; sds s;
char type = sdsReqType(initlen); char type = sdsReqType(initlen);
if (initlen < 0)
initlen = -initlen;
/* Empty strings are usually created in order to append. Use type 8 /* Empty strings are usually created in order to append. Use type 8
* since type 5 is not good at this. */ * since type 5 is not good at this. */
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; 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; *fp = type;
break; break;
} }
case SDS_TYPE_REFCOUNTED: {
SDS_HDR_VAR_REFCOUNTED(s);
sh->len = initlen;
sh->refcount = 1;
*fp = type;
break;
}
} }
if (initlen && init) if (initlen && init)
memcpy(s, init, initlen); memcpy(s, init, initlen);
@ -161,9 +177,25 @@ sds sdsdup(const char *s) {
return sdsnewlen(s, sdslen(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. */ /* Free an sds string. No operation is performed if 's' is NULL. */
void sdsfree(const char *s) { void sdsfree(const char *s) {
if (s == NULL) return; 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])); s_free((char*)s-sdsHdrSize(s[-1]));
} }
@ -368,6 +400,11 @@ void sdsIncrLen(sds s, ssize_t incr) {
len = (sh->len += incr); len = (sh->len += incr);
break; break;
} }
case SDS_TYPE_REFCOUNTED: {
SDS_HDR_VAR_REFCOUNTED(s);
len = (sh->len += incr);
break;
}
default: len = 0; /* Just to avoid compilation warnings. */ default: len = 0; /* Just to avoid compilation warnings. */
} }
s[len] = '\0'; s[len] = '\0';
@ -787,7 +824,7 @@ void sdstoupper(sds s) {
* If two strings share exactly the same prefix, but one of the two has * If two strings share exactly the same prefix, but one of the two has
* additional characters, the longer string is considered to be greater than * additional characters, the longer string is considered to be greater than
* the smaller one. */ * the smaller one. */
int sdscmp(const sds s1, const sds s2) { int sdscmp(const char *s1, const char *s2) {
size_t l1, l2, minlen; size_t l1, l2, minlen;
int cmp; int cmp;

138
src/sds.h
View File

@ -91,15 +91,27 @@ struct __attribute__ ((__packed__)) sdshdr64 {
#endif #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_5 0
#define SDS_TYPE_8 1 #define SDS_TYPE_8 1
#define SDS_TYPE_16 2 #define SDS_TYPE_16 2
#define SDS_TYPE_32 3 #define SDS_TYPE_32 3
#define SDS_TYPE_64 4 #define SDS_TYPE_64 4
#define SDS_TYPE_REFCOUNTED 5
#define SDS_TYPE_MASK 7 #define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3 #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(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(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) #define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
static inline size_t sdslen(const char *s) { 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; return SDS_HDR(32,s)->len;
case SDS_TYPE_64: case SDS_TYPE_64:
return SDS_HDR(64,s)->len; return SDS_HDR(64,s)->len;
case SDS_TYPE_REFCOUNTED:
return SDS_HDR_REFCOUNTED(s)->len;
} }
} }
return 0; return 0;
@ -148,6 +162,9 @@ static inline size_t sdsavail(const char * s) {
SDS_HDR_VAR(64,s); SDS_HDR_VAR(64,s);
return sh->alloc - sh->len; return sh->alloc - sh->len;
} }
case SDS_TYPE_REFCOUNTED: {
return 0; // immutable
}
} }
return 0; return 0;
} }
@ -173,6 +190,9 @@ static inline void sdssetlen(sds s, size_t newlen) {
case SDS_TYPE_64: case SDS_TYPE_64:
SDS_HDR(64,s)->len = newlen; SDS_HDR(64,s)->len = newlen;
break; 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: case SDS_TYPE_64:
SDS_HDR(64,s)->len += inc; SDS_HDR(64,s)->len += inc;
break; 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; return SDS_HDR(32,s)->alloc;
case SDS_TYPE_64: case SDS_TYPE_64:
return SDS_HDR(64,s)->alloc; return SDS_HDR(64,s)->alloc;
case SDS_TYPE_REFCOUNTED:
return SDS_HDR_REFCOUNTED(s)->len;
} }
return 0; return 0;
} }
@ -237,13 +262,22 @@ static inline void sdssetalloc(sds s, size_t newlen) {
case SDS_TYPE_64: case SDS_TYPE_64:
SDS_HDR(64,s)->alloc = newlen; SDS_HDR(64,s)->alloc = newlen;
break; 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 sdsnew(const char *init);
sds sdsempty(void); sds sdsempty(void);
sds sdsdup(const char *s); sds sdsdup(const char *s);
sds sdsdupshared(const char *s);
void sdsfree(const char *s); void sdsfree(const char *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);
@ -265,7 +299,7 @@ sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, ssize_t start, ssize_t end); void sdsrange(sds s, ssize_t start, ssize_t end);
void sdsupdatelen(sds s); void sdsupdatelen(sds s);
void sdsclear(sds s); void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2); int sdscmp(const char *s1, const char *s2);
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count); sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count); void sdsfreesplitres(sds *tokens, int count);
void sdstolower(sds s); void sdstolower(sds s);
@ -298,6 +332,106 @@ int sdsTest(int argc, char *argv[]);
#ifdef __cplusplus #ifdef __cplusplus
} }
class sdsview
{
protected:
sds m_str = nullptr;
sdsview() = default; // Not allowed to create a sdsview directly with a nullptr
public:
sdsview(sds str)
: m_str(str)
{}
sdsview(const char *str)
: m_str((sds)str)
{}
bool operator<(const sdsview &other) const
{
return sdscmp(m_str, other.m_str) < 0;
}
bool operator==(const sdsview &other) const
{
return sdscmp(m_str, other.m_str) == 0;
}
bool operator==(const char *other) const
{
return sdscmp(m_str, other) == 0;
}
char operator[](size_t idx) const
{
return m_str[idx];
}
size_t size() const
{
return sdslen(m_str);
}
const char *get() const { return m_str; }
explicit operator const char*() const { return m_str; }
};
class sdsstring : public sdsview
{
public:
sdsstring() = default;
explicit sdsstring(sds str)
: sdsview(str)
{}
sdsstring(const sdsstring &other)
: sdsview(sdsdup(other.m_str))
{}
sdsstring(sdsstring &&other)
: sdsview(other.m_str)
{
other.m_str = nullptr;
}
~sdsstring()
{
sdsfree(m_str);
}
};
class sdsimmutablestring : public sdsstring
{
public:
sdsimmutablestring() = default;
explicit sdsimmutablestring(sds str)
: sdsstring(str)
{}
explicit sdsimmutablestring(const char *str)
: sdsstring((sds)str)
{}
sdsimmutablestring(const sdsimmutablestring &other)
: sdsstring(sdsdupshared(other.m_str))
{}
sdsimmutablestring(sdsimmutablestring &&other)
: sdsstring(other.m_str)
{
other.m_str = nullptr;
}
auto &operator=(const sdsimmutablestring &other)
{
sdsfree(m_str);
m_str = sdsdupshared(other.m_str);
return *this;
}
};
#endif #endif
#endif #endif