@@ -310,46 +310,72 @@ void outputStream::print_data(void* data, size_t len, bool with_ascii) {
310310 }
311311}
312312
313- stringStream::stringStream (size_t initial_size) : outputStream() {
314- buffer_length = initial_size;
315- buffer = NEW_C_HEAP_ARRAY (char , buffer_length, mtInternal);
316- buffer_pos = 0 ;
317- buffer_fixed = false ;
313+ stringStream::stringStream (size_t initial_capacity) :
314+ outputStream(),
315+ _buffer(_small_buffer),
316+ _written(0 ),
317+ _capacity(sizeof (_small_buffer)),
318+ _is_fixed(false )
319+ {
320+ if (initial_capacity > _capacity) {
321+ grow (initial_capacity);
322+ }
318323 zero_terminate ();
319324}
320325
321326// useful for output to fixed chunks of memory, such as performance counters
322- stringStream::stringStream (char * fixed_buffer, size_t fixed_buffer_size) : outputStream() {
323- buffer_length = fixed_buffer_size;
324- buffer = fixed_buffer;
325- buffer_pos = 0 ;
326- buffer_fixed = true ;
327+ stringStream::stringStream (char * fixed_buffer, size_t fixed_buffer_size) :
328+ outputStream(),
329+ _buffer(fixed_buffer),
330+ _written(0 ),
331+ _capacity(fixed_buffer_size),
332+ _is_fixed(true )
333+ {
327334 zero_terminate ();
328335}
329336
337+ // Grow backing buffer to desired capacity. Don't call for fixed buffers
338+ void stringStream::grow (size_t new_capacity) {
339+ assert (!_is_fixed, " Don't call for caller provided buffers" );
340+ assert (new_capacity > _capacity, " Sanity" );
341+ assert (new_capacity > sizeof (_small_buffer), " Sanity" );
342+ if (_buffer == _small_buffer) {
343+ _buffer = NEW_C_HEAP_ARRAY (char , new_capacity, mtInternal);
344+ _capacity = new_capacity;
345+ if (_written > 0 ) {
346+ ::memcpy (_buffer, _small_buffer, _written);
347+ }
348+ zero_terminate ();
349+ } else {
350+ _buffer = REALLOC_C_HEAP_ARRAY (char , _buffer, new_capacity, mtInternal);
351+ _capacity = new_capacity;
352+ }
353+ }
354+
330355void stringStream::write (const char * s, size_t len) {
331- size_t write_len = len; // number of non-null bytes to write
332- size_t end = buffer_pos + len + 1 ; // position after write and final '\0'
333- if (end > buffer_length) {
334- if (buffer_fixed) {
335- // if buffer cannot resize, silently truncate
336- end = buffer_length;
337- write_len = end - buffer_pos - 1 ; // leave room for the final '\0'
338- } else {
339- // For small overruns, double the buffer. For larger ones,
340- // increase to the requested size.
341- if (end < buffer_length * 2 ) {
342- end = buffer_length * 2 ;
343- }
344- buffer = REALLOC_C_HEAP_ARRAY (char , buffer, end, mtInternal);
345- buffer_length = end;
356+ assert (_capacity >= _written + 1 , " Sanity" );
357+ if (len == 0 ) {
358+ return ;
359+ }
360+ const size_t reasonable_max_len = 1 * G;
361+ if (len >= reasonable_max_len) {
362+ assert (false , " bad length? (" SIZE_FORMAT " )" , len);
363+ return ;
364+ }
365+ size_t write_len = 0 ;
366+ if (_is_fixed) {
367+ write_len = MIN2 (len, _capacity - _written - 1 );
368+ } else {
369+ write_len = len;
370+ size_t needed = _written + len + 1 ;
371+ if (needed > _capacity) {
372+ grow (MAX2 (needed, _capacity * 2 ));
346373 }
347374 }
348- // invariant: buffer is always null-terminated
349- guarantee (buffer_pos + write_len + 1 <= buffer_length, " stringStream oob" );
375+ assert (_written + write_len + 1 <= _capacity, " stringStream oob" );
350376 if (write_len > 0 ) {
351- memcpy (buffer + buffer_pos , s, write_len);
352- buffer_pos += write_len;
377+ :: memcpy (_buffer + _written , s, write_len);
378+ _written += write_len;
353379 zero_terminate ();
354380 }
355381
@@ -360,21 +386,22 @@ void stringStream::write(const char* s, size_t len) {
360386}
361387
362388void stringStream::zero_terminate () {
363- assert (buffer != NULL &&
364- buffer_pos < buffer_length , " sanity" );
365- buffer[buffer_pos ] = ' \0 ' ;
389+ assert (_buffer != NULL &&
390+ _written < _capacity , " sanity" );
391+ _buffer[_written ] = ' \0 ' ;
366392}
367393
368394void stringStream::reset () {
369- buffer_pos = 0 ; _precount = 0 ; _position = 0 ;
395+ _written = 0 ; _precount = 0 ; _position = 0 ;
396+ _newlines = 0 ;
370397 zero_terminate ();
371398}
372399
373400char * stringStream::as_string (bool c_heap) const {
374401 char * copy = c_heap ?
375- NEW_C_HEAP_ARRAY (char , buffer_pos + 1 , mtInternal) : NEW_RESOURCE_ARRAY (char , buffer_pos + 1 );
376- strncpy (copy, buffer, buffer_pos );
377- copy[buffer_pos ] = 0 ; // terminating null
402+ NEW_C_HEAP_ARRAY (char , _written + 1 , mtInternal) : NEW_RESOURCE_ARRAY (char , _written + 1 );
403+ ::memcpy (copy, _buffer, _written );
404+ copy[_written ] = 0 ; // terminating null
378405 if (c_heap) {
379406 // Need to ensure our content is written to memory before we return
380407 // the pointer to it.
@@ -384,8 +411,8 @@ char* stringStream::as_string(bool c_heap) const {
384411}
385412
386413stringStream::~stringStream () {
387- if (buffer_fixed == false && buffer != NULL ) {
388- FREE_C_HEAP_ARRAY (char , buffer );
414+ if (!_is_fixed && _buffer != _small_buffer ) {
415+ FREE_C_HEAP_ARRAY (char , _buffer );
389416 }
390417}
391418
0 commit comments