summaryrefslogtreecommitdiffstats
path: root/stream/stream.h
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.h')
-rw-r--r--stream/stream.h46
1 files changed, 37 insertions, 9 deletions
diff --git a/stream/stream.h b/stream/stream.h
index 66f151962a..7437e1c86b 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -28,7 +28,11 @@
#include "misc/bstr.h"
+// Minimum guaranteed buffer and seek-back size. For any reads <= of this size,
+// it's guaranteed that you can seek back by <= of this size again.
#define STREAM_BUFFER_SIZE 2048
+// (Half of this is typically reserved for seeking back.)
+#define STREAM_FIXED_BUFFER_SIZE (STREAM_BUFFER_SIZE * 2)
// stream->mode
#define STREAM_READ 0
@@ -119,7 +123,6 @@ typedef struct stream {
void (*close)(struct stream *s);
int read_chunk; // maximum amount of data to read at once to limit latency
- unsigned int buf_pos, buf_len;
int64_t pos;
int eof;
int mode; //STREAM_READ or STREAM_WRITE
@@ -145,20 +148,46 @@ typedef struct stream {
// added to this. The user can reset this as needed.
uint64_t total_unbuffered_read_bytes;
+ // Buffer size requested by user; s->buffer may have a different size
+ int requested_buffer_size;
+
+ // This is a ring buffer. It is reset only on seeks (or when buffers are
+ // dropped). Otherwise old contents always stay valid.
+ // The valid buffer is from buf_start to buf_end; buf_end can be larger
+ // then the buffer size (requires wrap around). buf_cur is a value in the
+ // range [buf_start, buf_end].
+ // When reading more data from the stream, buf_start is advanced as old
+ // data is overwritten with new data.
+ // Example:
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ // +===========================+---------------------------+
+ // + 05 06 07 08 | 01 02 03 04 + 05 06 07 08 | 01 02 03 04 +
+ // +===========================+---------------------------+
+ // ^ buf_start (4) | |
+ // | ^ buf_end (12 % 8 => 4)
+ // ^ buf_cur (9 % 8 => 1)
+ // Here, the entire 8 byte buffer is filled, i.e. buf_end - buf_start = 8.
+ // buffer_mask == 7, so (x & buffer_mask) == (x % buffer_size)
+ unsigned int buf_start; // index of oldest byte in buffer (is <= buffer_mask)
+ unsigned int buf_cur; // current read pos (can be > buffer_mask)
+ unsigned int buf_end; // end position (can be > buffer_mask)
+
+ unsigned int buffer_mask; // buffer_size-1, where buffer_size == 2**n
uint8_t *buffer;
- int buffer_alloc;
- uint8_t buffer_inline[STREAM_BUFFER_SIZE];
+ uint8_t buffer_inline[STREAM_FIXED_BUFFER_SIZE];
} stream_t;
-int stream_fill_buffer(stream_t *s);
+// Non-inline version with stream_read_char().
+int stream_read_char_fallback(stream_t *s);
int stream_write_buffer(stream_t *s, unsigned char *buf, int len);
inline static int stream_read_char(stream_t *s)
{
- return (s->buf_pos < s->buf_len) ? s->buffer[s->buf_pos++] :
- (stream_fill_buffer(s) ? s->buffer[s->buf_pos++] : -256);
+ return s->buf_cur < s->buf_end
+ ? s->buffer[(s->buf_cur++) & s->buffer_mask]
+ : stream_read_char_fallback(s);
}
int stream_skip_bom(struct stream *s);
@@ -170,15 +199,14 @@ inline static int stream_eof(stream_t *s)
inline static int64_t stream_tell(stream_t *s)
{
- return s->pos + s->buf_pos - s->buf_len;
+ return s->pos + s->buf_cur - s->buf_end;
}
bool stream_skip(stream_t *s, int64_t len);
bool stream_seek(stream_t *s, int64_t pos);
int stream_read(stream_t *s, char *mem, int total);
int stream_read_partial(stream_t *s, char *buf, int buf_size);
-struct bstr stream_peek(stream_t *s, int len);
-struct bstr stream_peek_buffer(stream_t *s);
+int stream_read_peek(stream_t *s, void* buf, int buf_size);
void stream_drop_buffers(stream_t *s);
int64_t stream_get_size(stream_t *s);