1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-01 13:50:36 +00:00

Add append-only buffer API

The Buffer API implements an append-only buffer, where you can write to
the end or read from the beginning. Data that is read is discarded from
the buffer, and you can query the buffer to get the current amount of
data inside.

Internally the buffer API is implemented as a chain of separate buffers.
This is done to avoid having to resize the existing buffer, which is
expensive. We keep track of where the reading currently is, and discard
the internal buffers after all the data in them is read.
This commit is contained in:
Matthew Kilgore 2022-06-07 23:25:16 -04:00
parent ecfc71ef95
commit 4052b8cc19
3 changed files with 121 additions and 0 deletions

View file

@ -1,5 +1,6 @@
libqb-objs-y += $(PATH_LIBQB)/src/threading.o
libqb-objs-y += $(PATH_LIBQB)/src/buffer.o
libqb-objs-y += $(PATH_LIBQB)/src/threading-$(PLATFORM).o

View file

@ -0,0 +1,34 @@
#ifndef INCLUDE_LIBQB_BUFFER_H
#define INCLUDE_LIBQB_BUFFER_H
struct libqb_buffer_entry {
size_t length;
char *data;
struct libqb_buffer_entry *next;
};
struct libqb_buffer {
size_t total_length;
size_t cur_entry_offset;
struct libqb_buffer_entry *head;
struct libqb_buffer_entry **tail;
};
void libqb_buffer_init(struct libqb_buffer *);
// Free's all data used by the buffer.
void libqb_buffer_clear(struct libqb_buffer *);
// Returns the current length of the buffer.
size_t libqb_buffer_length(struct libqb_buffer *);
// Reads data from the buffer. The data read is removed from the buffer
//
// Returns the number of bytes actually read
size_t libqb_buffer_read(struct libqb_buffer *, char *, size_t length);
// Writes data into the buffer
void libqb_buffer_write(struct libqb_buffer *, const char *, size_t length);
#endif

View file

@ -0,0 +1,86 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "buffer.h"
void libqb_buffer_init(struct libqb_buffer *buffer) {
memset(buffer, 0, sizeof(*buffer));
buffer->tail = &buffer->head;
}
static void libqb_buffer_entry_free(struct libqb_buffer_entry *ent) {
free(ent->data);
free(ent);
}
void libqb_buffer_clear(struct libqb_buffer *buffer) {
struct libqb_buffer_entry *entry = buffer->head;
while (entry) {
struct libqb_buffer_entry *nxt = entry->next;
libqb_buffer_entry_free(entry);
entry = nxt;
}
libqb_buffer_init(buffer);
}
size_t libqb_buffer_length(struct libqb_buffer *buffer) {
return buffer->total_length;
}
size_t libqb_buffer_read(struct libqb_buffer *buffer, char *out, size_t length) {
size_t actual_length = 0;
while (buffer->head && length) {
struct libqb_buffer_entry *entry = buffer->head;
size_t offset = buffer->cur_entry_offset;
size_t len = entry->length - offset;
if (len > length)
len = length;
memcpy(out, entry->data + offset, len);
out += len;
length -= len;
actual_length += len;
if (len == entry->length - offset) {
// This buffer is done, drop it
libqb_buffer_entry_free(entry);
buffer->head = buffer->head->next;
buffer->cur_entry_offset = 0;
} else {
// We didn't use the whole buffer, length == 0, loop will end
buffer->cur_entry_offset = offset + len;
}
}
// If the list is now empty, we need to reset the tail pointer
if (!buffer->head)
buffer->tail = &buffer->head;
buffer->total_length -= actual_length;
return actual_length;
}
void libqb_buffer_write(struct libqb_buffer *buffer, const char *in, size_t length) {
struct libqb_buffer_entry *new_ent = (struct libqb_buffer_entry *)malloc(sizeof(*new_ent));
new_ent->length = length;
new_ent->next = NULL;
new_ent->data = (char *)malloc(length);
memcpy(new_ent->data, in, length);
*buffer->tail = new_ent;
buffer->tail = &new_ent->next;
buffer->total_length += length;
}