From 06a4eafbb92f9700c3408821222068517105b478 Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Mon, 9 Feb 2026 09:53:15 +0000 Subject: [PATCH] stream: optimise stream_substr_abs, stream_till, stream_while In the base cases of STRINGS and FILES, these functions should be very quick (operating on stuff in memory), and amortized for pipes. --- src/stream.c | 102 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/src/stream.c b/src/stream.c index 72e69d5..6f4fba4 100644 --- a/src/stream.c +++ b/src/stream.c @@ -353,13 +353,25 @@ sv_t stream_substr(stream_t *stream, u64 size) sv_t stream_substr_abs(stream_t *stream, u64 index, u64 size) { - if (index + size > stream_size(stream)) + switch (stream->type) { - // => try reading chunks till either we drop or we have enough space - for (bool read_chunk = stream_chunk(stream); - read_chunk && index + size >= stream->pipe.cache.size; - read_chunk = stream_chunk(stream)) - continue; + case STREAM_TYPE_PIPE: + { + if (index + size > stream_size(stream)) + { + // => try reading chunks till either we drop or we have enough space + for (bool read_chunk = stream_chunk(stream); + read_chunk && index + size >= stream->pipe.cache.size; + read_chunk = stream_chunk(stream)) + continue; + } + break; + } + case STREAM_TYPE_STRING: + case STREAM_TYPE_FILE: + break; + default: + FAIL("Unreachable"); } sv_t sv = stream_sv_abs(stream); @@ -372,28 +384,74 @@ sv_t stream_till(stream_t *stream, const char *str) { if (stream_eoc(stream)) return SV(NULL, 0); - u64 current_position = stream->position; - for (char c = stream_peek(stream); c != '\0' && strchr(str, c) == NULL; - c = stream_next(stream)) - continue; - u64 size = stream->position - current_position; - if (size == 0) - return SV(NULL, 0); - return stream_substr_abs(stream, current_position, size); + + sv_t cur_sv = stream_sv(stream); + sv_t sv = sv_till(cur_sv, str); + stream_seek_forward(stream, sv.size); + switch (stream->type) + { + case STREAM_TYPE_FILE: + case STREAM_TYPE_STRING: + return sv; + case STREAM_TYPE_PIPE: + { + if (cur_sv.size > sv.size) + return sv; + + // Build a substring by hand while chunking data. + u64 index, size; + for (index = stream->position - sv.size, size = sv.size; + cur_sv.size == sv.size; size += sv.size) + { + cur_sv = stream_sv(stream); + sv = sv_till(cur_sv, str); + stream_seek_forward(stream, sv.size); + if (sv.size == 0) + // Must stop if this has happened; nothing else to pick up. + break; + } + return stream_substr_abs(stream, index, size); + } + default: + FAIL("Unreachable"); + } } sv_t stream_while(stream_t *stream, const char *str) { if (stream_eoc(stream)) return SV(NULL, 0); - u64 current_position = stream->position; - for (char c = stream_peek(stream); c != '\0' && strchr(str, c); - c = stream_next(stream)) - continue; - u64 size = stream->position - current_position; - if (size == 0) - return SV(NULL, 0); - return stream_substr_abs(stream, current_position, size); + + sv_t cur_sv = stream_sv(stream); + sv_t sv = sv_while(cur_sv, str); + stream_seek_forward(stream, sv.size); + switch (stream->type) + { + case STREAM_TYPE_FILE: + case STREAM_TYPE_STRING: + return sv; + case STREAM_TYPE_PIPE: + { + if (cur_sv.size > sv.size) + return sv; + + // Build a substring by hand while chunking data. + u64 index, size; + for (index = stream->position - sv.size, size = sv.size; + cur_sv.size == sv.size; size += sv.size) + { + cur_sv = stream_sv(stream); + sv = sv_while(cur_sv, str); + stream_seek_forward(stream, sv.size); + if (sv.size == 0) + // Must stop if this has happened; nothing else to pick up. + break; + } + return stream_substr_abs(stream, index, size); + } + default: + FAIL("Unreachable"); + } } void stream_line_col(stream_t *stream, u64 *line, u64 *col)