diff --git a/src/sds.c b/src/sds.c index eafa13c29..ff633c8bc 100644 --- a/src/sds.c +++ b/src/sds.c @@ -248,16 +248,23 @@ sds sdsMakeRoomFor(sds s, size_t addlen) { sds sdsRemoveFreeSpace(sds s) { void *sh, *newsh; char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; + int hdrlen, oldhdrlen = sdsHdrSize(oldtype); size_t len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); + sh = (char*)s-oldhdrlen; + /* Check what would be the minimum SDS header that is just good enough to + * fit this string. */ type = sdsReqType(len); hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+len+1); + + /* 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+hdrlen; + s = (char*)newsh+oldhdrlen; } else { newsh = s_malloc(hdrlen+len+1); if (newsh == NULL) return NULL;