diff --git a/cmdline/stream.c b/cmdline/stream.c index be5b9656..aadf917a 100644 --- a/cmdline/stream.c +++ b/cmdline/stream.c @@ -711,40 +711,33 @@ int sgetbs(STREAM* f, char* str, size_t size) return sread(f, str, len); } -int swrite(const void* void_data, size_t size, STREAM* f) +int swrite_uncached(const void* void_data, size_t size, STREAM* f) { const unsigned char* data = void_data; - /* if there is enough space in memory */ - if (sptrlookup(f, size)) { - /* optimized version with all the data in memory */ - unsigned char* pos = sptrget(f); + while (size) { + size_t available; - /** - * Update the crc *before* writing the data in the buffer - * - * This must be done before the memory write, - * to be able to detect memory errors on the buffer, - * happening before we write it on the file. - */ - if (f->flags & STREAM_FLAGS_CRC) { - f->crc_stream = crc32c_plain(f->crc_stream, data, size); - } - - /* copy it */ - while (size--) - *pos++ = *data++; - - sptrset(f, pos); - } else { - /* standard version using sputc() */ - while (size--) { - if (sputc(*data++, f) != 0) { + if (f->pos == f->end) { + if (sflush(f) != 0) { /* LCOV_EXCL_START */ return -1; /* LCOV_EXCL_STOP */ } } + + available = (size_t)(f->end - f->pos); + if (available > size) + available = size; + + /* compute the independent CRC before copying to detect buffer corruption */ + if (f->flags & STREAM_FLAGS_CRC) + f->crc_stream = crc32c_plain(f->crc_stream, data, available); + + memcpy(f->pos, data, available); + f->pos += available; + data += available; + size -= available; } return 0; diff --git a/cmdline/stream.h b/cmdline/stream.h index 49a78b11..9a963612 100644 --- a/cmdline/stream.h +++ b/cmdline/stream.h @@ -395,10 +395,29 @@ static inline int sputeol(STREAM* s) } /** - * Write a sized string. + * \internal Used by swrite() when the data crosses the buffered range. + * \note Don't call this directly, but use swrite(). + */ +int swrite_uncached(const void* data, size_t size, STREAM* f); + +/** + * Write a sized buffer. * Return 0 on success or -1 on error. */ -int swrite(const void* data, size_t size, STREAM* f); +static __always_inline int swrite(const void* data, size_t size, STREAM* f) +{ + if (tommy_unlikely(!sptrlookup(f, size))) + return swrite_uncached(data, size, f); + + /* compute the independent CRC before copying to detect buffer corruption */ + if (f->flags & STREAM_FLAGS_CRC) + f->crc_stream = crc32c_plain(f->crc_stream, data, size); + + memcpy(f->pos, data, size); + f->pos += size; + + return 0; +} /****************************************************************************/ /* binary put */