aboutsummaryrefslogtreecommitdiff
path: root/xrena.h
blob: 7789e8289568c5bcb6564015ec4af9ebc6f00b88 (plain) (blame)
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
/// __  ___ __ ___ _ __   __ _
/// \ \/ / '__/ _ \ '_ \ / _` |
///  >  <| | |  __/ | | | (_| |
/// /_/\_\_|  \___|_| |_|\__,_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xrena - Probably the most minimalistic arena allocator possible, and undoubtedly evil in implementation details.
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...

#ifndef arena_block_limit
#define arena_block_limit (1024 * 1024)
#endif

static struct {
	natural_64 block_count;
	natural_64 block_limit;
	struct {
		natural_64   count;
		natural_64   capacity;
		character  * buffer;
	} * * block_array;
} * arena = null;

static procedure arena_initialize (none) {
	natural_64 current = ++arena->block_count - 1;

	arena->block_limit = arena_block_limit;

	arena->block_array = reallocate (arena->block_array, arena->block_count * sizeof (* arena->block_array));

	arena->block_array [current] = allocate (sizeof (* arena));

	arena->block_array [current]->buffer   = allocate (arena_block_limit);
	arena->block_array [current]->count    = 0;
	arena->block_array [current]->capacity = arena_block_limit;
}

static procedure arena_deinitialize (none) {
	for (natural_64 index = 0; index < arena->block_count; ++index) {
		arena->block_array [index]->buffer = deallocate (arena->block_array [index]->buffer);
		arena->block_array [index]         = deallocate (arena->block_array [index]);
	}

	arena->block_array = deallocate (arena->block_array);
	arena              = deallocate (arena);
}

static generic * arena_add (natural_64 size) {
	natural_64 current = arena->block_count - 1;

	if (arena == null) {
		clean_up (arena_deinitialize);

		arena = allocate (sizeof (* arena));

		arena_initialize ();
	}

	fatal_failure (size > arena->block_limit, "arena_add: Block limit reached.");

	if (arena->block_array [current]->count + size > arena->block_array [current]->capacity) {
		arena_initialize ();
	}

	arena->block_array [current]->count += size;

	return ((v0*) & arena->block_array [current]->buffer [arena->block_array [current]->count - size]);
}

static character * arena_add_data (generic * data, natural_64 size) {
	generic * pointer = arena_add (size);

	memory_copy (pointer, data, size);

	return (pointer);
}

static character * arena_add_file (character * path, natural flag, boolean null_terminate) {
	integer     file = -1;
	natural_64   size = 0;
	character  * data = null;

	file = file_open (path, flag);
	size = file_size (path) + (natural_64) null_terminate;
	data = arena_add (size);

	file_read (file, data, size - (natural_64) null_terminate);

	file = file_close (file);

	return (data);
}

static natural_64 arena_usage (none) {
	natural_64 usage = 0;

	for (natural_64 block = 0; block < arena->block_count; ++block) {
		usage += arena->block_array [block]->count;
	}

	return (usage);
}