1 /*
2 * Copyright (C) 2018 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include "lexbor/core/mem.h"
8
9
10 lexbor_mem_t *
lexbor_mem_create(void)11 lexbor_mem_create(void)
12 {
13 return lexbor_calloc(1, sizeof(lexbor_mem_t));
14 }
15
16 lxb_status_t
lexbor_mem_init(lexbor_mem_t * mem,size_t min_chunk_size)17 lexbor_mem_init(lexbor_mem_t *mem, size_t min_chunk_size)
18 {
19 if (mem == NULL) {
20 return LXB_STATUS_ERROR_OBJECT_IS_NULL;
21 }
22
23 if (min_chunk_size == 0) {
24 return LXB_STATUS_ERROR_WRONG_ARGS;
25 }
26
27 mem->chunk_min_size = lexbor_mem_align(min_chunk_size);
28
29 /* Create first chunk */
30 mem->chunk = lexbor_mem_chunk_make(mem, mem->chunk_min_size);
31 if (mem->chunk == NULL) {
32 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
33 }
34
35 mem->chunk_length = 1;
36 mem->chunk_first = mem->chunk;
37
38 return LXB_STATUS_OK;
39 }
40
41 void
lexbor_mem_clean(lexbor_mem_t * mem)42 lexbor_mem_clean(lexbor_mem_t *mem)
43 {
44 lexbor_mem_chunk_t *prev, *chunk;
45
46 if (mem == NULL) {
47 return;
48 }
49
50 chunk = mem->chunk;
51
52 while (chunk->prev) {
53 prev = chunk->prev;
54
55 chunk->data = lexbor_free(chunk->data);
56 lexbor_free(chunk);
57
58 chunk = prev;
59 }
60
61 chunk->next = NULL;
62 chunk->length = 0;
63
64 mem->chunk = mem->chunk_first;
65 mem->chunk_length = 1;
66 }
67
68 lexbor_mem_t *
lexbor_mem_destroy(lexbor_mem_t * mem,bool destroy_self)69 lexbor_mem_destroy(lexbor_mem_t *mem, bool destroy_self)
70 {
71 lexbor_mem_chunk_t *chunk, *prev;
72
73 if (mem == NULL) {
74 return NULL;
75 }
76
77 /* Destroy all chunk */
78 if (mem->chunk) {
79 chunk = mem->chunk;
80
81 while (chunk) {
82 prev = chunk->prev;
83 lexbor_mem_chunk_destroy(mem, chunk, true);
84 chunk = prev;
85 }
86
87 mem->chunk = NULL;
88 }
89
90 if (destroy_self) {
91 return lexbor_free(mem);
92 }
93
94 return mem;
95 }
96
97 uint8_t *
lexbor_mem_chunk_init(lexbor_mem_t * mem,lexbor_mem_chunk_t * chunk,size_t length)98 lexbor_mem_chunk_init(lexbor_mem_t *mem,
99 lexbor_mem_chunk_t *chunk, size_t length)
100 {
101 length = lexbor_mem_align(length);
102
103 if (length > mem->chunk_min_size) {
104 if (mem->chunk_min_size > (SIZE_MAX - length)) {
105 chunk->size = length;
106 }
107 else {
108 chunk->size = length + mem->chunk_min_size;
109 }
110 }
111 else {
112 chunk->size = mem->chunk_min_size;
113 }
114
115 chunk->length = 0;
116 chunk->data = lexbor_malloc(chunk->size * sizeof(uint8_t));
117
118 return chunk->data;
119 }
120
121 lexbor_mem_chunk_t *
lexbor_mem_chunk_make(lexbor_mem_t * mem,size_t length)122 lexbor_mem_chunk_make(lexbor_mem_t *mem, size_t length)
123 {
124 lexbor_mem_chunk_t *chunk = lexbor_calloc(1, sizeof(lexbor_mem_chunk_t));
125
126 if (chunk == NULL) {
127 return NULL;
128 }
129
130 if (lexbor_mem_chunk_init(mem, chunk, length) == NULL) {
131 return lexbor_free(chunk);
132 }
133
134 return chunk;
135 }
136
137 lexbor_mem_chunk_t *
lexbor_mem_chunk_destroy(lexbor_mem_t * mem,lexbor_mem_chunk_t * chunk,bool self_destroy)138 lexbor_mem_chunk_destroy(lexbor_mem_t *mem,
139 lexbor_mem_chunk_t *chunk, bool self_destroy)
140 {
141 if (chunk == NULL || mem == NULL) {
142 return NULL;
143 }
144
145 if (chunk->data) {
146 chunk->data = lexbor_free(chunk->data);
147 }
148
149 if (self_destroy) {
150 return lexbor_free(chunk);
151 }
152
153 return chunk;
154 }
155
156 void *
lexbor_mem_alloc(lexbor_mem_t * mem,size_t length)157 lexbor_mem_alloc(lexbor_mem_t *mem, size_t length)
158 {
159 if (length == 0) {
160 return NULL;
161 }
162
163 length = lexbor_mem_align(length);
164
165 if ((mem->chunk->length + length) > mem->chunk->size) {
166 if ((SIZE_MAX - mem->chunk_length) == 0) {
167 return NULL;
168 }
169
170 mem->chunk->next = lexbor_mem_chunk_make(mem, length);
171 if (mem->chunk->next == NULL) {
172 return NULL;
173 }
174
175 mem->chunk->next->prev = mem->chunk;
176 mem->chunk = mem->chunk->next;
177
178 mem->chunk_length++;
179 }
180
181 mem->chunk->length += length;
182
183 return &mem->chunk->data[(mem->chunk->length - length)];
184 }
185
186 void *
lexbor_mem_calloc(lexbor_mem_t * mem,size_t length)187 lexbor_mem_calloc(lexbor_mem_t *mem, size_t length)
188 {
189 void *data = lexbor_mem_alloc(mem, length);
190
191 if (data != NULL) {
192 memset(data, 0, length);
193 }
194
195 return data;
196 }
197
198 /*
199 * No inline functions for ABI.
200 */
201 size_t
lexbor_mem_current_length_noi(lexbor_mem_t * mem)202 lexbor_mem_current_length_noi(lexbor_mem_t *mem)
203 {
204 return lexbor_mem_current_length(mem);
205 }
206
207 size_t
lexbor_mem_current_size_noi(lexbor_mem_t * mem)208 lexbor_mem_current_size_noi(lexbor_mem_t *mem)
209 {
210 return lexbor_mem_current_size(mem);
211 }
212
213 size_t
lexbor_mem_chunk_length_noi(lexbor_mem_t * mem)214 lexbor_mem_chunk_length_noi(lexbor_mem_t *mem)
215 {
216 return lexbor_mem_chunk_length(mem);
217 }
218 size_t
lexbor_mem_align_noi(size_t size)219 lexbor_mem_align_noi(size_t size)
220 {
221 return lexbor_mem_align(size);
222 }
223
224 size_t
lexbor_mem_align_floor_noi(size_t size)225 lexbor_mem_align_floor_noi(size_t size)
226 {
227 return lexbor_mem_align_floor(size);
228 }
229