From d0b2a9b2234afe82d6ed42a8c45f8221ede25d8f Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 2 Nov 2011 16:50:59 +0100 Subject: [PATCH] sdsMakeRoomFor() exposed as public API. sdsIncrLen() added. Both the changes make it possible to copy stuff from a system call to an sds buffer without the need of an additional buffer and copying overhead. --- src/sds.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/sds.h | 4 ++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/sds.c b/src/sds.c index fc104a4a..c3a0ccb9 100644 --- a/src/sds.c +++ b/src/sds.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "sds.h" #include "zmalloc.h" @@ -107,7 +108,7 @@ void sdsclear(sds s) { * * Note: this does not change the *size* of the sds string as returned * by sdslen(), but only the free buffer space we have. */ -static sds sdsMakeRoomFor(sds s, size_t addlen) { +sds sdsMakeRoomFor(sds s, size_t addlen) { struct sdshdr *sh, *newsh; size_t free = sdsavail(s); size_t len, newlen; @@ -127,6 +128,37 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) { return newsh->buf; } +/* Increment the sds length and decrements the left free space at the + * end of the string accordingly to 'incr'. Also set the null term + * in the new end of the string. + * + * This function is used in order to fix the string length after the + * user calls sdsMakeRoomFor(), writes something after the end of + * the current string, and finally needs to set the new length. + * + * Note: it is possible to use a negative increment in order to + * right-trim the string. + * + * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the + * following schema to cat bytes coming from the kerenl to the end of an + * sds string new things without copying into an intermediate buffer: + * + * oldlen = sdslen(s); + * s = sdsMakeRoomFor(s, BUFFER_SIZE); + * nread = read(fd, s+oldlen, BUFFER_SIZE); + * ... check for nread <= 0 and handle it ... + * sdsIncrLen(s, nhread); + */ +void sdsIncrLen(sds s, int incr) { + struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); + + assert(sh->free >= incr); + sh->len += incr; + sh->free -= incr; + assert(sh->free >= 0); + s[sh->len] = '\0'; +} + /* Grow the sds to have the specified length. Bytes that were not part of * the original length of the sds will be set to zero. */ sds sdsgrowzero(sds s, size_t len) { @@ -615,6 +647,7 @@ sds sdsmapchars(sds s, char *from, char *to, size_t setlen) { int main(void) { { + struct sdshdr *sh; sds x = sdsnew("foo"), y; test_cond("Create a string and obtain the length", @@ -694,7 +727,26 @@ int main(void) { x = sdsnew("aar"); y = sdsnew("bar"); test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) + + { + int oldfree; + + sdsfree(x); + x = sdsnew("0"); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); + x = sdsMakeRoomFor(x,1); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); + oldfree = sh->free; + x[1] = '1'; + sdsIncrLen(x,1); + test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); + test_cond("sdsIncrLen() -- len", sh->len == 2); + test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); + } } test_report() + return 0; } #endif diff --git a/src/sds.h b/src/sds.h index 6e5684ee..eff1b03e 100644 --- a/src/sds.h +++ b/src/sds.h @@ -88,4 +88,8 @@ sds *sdssplitargs(char *line, int *argc); void sdssplitargs_free(sds *argv, int argc); sds sdsmapchars(sds s, char *from, char *to, size_t setlen); +/* Low level functions exposed to the user API */ +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); + #endif -- 2.45.2