ion: first pass at stretchy buffers.

However, len is expressed as number of elements, and capacity as
number of bytes.
This commit is contained in:
Kyle Isom 2018-03-15 13:43:46 -07:00
parent 5f5c4ac7ae
commit 39937b6c00
3 changed files with 128 additions and 0 deletions

12
bitwise/ion/Makefile Normal file
View File

@ -0,0 +1,12 @@
TARGET := ion
OBJS := $(TARGET).o
CFLAGS := -g
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
.PHONY: clean
clean:
rm -f $(OBJS) $(TARGET)

105
bitwise/ion/ion.c Normal file
View File

@ -0,0 +1,105 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// stretchy buffers
static size_t
buf_len(void *buf)
{
return *(size_t *)(buf - (2 * sizeof(size_t)));
}
static void
buf_set_len(void *buf, size_t len)
{
*(size_t *)(buf - (2 * sizeof(size_t))) = len;
}
static size_t
buf_cap(void *buf)
{
return *(size_t *)(buf - sizeof(size_t));
}
static size_t
buf_set_cap(void *buf, size_t cap)
{
*(size_t *)(buf - sizeof(size_t)) = cap;
}
static const size_t buf_overhead = 2 * sizeof(size_t);
static void
buf_allocate(void **buf, size_t nelem, size_t size)
{
size_t len = 0, cap = nelem * size;
if (*buf == NULL) {
*buf = malloc(buf_overhead + cap);
*buf += buf_overhead;
}
else {
len = buf_len(*buf);
assert(len < cap);
void *new_buf = malloc(buf_overhead + cap);
new_buf += buf_overhead;
memcpy(new_buf, *buf, cap);
free(*buf);
*buf = new_buf;
}
buf_set_len(*buf, len);
buf_set_cap(*buf, cap);
}
static bool
buf_must_grow(void *buf)
{
return (buf == NULL) || (buf_len(buf) == buf_cap(buf));
}
static const size_t buf_initial_length = 32;
#define buf_push(buf, x) { \
if ((void *)buf == NULL) { buf_allocate((void **)&(buf), buf_initial_length, sizeof((x))); } \
if (buf_must_grow((void *)(buf))) { buf_allocate((void **)&(buf), 2 * buf_cap((void *)(buf)), 1); } \
(buf)[buf_len((buf))] = (x); \
buf_set_len((void *)(buf), buf_len((void *)(buf)) + 1); \
} \
static void
buf_free(void *buf)
{
buf = (void *)buf - buf_overhead;
free(buf);
}
/*
* 1. NULL? allocate with default size (32?)
* 2.
*/
int
main(int argc, char *argv[])
{
int *buf = NULL;
buf_push(buf, 47); // std::vector::push_back
// now buf actually points to a buffer
buf_push(buf, 1234);
printf("buf length: %lu / cap: %lu\n", buf_len(buf), buf_cap(buf));
for (int i = 0; i < buf_len(buf); i++) {
printf("%d\n", buf[i]);
}
for (int i = 0; i < 1024; i++) {
buf_push(buf, i+1);
}
printf("buf length: %lu / cap: %lu\n", buf_len(buf), buf_cap(buf));
buf_free(buf);
return 0;
}

11
bitwise/ion/notes.txt Normal file
View File

@ -0,0 +1,11 @@
NOTES
=====
2018-03-15
----------
+ chapter 2 - 4.1 of Wirth's [compiler book](http://www.ethoberon.ethz.ch/WirthPubl/CBEAll.pdf)
stretch buffers:
+ dynamically growable arrays such that with a few pitfalls but is easy to generate
+ invented by stb?