Skip to content

Commit

Permalink
Upd: sds
Browse files Browse the repository at this point in the history
  • Loading branch information
jcorporation committed Sep 23, 2024
1 parent 7b552bf commit 243fcbf
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 121 deletions.
248 changes: 129 additions & 119 deletions dist/sds/sds.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,46 +388,20 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
*
* 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. */
sds sdsRemoveFreeSpace(sds s) {
void *sh, *newsh;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
size_t len = sdslen(s);
size_t avail = sdsavail(s);
sh = (char*)s-oldhdrlen;

/* Return ASAP if there is no space left. */
if (avail == 0) return s;

/* Check what would be the minimum SDS header that is just good enough to
* fit this string. */
type = sdsReqType(len);
hdrlen = sdsHdrSize(type);

/* If the type is the same, or at least a large enough type is still
* required, we just realloc(), letting the allocator to do the copy
* only if really needed. Otherwise if the change is huge, we manually
* reallocate the string to use the different header type. */
if (oldtype==type || type > SDS_TYPE_8) {
newsh = s_realloc(sh, oldhdrlen+len+1);
if (newsh == NULL) return NULL;
s = (char*)newsh+oldhdrlen;
} else {
newsh = s_malloc(hdrlen+len+1);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len+1);
s_free(sh);
s = (char*)newsh+hdrlen;
s[-1] = type;
sdssetlen(s, len);
}
sdssetalloc(s, len);
return s;
sds sdsRemoveFreeSpace(sds s, int would_regrow) {
return sdsResize(s, sdslen(s), would_regrow);
}

/* Resize the allocation, this can make the allocation bigger or smaller,
* if the size is smaller than currently used len, the data will be truncated */
sds sdsResize(sds s, size_t size) {
* if the size is smaller than currently used len, the data will be truncated.
*
* The when the would_regrow argument is set to 1, it prevents the use of
* SDS_TYPE_5, which is desired when the sds is likely to be changed again.
*
* The sdsAlloc size will be set to the requested size regardless of the actual
* allocation size, this is done in order to avoid repeated calls to this
* function when the caller detects that it has excess space. */
sds sdsResize(sds s, size_t size, int would_regrow) {
void *sh, *newsh;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
Expand All @@ -443,21 +417,25 @@ sds sdsResize(sds s, size_t size) {
/* Check what would be the minimum SDS header that is just good enough to
* fit this string. */
type = sdsReqType(size);
/* Don't use type 5, it is not good for strings that are resized. */
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
if (would_regrow) {
/* Don't use type 5, it is not good for strings that are expected to grow back. */
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
}
hdrlen = sdsHdrSize(type);

/* If the type is the same, or can hold the size in it with low overhead
* (larger than SDS_TYPE_8), we just realloc(), letting the allocator
* to do the copy only if really needed. Otherwise if the change is
* huge, we manually reallocate the string to use the different header
* type. */
if (oldtype==type || (type < oldtype && type > SDS_TYPE_8)) {
newsh = s_realloc(sh, oldhdrlen+size+1);
int use_realloc = (oldtype==type || (type < oldtype && type > SDS_TYPE_8));
size_t newlen = use_realloc ? oldhdrlen+size+1 : hdrlen+size+1;
if (use_realloc) {
newsh = s_realloc(sh, newlen);
if (newsh == NULL) return NULL;
s = (char*)newsh+oldhdrlen;
} else {
newsh = s_malloc(hdrlen+size+1);
newsh = s_malloc(newlen);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len);
s_free(sh);
Expand Down Expand Up @@ -621,91 +599,123 @@ sds sdscpy(sds s, const char *t) {
return sdscpylen(s, t, strlen(t));
}

/* Helper for sdscatlonglong() doing the actual number -> string
* conversion. 's' must point to a string with room for at least
* SDS_LLSTR_SIZE bytes.
*
* The function returns the length of the null-terminated string
* representation stored at 's'. */
#define SDS_LLSTR_SIZE 21
int sdsll2str(char *s, long long value) {
char *p, aux;
unsigned long long v;
size_t l;

/* Generate the string representation, this method produces
* a reversed string. */
if (value < 0) {
/* Since v is unsigned, if value==LLONG_MIN then
* -LLONG_MIN will overflow. */
if (value != LLONG_MIN) {
v = -value;
} else {
v = ((unsigned long long)LLONG_MAX) + 1;
/* Return the number of digits of 'v' when converted to string in radix 10.
* See sdsll2string() for more information. */
uint32_t digits10(uint64_t v) {
if (v < 10) return 1;
if (v < 100) return 2;
if (v < 1000) return 3;
if (v < 1000000000000UL) {
if (v < 100000000UL) {
if (v < 1000000) {
if (v < 10000) return 4;
return 5 + (v >= 100000);
}
return 7 + (v >= 10000000UL);
}
} else {
v = value;
if (v < 10000000000UL) {
return 9 + (v >= 1000000000UL);
}
return 11 + (v >= 100000000000UL);
}
return 12 + digits10(v / 1000000000000UL);
}

/* Convert a unsigned long long into a string. Returns the number of
* characters needed to represent the number.
* If the buffer is not big enough to store the string, 0 is returned.
*
* Based on the following article (that apparently does not provide a
* novel approach but only publicizes an already used technique):
*
* https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 */
int sdsull2string(char *dst, size_t dstlen, unsigned long long value) {
static const char digits[201] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";

/* Check length. */
uint32_t length = digits10(value);
if (length >= dstlen) goto err;;

/* Null term. */
uint32_t next = length - 1;
dst[next + 1] = '\0';
while (value >= 100) {
int const i = (value % 100) * 2;
value /= 100;
dst[next] = digits[i + 1];
dst[next - 1] = digits[i];
next -= 2;
}

p = s;
do {
*p++ = '0'+(v%10);
v /= 10;
} while(v);
if (value < 0) *p++ = '-';

/* Compute length and add null term. */
l = p-s;
*p = '\0';

/* Reverse the string. */
p--;
while(s < p) {
aux = *s;
*s = *p;
*p = aux;
s++;
p--;
/* Handle last 1-2 digits. */
if (value < 10) {
dst[next] = '0' + (uint32_t) value;
} else {
int i = (uint32_t) value * 2;
dst[next] = digits[i + 1];
dst[next - 1] = digits[i];
}
return l;
return length;
err:
/* force add Null termination */
if (dstlen > 0)
dst[0] = '\0';
return 0;
}

/* Identical sdsll2str(), but for unsigned long long type. */
int sdsull2str(char *s, unsigned long long v) {
char *p, aux;
size_t l;

/* Generate the string representation, this method produces
* a reversed string. */
p = s;
do {
*p++ = '0'+(v%10);
v /= 10;
} while(v);

/* Compute length and add null term. */
l = p-s;
*p = '\0';

/* Reverse the string. */
p--;
while(s < p) {
aux = *s;
*s = *p;
*p = aux;
s++;
p--;
/* Convert a long long into a string. Returns the number of
* characters needed to represent the number.
* If the buffer is not big enough to store the string, 0 is returned. */
int sdsll2string(char *dst, size_t dstlen, long long svalue) {
unsigned long long value;
int negative = 0;

/* The ull2string function with 64bit unsigned integers for simplicity, so
* we convert the number here and remember if it is negative. */
if (svalue < 0) {
if (svalue != LLONG_MIN) {
value = -svalue;
} else {
value = ((unsigned long long) LLONG_MAX)+1;
}
if (dstlen < 2)
goto err;
negative = 1;
dst[0] = '-';
dst++;
dstlen--;
} else {
value = svalue;
}
return l;

/* Converts the unsigned long long value to string*/
int length = sdsull2string(dst, dstlen, value);
if (length == 0) return 0;
return length + negative;

err:
/* force add Null termination */
if (dstlen > 0)
dst[0] = '\0';
return 0;
}


/* Bytes needed for long -> str + '\0' */
#define SDS_LLSTR_SIZE 21

/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds sdsfromlonglong(long long value) {
char buf[SDS_LLSTR_SIZE];
int len = sdsll2str(buf,value);
int len = sdsll2string(buf,sizeof(buf),value);

return sdsnewlen(buf,len);
}
Expand Down Expand Up @@ -853,7 +863,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
num = va_arg(ap,long long);
{
char buf[SDS_LLSTR_SIZE];
l = sdsll2str(buf,num);
l = sdsll2string(buf,sizeof(buf),num);
if (sdsavail(s) < l) {
s = sdsMakeRoomFor(s,l);
}
Expand All @@ -873,7 +883,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
unum = va_arg(ap,unsigned long long);
{
char buf[SDS_LLSTR_SIZE];
l = sdsull2str(buf,unum);
l = sdsull2string(buf,sizeof(buf),unum);
if (sdsavail(s) < l) {
s = sdsMakeRoomFor(s,l);
}
Expand Down Expand Up @@ -1565,27 +1575,27 @@ int sdsTest(void) {

/* Test sdsresize - extend */
x = sdsnew("1234567890123456789012345678901234567890");
x = sdsResize(x, 200);
x = sdsResize(x, 200, 1);
test_cond("sdsrezie() expand len", sdslen(x) == 40);
test_cond("sdsrezie() expand strlen", strlen(x) == 40);
test_cond("sdsrezie() expand alloc", sdsalloc(x) == 200);
/* Test sdsresize - trim free space */
x = sdsResize(x, 80);
x = sdsResize(x, 80, 1);
test_cond("sdsrezie() shrink len", sdslen(x) == 40);
test_cond("sdsrezie() shrink strlen", strlen(x) == 40);
test_cond("sdsrezie() shrink alloc", sdsalloc(x) == 80);
/* Test sdsresize - crop used space */
x = sdsResize(x, 30);
x = sdsResize(x, 30, 1);
test_cond("sdsrezie() crop len", sdslen(x) == 30);
test_cond("sdsrezie() crop strlen", strlen(x) == 30);
test_cond("sdsrezie() crop alloc", sdsalloc(x) == 30);
/* Test sdsresize - extend to different class */
x = sdsResize(x, 400);
x = sdsResize(x, 400, 1);
test_cond("sdsrezie() expand len", sdslen(x) == 30);
test_cond("sdsrezie() expand strlen", strlen(x) == 30);
test_cond("sdsrezie() expand alloc", sdsalloc(x) == 400);
/* Test sdsresize - shrink to different class */
x = sdsResize(x, 4);
x = sdsResize(x, 4, 1);
test_cond("sdsrezie() crop len", sdslen(x) == 4);
test_cond("sdsrezie() crop strlen", strlen(x) == 4);
test_cond("sdsrezie() crop alloc", sdsalloc(x) == 4);
Expand Down
4 changes: 2 additions & 2 deletions dist/sds/sds.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ int sdsneedsrepr(const sds s);
/* Low level functions exposed to the user API */
sds sdsMakeRoomFor(sds s, size_t addlen);
void sdsIncrLen(sds s, ssize_t incr);
sds sdsRemoveFreeSpace(sds s);
sds sdsResize(sds s, size_t size);
sds sdsRemoveFreeSpace(sds s, int would_regrow);
sds sdsResize(sds s, size_t size, int would_regrow);
size_t sdsAllocSize(sds s);
void *sdsAllocPtr(sds s);

Expand Down

0 comments on commit 243fcbf

Please sign in to comment.