xref: /php-src/ext/dom/lexbor/lexbor/core/mem.c (revision bffab33a)
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