summary refs log tree commit diff
path: root/zone.h
blob: 8199bda189d0866f22903b1a934dd75382568c8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#ifndef ZONE_H
#define ZONE_H

#include <stdint.h>

#define ZONE_FRAME_CAPACITY_DEFAULT 1024

typedef struct ZoneFrame ZoneFrame;
struct ZoneFrame {
	ZoneFrame *prev, *next;
	size_t length, capacity;
	uintptr_t data[];
};

typedef struct {
	ZoneFrame *tail, *here;
} Zone;

void zn_free(Zone *z);
void zn_clear(Zone *z);

void *zn_alloc(Zone *z, size_t n);
void *zn_zf_alloc(Zone *z, ZoneFrame **zf, size_t n);
void *zn_zf_realloc(Zone *z, ZoneFrame **zf, void *ptr, size_t oldsz, size_t newsz);
char *zn_strdup(Zone *z, const char *s);

#ifdef ZONE_IMPL

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "zone.h"

static ZoneFrame *zn_new_frame(size_t capacity) {
	ZoneFrame *zf = malloc(sizeof *zf + capacity * sizeof(uintptr_t));
	if (!zf) {
		fprintf(stderr, "failed to allocate memory zone frame\n");
		abort();
	}
	zf->prev = NULL;
	zf->next = NULL;
	zf->length = 0;
	zf->capacity = capacity;
	return zf;
}

void *zn_alloc(Zone *z, size_t n) {
	return zn_zf_alloc(z, NULL, n);
}

void *zn_zf_alloc(Zone *z, ZoneFrame **zfo, size_t n) {
	ZoneFrame *zf = NULL;
	size_t wordsz = (n + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
	for (ZoneFrame *f = z->here; f; f = f->next) {
		if (f->capacity - f->length >= wordsz) {
			zf = f;
			break;
		}
	}
	if (!zf) {
		size_t cap = ZONE_FRAME_CAPACITY_DEFAULT;
		while (wordsz >= cap) cap <<= 1; 
		zf = zn_new_frame(cap);
		zf->prev = z->tail;
		if (z->tail) z->tail->next = zf;
		z->tail = zf;
	}
	void *ptr = &zf->data[zf->length];
	zf->length += wordsz;
	z->here = zf;
	if (zfo) *zfo = zf;
	return ptr;
}

void *zn_zf_realloc(Zone *z, ZoneFrame **zfo, void *old, size_t oldsz, size_t newsz) {
	ZoneFrame *zf = *zfo;
	size_t old_wordsz = (oldsz + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
	size_t new_wordsz = (newsz + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
	if (&zf->data[zf->length - old_wordsz] == old && zf->length + new_wordsz - old_wordsz <= zf->capacity) {
		zf->length = zf->length + new_wordsz - old_wordsz;
		return old;
	} else {
		void *new = zn_zf_alloc(z, zfo, newsz);
		zf->length -= old_wordsz;
		memcpy(new, old, oldsz);
		return new;
	}
}

void zn_free(Zone *z) {
	ZoneFrame *p, *t;
	t = z->tail;
	while (t) {
		p = t->prev;
		free(t);
		t = p;
	}
}

void zn_clear(Zone *z) {
	ZoneFrame *zf = z->here;
	if (!zf) return;
	for (;;) {
		zf->length = 0;
		if (zf->prev) zf = zf->prev;
		else break;
	}
	z->tail = zf;
}

char *zn_strdup(Zone *z, const char *s) {
	size_t n = strlen(s) + 1;
	char *d = zn_alloc(z, n);
	memcpy(d, s, n);
	return d;
}

#endif
#endif