Last active
November 28, 2016 14:48
-
-
Save jcoglan/85614a39ce7929de1bdcac4acafefba3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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; | |
| } |
also, welcome to C. The usual way of writing a function declaration that returns a pointer is foo* bar(). Yes, it makes no sense
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
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
callochere.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.