Skip to content

Instantly share code, notes, and snippets.

@jcoglan
Last active November 28, 2016 14:48
Show Gist options
  • Select an option

  • Save jcoglan/85614a39ce7929de1bdcac4acafefba3 to your computer and use it in GitHub Desktop.

Select an option

Save jcoglan/85614a39ce7929de1bdcac4acafefba3 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char * BLOB;
typedef struct BufferChunk {
int length;
int cursor;
BLOB data;
struct BufferChunk *next;
} BufferChunk;
typedef struct {
int total;
BufferChunk *head;
} Buffer;
BufferChunk *buffer_create_chunk()
{
BufferChunk *chunk = malloc(sizeof(BufferChunk));
chunk->length = 0;
chunk->cursor = 0;
chunk->data = NULL;
chunk->next = NULL;
return chunk;
}
Buffer *buffer_create()
{
Buffer *buf = malloc(sizeof(Buffer));
buf->total = 0;
buf->head = buffer_create_chunk();
return buf;
}
void buffer_destroy(Buffer *buf)
{
// TODO free the remaining chain of chunks
free(buf->head->data);
free(buf->head);
free(buf);
}
void buffer_push(Buffer *buf, int length, BLOB data)
{
buf->total += length;
BufferChunk *chunk = buf->head;
while (chunk->next != NULL) chunk = chunk->next;
chunk->length = length;
chunk->cursor = 0;
chunk->data = malloc(sizeof(char) * length);
memcpy(chunk->data, data, length);
chunk->next = buffer_create_chunk();
}
BLOB buffer_read(Buffer *buf, int length)
{
if (buf->total < length) return NULL;
buf->total -= length;
BufferChunk *chunk = buf->head;
int offset = 0;
BLOB result = malloc(sizeof(char) * length + 1);
result[length] = '\0';
while (offset < length) {
int size = chunk->length - chunk->cursor;
int required = length - offset;
int take = (required < size) ? required : size;
memcpy(result + offset, chunk->data + chunk->cursor, take);
offset += take;
if (take >= size) {
BufferChunk *old = chunk;
chunk = chunk->next;
free(old->data);
free(old);
} else {
chunk->cursor += take;
}
}
buf->head = chunk;
return result;
}
BLOB buffer_read_all(Buffer *buf)
{
return buffer_read(buf, buf->total);
}
int main(int argc, char *argv[])
{
Buffer *buf = buffer_create();
buffer_push(buf, 10, "The quick ");
buffer_push(buf, 10, "brown fox ");
buffer_push(buf, 15, "jumps over the ");
buffer_push(buf, 9, "lazy dog.");
int size = 12;
while (buf->total >= size) {
BLOB chunk = buffer_read(buf, size);
printf("[%s]\n", chunk);
free(chunk);
}
printf("[%s]\n", buffer_read_all(buf));
printf("%d\n", buf->total);
buffer_destroy(buf);
return 0;
}
@DanielMorsing
Copy link

github doesn't let me comment directly on lines, so here goes
line 21: there are a bunch of ways to allocate and zero piece of memory. Consider using calloc here.
line 63: the usual way of reading something from an opaque datatype is to provide it with a buffer and size from elsewhere, making the caller responsible for cleaning up memory

for someone just getting started with C, this is pretty clean. The cursor abstraction would usually be an external type that would have a pointer to the chunk and contain an offset within it.

@DanielMorsing
Copy link

also, welcome to C. The usual way of writing a function declaration that returns a pointer is foo* bar(). Yes, it makes no sense

@DRMacIver
Copy link

also, welcome to C. The usual way of writing a function declaration that returns a pointer is foo* bar(). Yes, it makes no sense

Wait, really? That's totally not the style I've been using. Dammit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment