From: Timo Sirainen Date: Tue, 29 Apr 2014 09:35:05 +0000 (+0300) Subject: istream-lf: Cleanup & performance improvement. X-Git-Tag: 2.2.13.rc1~76 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0261d4fe4dfd422a051e474482e88785c04ee41;p=thirdparty%2Fdovecot%2Fcore.git istream-lf: Cleanup & performance improvement. memchr() is faster than lopping through the data ourself. --- diff --git a/src/lib/istream-crlf.c b/src/lib/istream-crlf.c index 3cd113c1d2..e74bbba723 100644 --- a/src/lib/istream-crlf.c +++ b/src/lib/istream-crlf.c @@ -114,10 +114,10 @@ static ssize_t i_stream_crlf_read_crlf(struct istream_private *stream) static ssize_t i_stream_crlf_read_lf(struct istream_private *stream) { struct crlf_istream *cstream = (struct crlf_istream *)stream; - const unsigned char *data; - size_t i, dest, size; + const unsigned char *data, *p; + size_t i, dest, size, max; ssize_t ret; - int diff; + bool pending_cr; ret = i_stream_crlf_read_common(cstream); if (ret <= 0) @@ -126,40 +126,44 @@ static ssize_t i_stream_crlf_read_lf(struct istream_private *stream) data = i_stream_get_data(stream->parent, &size); /* @UNSAFE */ + /* \r\n -> \n + \r -> \r + \r\r\n -> \r\n */ dest = stream->pos; - if (data[0] == '\n') { - stream->w_buffer[dest++] = '\n'; - cstream->pending_cr = FALSE; - } else { - if (cstream->pending_cr) { - /* CR without LF */ - stream->w_buffer[dest++] = '\r'; - if (dest == stream->buffer_size) { - stream->pos++; - cstream->pending_cr = FALSE; - return 1; - } - } - if (data[0] != '\r') - stream->w_buffer[dest++] = data[0]; - } - - diff = 1; - for (i = 1; i < size && dest < stream->buffer_size; i++) { + pending_cr = cstream->pending_cr; + for (i = 0; i < size && dest < stream->buffer_size; ) { if (data[i] == '\r') { - if (data[i-1] != '\r') - continue; - } else if (data[i-1] == '\r' && data[i] != '\n') { - stream->w_buffer[dest++] = '\r'; - if (dest == stream->buffer_size) { - diff = 0; - break; + if (pending_cr) { + /* \r\r */ + stream->w_buffer[dest++] = '\r'; + } else { + pending_cr = TRUE; } + i++; + } else if (data[i] == '\n') { + /* [\r]\n */ + pending_cr = FALSE; + stream->w_buffer[dest++] = '\n'; + i++; + } else if (pending_cr) { + /* \r */ + pending_cr = FALSE; + stream->w_buffer[dest++] = '\r'; + } else { + /* copy everything until the next \r */ + max = I_MIN(size - i, stream->buffer_size - dest); + p = memchr(data + i, '\r', max); + if (p != NULL) + max = p - (data+i); + memcpy(stream->w_buffer + dest, data + i, max); + dest += max; + i += max; } - - stream->w_buffer[dest++] = data[i]; } - cstream->pending_cr = data[i-diff] == '\r'; + i_assert(i <= size); + i_assert(dest <= stream->buffer_size); + + cstream->pending_cr = pending_cr; i_stream_skip(stream->parent, i); ret = dest - stream->pos;