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.
This commit is contained in:
102
src/stream.c
102
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)
|
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
|
case STREAM_TYPE_PIPE:
|
||||||
for (bool read_chunk = stream_chunk(stream);
|
{
|
||||||
read_chunk && index + size >= stream->pipe.cache.size;
|
if (index + size > stream_size(stream))
|
||||||
read_chunk = stream_chunk(stream))
|
{
|
||||||
continue;
|
// => 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);
|
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))
|
if (stream_eoc(stream))
|
||||||
return SV(NULL, 0);
|
return SV(NULL, 0);
|
||||||
u64 current_position = stream->position;
|
|
||||||
for (char c = stream_peek(stream); c != '\0' && strchr(str, c) == NULL;
|
sv_t cur_sv = stream_sv(stream);
|
||||||
c = stream_next(stream))
|
sv_t sv = sv_till(cur_sv, str);
|
||||||
continue;
|
stream_seek_forward(stream, sv.size);
|
||||||
u64 size = stream->position - current_position;
|
switch (stream->type)
|
||||||
if (size == 0)
|
{
|
||||||
return SV(NULL, 0);
|
case STREAM_TYPE_FILE:
|
||||||
return stream_substr_abs(stream, current_position, size);
|
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)
|
sv_t stream_while(stream_t *stream, const char *str)
|
||||||
{
|
{
|
||||||
if (stream_eoc(stream))
|
if (stream_eoc(stream))
|
||||||
return SV(NULL, 0);
|
return SV(NULL, 0);
|
||||||
u64 current_position = stream->position;
|
|
||||||
for (char c = stream_peek(stream); c != '\0' && strchr(str, c);
|
sv_t cur_sv = stream_sv(stream);
|
||||||
c = stream_next(stream))
|
sv_t sv = sv_while(cur_sv, str);
|
||||||
continue;
|
stream_seek_forward(stream, sv.size);
|
||||||
u64 size = stream->position - current_position;
|
switch (stream->type)
|
||||||
if (size == 0)
|
{
|
||||||
return SV(NULL, 0);
|
case STREAM_TYPE_FILE:
|
||||||
return stream_substr_abs(stream, current_position, size);
|
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)
|
void stream_line_col(stream_t *stream, u64 *line, u64 *col)
|
||||||
|
|||||||
Reference in New Issue
Block a user