Dynbuf dynamic buffer/array/vector sample code
This commit is contained in:
parent
715f6af296
commit
77a8a6bb74
4 changed files with 187 additions and 0 deletions
12
dynbuf/Makefile
Normal file
12
dynbuf/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
CC ?= gcc
|
||||||
|
CFLAGS ?= -Wall -O2
|
||||||
|
|
||||||
|
TARGET = main.elf
|
||||||
|
SRC = dynbuf.c main_demo.c
|
||||||
|
|
||||||
|
$(TARGET): $(SRC)
|
||||||
|
@echo CC $@
|
||||||
|
@$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
79
dynbuf/dynbuf.c
Normal file
79
dynbuf/dynbuf.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "dynbuf.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef GROWTH_FACTOR
|
||||||
|
#define GROWTH_FACTOR 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INITIAL_CAPACITY
|
||||||
|
#define INITIAL_CAPACITY 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GROWTH_POW2
|
||||||
|
#define ROUND_UP_POW2(x) round_up_pow2(x)
|
||||||
|
|
||||||
|
static inline int round_up_pow2(int x) {
|
||||||
|
if (x <= 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define ROUND_UP_POW2(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void dynbuf_init(Dynbuf *v, size_t elem_size) {
|
||||||
|
v->elem_size = elem_size;
|
||||||
|
v->length = 0;
|
||||||
|
v->capacity = INITIAL_CAPACITY;
|
||||||
|
v->data = malloc(v->capacity * elem_size);
|
||||||
|
assert(v->data != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynbuf_free(Dynbuf *v) {
|
||||||
|
free(v->data);
|
||||||
|
v->data = NULL;
|
||||||
|
v->length = 0;
|
||||||
|
v->capacity = 0;
|
||||||
|
v->elem_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynbuf_push(Dynbuf *v, const void *elem) {
|
||||||
|
if (v->length == v->capacity) {
|
||||||
|
dynbuf_resize(v, ROUND_UP_POW2(v->capacity * GROWTH_FACTOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((char *)v->data + v->length * v->elem_size, elem, v->elem_size);
|
||||||
|
v->length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynbuf_resize(Dynbuf *v, size_t newcap) {
|
||||||
|
printf("Resize to %zu\n", newcap);
|
||||||
|
|
||||||
|
if (newcap > v->capacity) {
|
||||||
|
v->capacity = newcap;
|
||||||
|
v->data = realloc(v->data, v->capacity * v->elem_size);
|
||||||
|
assert(v->data != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dynbuf_pop(Dynbuf *v) {
|
||||||
|
if (v->length > 0) {
|
||||||
|
v->length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dynbuf_get(Dynbuf *v, size_t index) {
|
||||||
|
assert(index < v->length);
|
||||||
|
return (char *)v->data + index * v->elem_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t dynbuf_size(const Dynbuf *v) { return v->length; }
|
||||||
|
|
||||||
|
inline size_t dynbuf_capacity(const Dynbuf *v) { return v->capacity; }
|
63
dynbuf/dynbuf.h
Normal file
63
dynbuf/dynbuf.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef DYNBUF_H
|
||||||
|
#define DYNBUF_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For enabling predictable growth rate, always sizing to a power of two when
|
||||||
|
* growing. Keep in mind that manual resizing with dynbuf_capacity() will not
|
||||||
|
* obey this.
|
||||||
|
*/
|
||||||
|
#define GROWTH_POW2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the growth factor for the buffer. When expanding capacity, the new
|
||||||
|
* capacity will be sized in proportion to this value. Two is a decent
|
||||||
|
* value, while 1.5 is suited for a more conservative rate.
|
||||||
|
*/
|
||||||
|
#define GROWTH_FACTOR 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial capacity for the buffer. Anything >= 1 works here.
|
||||||
|
*/
|
||||||
|
#define INITIAL_CAPACITY 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic array/buffer
|
||||||
|
*
|
||||||
|
* Holds homogenous data. The underlying array will expand automatically.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
void *data;
|
||||||
|
size_t elem_size;
|
||||||
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
} Dynbuf;
|
||||||
|
|
||||||
|
/** Initialize the buffer */
|
||||||
|
void dynbuf_init(Dynbuf *v, size_t elem_size);
|
||||||
|
|
||||||
|
/** Free the buffer */
|
||||||
|
void dynbuf_free(Dynbuf *v);
|
||||||
|
|
||||||
|
/** Push some data to the buffer */
|
||||||
|
void dynbuf_push(Dynbuf *v, const void *elem);
|
||||||
|
|
||||||
|
/** Resize the buffer */
|
||||||
|
void dynbuf_resize(Dynbuf *v, size_t newcap);
|
||||||
|
|
||||||
|
/** Pop the topmost element */
|
||||||
|
void dynbuf_pop(Dynbuf *v);
|
||||||
|
|
||||||
|
/** Get some data from the buffer */
|
||||||
|
void *dynbuf_get(Dynbuf *v, size_t index);
|
||||||
|
|
||||||
|
/** Check the current size of the buffer (not capacity) */
|
||||||
|
size_t dynbuf_size(const Dynbuf *v);
|
||||||
|
|
||||||
|
/** Check the capacity of the buffer (not size) */
|
||||||
|
size_t dynbuf_capacity(const Dynbuf *v);
|
||||||
|
|
||||||
|
#endif
|
33
dynbuf/main_demo.c
Normal file
33
dynbuf/main_demo.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "dynbuf.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
Dynbuf dbuf = {};
|
||||||
|
|
||||||
|
dynbuf_init(&dbuf, sizeof(int));
|
||||||
|
dynbuf_resize(&dbuf, 7);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
dynbuf_push(&dbuf, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Size of buffer %zu\n", dynbuf_size(&dbuf));
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int *got = (int *)dynbuf_get(&dbuf, (size_t)i * 100);
|
||||||
|
printf("Got %d\n", *got);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dynbuf_size(&dbuf) > 0) {
|
||||||
|
dynbuf_pop(&dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Size of buffer %zu\n", dynbuf_size(&dbuf));
|
||||||
|
|
||||||
|
printf("Capacity of buffer %zu\n", dynbuf_capacity(&dbuf));
|
||||||
|
dynbuf_resize(&dbuf, 1337);
|
||||||
|
printf("Capacity of buffer %zu\n", dynbuf_capacity(&dbuf));
|
||||||
|
|
||||||
|
dynbuf_free(&dbuf);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue