diff --git a/src/StreamBuffer.cc b/src/StreamBuffer.cc index fdba24f..562ff9c 100644 --- a/src/StreamBuffer.cc +++ b/src/StreamBuffer.cc @@ -102,7 +102,7 @@ init(const void* s, ssize_t minsize) } // How the buffer looks like: -// |----free-----|####used####|--------00--------| +// |----junk-----|####used####|--------00--------| ///|<--- offs -->|<-- len --->|<- cap-offs-len ->| // 0 offs offs+len cap // |<-------------- minsize ---------------> @@ -254,39 +254,71 @@ replace(ssize_t remstart, ssize_t remlen, const void* ins, ssize_t inslen) if (inslen < 0) inslen = 0; size_t remend = remstart+remlen; size_t newlen = len+inslen-remlen; + +// How the buffer looks like before and after: +// |---junk---|##content_start##|/////////remove_this////////|##content_end##|0000| +// |<- offs ->|<-- remstart --->|<--------- remlen --------->| | | +// | |<--------------------- len ---------------------------------->| | +// 0 offs offs+remstart offs+remend offs+len cap +// +// If content size stays the same, no need to move old content: +// |---junk---|##content_start##|+++++++inserted_text++++++++|##content_end##|0000| +// |<----- inslen==remlen ----->| newlen==len +// +// If content shrinks (need to clear end of buffer): |< clear this >| +// |---junk---|##content_start##|inserted_text|##content_end##|00000000000000|0000| +// 0 offs |<- inslen -->| |< len-newlen >| +// offs+newlen offs+len +// +// If content grows but still fits (make sure to keep at least one 0 byte at end): +// |---junk---|##content_start##|++++++++inserted_text++++++++++|##content_end##|0| +// |<- offs ->|<--------------------- newlen ---------------------------------->| | +// 0 offs offs+newlen| +// |##content_start##|++++++++inserted_text++++++++++|##content_end##|0000000|0000| +// |<--------------------- newlen ---------------------------------->| | +// newlen offs+len +// +// Otherwise we need to copy to a new buffer. + + if (cap <= newlen) { - // buffer too short + // buffer too short, copy to new buffer size_t newcap; for (newcap = sizeof(local)*2; newcap <= newlen; newcap *= 2); char* newbuffer = new char[newcap]; - memcpy(newbuffer, buffer+offs, remstart); - memcpy(newbuffer+remstart, ins, inslen); - memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); - memset(newbuffer+newlen, 0, newcap-newlen); + memcpy(newbuffer, buffer+offs, remstart); // copy content start + memcpy(newbuffer+remstart, ins, inslen); // insert + memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); // copy content end + memset(newbuffer+newlen, 0, newcap-newlen); // clear buffer end if (buffer != local) - { - delete [] buffer; - } + delete[] buffer; buffer = newbuffer; cap = newcap; offs = 0; } else { - if (newlen+offs<=cap) + if (offs+newlen < cap) { - // move to start of buffer - memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend); - memcpy(buffer+offs+remstart, ins, inslen); - if (newlen