File Coverage

third_party/modest/source/mycore/utils/mchar_async.c
Criterion Covered Total %
statement 291 450 64.6
branch 107 224 47.7
condition n/a
subroutine n/a
pod n/a
total 398 674 59.0


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2015-2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library is distributed in the hope that it will be useful,
10             but WITHOUT ANY WARRANTY; without even the implied warranty of
11             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "mycore/utils/mchar_async.h"
22              
23 219           mchar_async_t * mchar_async_create(void)
24             {
25 219           return (mchar_async_t*)mycore_calloc(1, sizeof(mchar_async_t));
26             }
27              
28 219           mystatus_t mchar_async_init(mchar_async_t *mchar_async, size_t chunk_len, size_t char_size)
29             {
30 219 50         if(char_size < 4096)
31 0           char_size = 4096;
32            
33 219           mchar_async->origin_size = char_size;
34            
35 219           mchar_async->chunks_size = chunk_len;
36 219           mchar_async->chunks_pos_size = 1024;
37            
38             /* Chunck, list of mchar_async_chunk_t* */
39 219           mchar_async->chunks = (mchar_async_chunk_t**)mycore_calloc(mchar_async->chunks_pos_size, sizeof(mchar_async_chunk_t*));
40            
41 219 50         if(mchar_async->chunks == NULL)
42 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
43            
44             /* Init first mchar_async_chunk_t* */
45 219           mchar_async->chunks[0] = (mchar_async_chunk_t*)mycore_calloc(mchar_async->chunks_size, sizeof(mchar_async_chunk_t));
46            
47 219 50         if(mchar_async->chunks[0] == NULL) {
48 0           mchar_async->chunks = mycore_free(mchar_async->chunks);
49 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
50             }
51            
52             /* Init cache */
53 219           mystatus_t status = mchar_async_cache_init(&mchar_async->chunk_cache);
54            
55 219 50         if(status) {
56 0           mycore_free(mchar_async->chunks[0]);
57 0           mchar_async->chunks = mycore_free(mchar_async->chunks);
58            
59 0           return status;
60             }
61            
62 219           mchar_async->nodes_length = 0;
63 219           mchar_async->nodes_size = 64;
64 219           mchar_async->nodes = (mchar_async_node_t*)mycore_calloc(mchar_async->nodes_size, sizeof(mchar_async_node_t));
65            
66 219 50         if(mchar_async->nodes == NULL)
67 0           return status;
68            
69 219           mchar_async->nodes_cache_length = 0;
70 219           mchar_async->nodes_cache_size = mchar_async->nodes_size;
71 219           mchar_async->nodes_cache = (size_t*)mycore_malloc(mchar_async->nodes_cache_size * sizeof(size_t));
72            
73 219 50         if(mchar_async->nodes_cache == NULL)
74 0           return status;
75            
76 219           mchar_async_clean(mchar_async);
77            
78 219           mchar_async->mcsync = mcsync_create();
79 219 50         if(mchar_async->mcsync == NULL)
80 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
81            
82 219 50         if((status = mcsync_init(mchar_async->mcsync)))
83 0           return status;
84            
85 219           return MyCORE_STATUS_OK;
86             }
87              
88 219           mystatus_t mchar_async_clean(mchar_async_t *mchar_async)
89             {
90 219           mchar_async->chunks_length = 0;
91 219           mchar_async->chunks_pos_length = 1;
92            
93 219           mchar_async_cache_clean(&mchar_async->chunk_cache);
94            
95 219 50         for (size_t node_idx = 0; node_idx < mchar_async->nodes_length; node_idx++)
96             {
97 0           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
98 0           mchar_async_cache_clean(&node->cache);
99            
100 0           node->chunk = mchar_async_chunk_malloc(mchar_async, node, mchar_async->origin_size);
101            
102 0 0         if(node->chunk == NULL)
103 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
104            
105 0           node->chunk->prev = 0;
106             }
107            
108 219           return MyCORE_STATUS_OK;
109             }
110              
111 218           mchar_async_t * mchar_async_destroy(mchar_async_t *mchar_async, int destroy_self)
112             {
113 218 50         if(mchar_async == NULL)
114 0           return NULL;
115            
116 218 50         if(mchar_async->nodes)
117             {
118 660 100         for (size_t node_idx = 0; node_idx < mchar_async->nodes_length; node_idx++)
119             {
120 442           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
121 442           mchar_async_cache_destroy(&node->cache, false);
122             }
123            
124 218           mycore_free(mchar_async->nodes);
125 218           mchar_async->nodes = NULL;
126             }
127            
128 218 50         if(mchar_async->nodes_cache) {
129 218           mycore_free(mchar_async->nodes_cache);
130             }
131            
132 218 50         if(mchar_async->chunks)
133             {
134 436 100         for (size_t pos_idx = 0; pos_idx < mchar_async->chunks_pos_length; pos_idx++) {
135 218 50         if(mchar_async->chunks[pos_idx])
136             {
137 28122 100         for (size_t idx = 0; idx < mchar_async->chunks_size; idx++) {
138 27904 100         if(mchar_async->chunks[pos_idx][idx].begin)
139 443           mycore_free(mchar_async->chunks[pos_idx][idx].begin);
140             }
141            
142 218           mycore_free(mchar_async->chunks[pos_idx]);
143             }
144             }
145            
146 218           mycore_free(mchar_async->chunks);
147 218           mchar_async->chunks = NULL;
148             }
149            
150 218           mchar_async_cache_destroy(&mchar_async->chunk_cache, false);
151            
152 218           mchar_async->mcsync = mcsync_destroy(mchar_async->mcsync, 1);
153            
154 218           memset(mchar_async, 0, sizeof(mchar_async_t));
155            
156 218 50         if(destroy_self)
157 218           mycore_free(mchar_async);
158             else
159 0           return mchar_async;
160            
161 218           return NULL;
162             }
163              
164 445           void mchar_async_mem_malloc(mchar_async_t *mchar_async, mchar_async_node_t *node, mchar_async_chunk_t *chunk, size_t length)
165             {
166 445 50         if(chunk == NULL)
167 0           return;
168            
169 445 50         if(chunk->begin) {
170 0 0         if(length > chunk->size) {
171 0           mycore_free(chunk->begin);
172            
173 0           chunk->size = length + mchar_async->origin_size;
174 0           chunk->begin = (char*)mycore_malloc(chunk->size * sizeof(char));
175             }
176             }
177             else {
178 445           chunk->size = mchar_async->origin_size;
179            
180 445 100         if(length > chunk->size)
181 1           chunk->size = length;
182            
183 445           chunk->begin = (char*)mycore_malloc(chunk->size * sizeof(char));
184             }
185            
186 445           chunk->length = 0;
187             }
188              
189 445           mchar_async_chunk_t * mchar_async_chunk_malloc_without_lock(mchar_async_t *mchar_async, mchar_async_node_t *node, size_t length)
190             {
191 445 50         if(mchar_async_cache_has_nodes(mchar_async->chunk_cache))
192             {
193 0           size_t index = mchar_async_cache_delete(&mchar_async->chunk_cache, length);
194            
195 0 0         if(index)
196 0           return (mchar_async_chunk_t*)mchar_async->chunk_cache.nodes[index].value;
197             else
198 0           return NULL;
199             }
200            
201 445 50         if(mchar_async->chunks_length >= mchar_async->chunks_size)
202             {
203 0           size_t current_idx = mchar_async->chunks_pos_length;
204 0           mchar_async->chunks_pos_length++;
205            
206 0 0         if(mchar_async->chunks_pos_length >= mchar_async->chunks_pos_size)
207             {
208 0           mchar_async->chunks_pos_size <<= 1;
209 0           mchar_async_chunk_t **tmp_pos = mycore_realloc(mchar_async->chunks,
210 0           sizeof(mchar_async_chunk_t*) * mchar_async->chunks_pos_size);
211            
212 0 0         if(tmp_pos) {
213 0           memset(&tmp_pos[mchar_async->chunks_pos_length], 0, (mchar_async->chunks_pos_size - mchar_async->chunks_pos_length)
214             * sizeof(mchar_async_chunk_t*));
215            
216 0           mchar_async->chunks = tmp_pos;
217             }
218             else
219 0           return NULL;
220             }
221            
222 0 0         if(mchar_async->chunks[current_idx] == NULL) {
223 0           mchar_async_chunk_t *tmp = mycore_calloc(mchar_async->chunks_size, sizeof(mchar_async_chunk_t));
224            
225 0 0         if(tmp)
226 0           mchar_async->chunks[current_idx] = tmp;
227             else
228 0           return NULL;
229             }
230            
231 0           mchar_async->chunks_length = 0;
232             }
233            
234 445           mchar_async_chunk_t *chunk = &mchar_async->chunks[mchar_async->chunks_pos_length - 1][mchar_async->chunks_length];
235 445           mchar_async->chunks_length++;
236            
237 445           mchar_async_mem_malloc(mchar_async, node, chunk, length);
238            
239 445 50         if(chunk->begin == NULL)
240 0           return NULL;
241            
242 445           return chunk;
243             }
244              
245 1           mchar_async_chunk_t * mchar_async_chunk_malloc(mchar_async_t *mchar_async, mchar_async_node_t *node, size_t length)
246             {
247 1           mcsync_lock(mchar_async->mcsync);
248 1           mchar_async_chunk_t *chunk = mchar_async_chunk_malloc_without_lock(mchar_async, node, length);
249 1           mcsync_unlock(mchar_async->mcsync);
250            
251 1           return chunk;
252             }
253              
254 444           size_t mchar_async_node_add(mchar_async_t *mchar_async, mystatus_t* status)
255             {
256 444 50         if(mcsync_lock(mchar_async->mcsync)) {
257 0 0         if(status)
258 0           *status = MyCORE_STATUS_ASYNC_ERROR_LOCK;
259            
260 0           return 0;
261             }
262            
263             size_t node_idx;
264            
265 444 50         if(mchar_async->nodes_cache_length) {
266 0           mchar_async->nodes_cache_length--;
267            
268 0           node_idx = mchar_async->nodes_cache[ mchar_async->nodes_cache_length ];
269             }
270             else {
271 444 50         if(mchar_async->nodes_length >= mchar_async->nodes_size) {
272 0 0         if(status)
273 0           *status = MyCORE_STATUS_ERROR_NO_FREE_SLOT;
274            
275 0           mcsync_unlock(mchar_async->mcsync);
276 0           return 0;
277             }
278            
279 444           node_idx = mchar_async->nodes_length;
280 444           mchar_async->nodes_length++;
281             }
282            
283 444           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
284            
285 444 50         if(mchar_async_cache_init(&node->cache)) {
286 0 0         if(status)
287 0           *status = MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
288            
289 0           mcsync_unlock(mchar_async->mcsync);
290 0           return 0;
291             }
292            
293 444           node->chunk = mchar_async_chunk_malloc_without_lock(mchar_async, node, mchar_async->origin_size);
294            
295 444 50         if(node->chunk == NULL) {
296 0 0         if(status)
297 0           *status = MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
298            
299 0           mcsync_unlock(mchar_async->mcsync);
300 0           return 0;
301             }
302            
303 444           node->chunk->next = NULL;
304 444           node->chunk->prev = NULL;
305            
306 444           mcsync_unlock(mchar_async->mcsync);
307            
308 444 50         if(status)
309 444           *status = MyCORE_STATUS_OK;
310            
311 444           return node_idx;
312             }
313              
314 441           void mchar_async_node_clean(mchar_async_t *mchar_async, size_t node_idx)
315             {
316 441 50         if(mchar_async->nodes_length <= node_idx)
317 0           return;
318            
319 441           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
320            
321 441 50         while (node->chunk->prev)
322 0           node->chunk = node->chunk->prev;
323            
324 441           node->chunk->length = 0;
325 441           mchar_async_cache_clean(&node->cache);
326             }
327              
328 144           void mchar_async_node_delete(mchar_async_t *mchar_async, size_t node_idx)
329             {
330 144           mcsync_lock(mchar_async->mcsync);
331            
332 144 50         if(mchar_async->nodes_length <= node_idx) {
333 0           mcsync_unlock(mchar_async->mcsync);
334 0           return;
335             }
336            
337 144           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
338 144           mchar_async_chunk_t *chunk = node->chunk;
339            
340 144 50         while (chunk->next)
341 0           chunk = chunk->next;
342            
343 289 100         while (chunk)
344             {
345 145           mchar_async_cache_add(&mchar_async->chunk_cache, (void*)chunk, chunk->size);
346 145           chunk = chunk->prev;
347             }
348            
349 144 50         if(node->cache.nodes)
350 144           mchar_async_cache_destroy(&node->cache, false);
351            
352 144           memset(node, 0, sizeof(mchar_async_node_t));
353            
354 144 50         if(mchar_async->nodes_cache_length >= mchar_async->nodes_cache_size) {
355 0           size_t new_size = mchar_async->nodes_cache_size << 1;
356            
357 0           size_t *tmp = (size_t*)mycore_realloc(mchar_async->nodes_cache, sizeof(size_t) * mchar_async->nodes_cache_size);
358            
359 0 0         if(tmp) {
360 0           mchar_async->nodes_cache = tmp;
361 0           mchar_async->nodes_cache_size = new_size;
362             }
363             }
364            
365 144           mchar_async->nodes_cache[ mchar_async->nodes_cache_length ] = node_idx;
366 144           mchar_async->nodes_cache_length++;
367            
368 144           mcsync_unlock(mchar_async->mcsync);
369             }
370              
371 1           mchar_async_chunk_t * mchar_sync_chunk_find_by_size(mchar_async_node_t *node, size_t size)
372             {
373 1           mchar_async_chunk_t *chunk = node->chunk->next;
374            
375 1 50         while (chunk) {
376 0 0         if(chunk->size >= size)
377 0           return chunk;
378            
379 0           chunk = chunk->next;
380             }
381            
382 1           return NULL;
383             }
384              
385 1           void mchar_sync_chunk_insert_after(mchar_async_chunk_t *base, mchar_async_chunk_t *chunk)
386             {
387 1 50         if(base->next == chunk)
388 0           return;
389            
390 1 50         if(chunk->prev)
391 0           chunk->prev->next = chunk->next;
392            
393 1 50         if(chunk->next)
394 0           chunk->next->prev = chunk->prev;
395            
396 1 50         if(base->next)
397 0           base->next->prev = chunk;
398            
399 1           chunk->next = base->next;
400 1           chunk->prev = base;
401            
402 1           base->next = chunk;
403             }
404              
405 1751           char * mchar_async_malloc(mchar_async_t *mchar_async, size_t node_idx, size_t size)
406             {
407 1751 50         if(size == 0)
408 0           return NULL;
409            
410 1751           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
411 1751           mchar_async_chunk_t *chunk = node->chunk;
412            
413 1751 100         if(mchar_async_cache_has_nodes(node->cache)) {
414 174           size_t index = mchar_async_cache_delete(&node->cache, size);
415            
416 174 100         if(index) {
417 162           return (char *)(node->cache.nodes[index].value);
418             }
419             }
420            
421 1589           size_t new_size = chunk->length + size + sizeof(size_t);
422            
423 1589 100         if(new_size > chunk->size)
424             {
425 1 50         if((chunk->length + sizeof(size_t)) < chunk->size)
426             {
427 1           size_t calc_size = (chunk->size - chunk->length) - sizeof(size_t);
428            
429 1 50         if(calc_size) {
430 1           char *tmp = &chunk->begin[(chunk->length + sizeof(size_t))];
431 1           memcpy(&chunk->begin[chunk->length], &calc_size, sizeof(size_t));
432            
433 1           chunk->length = chunk->size;
434            
435 1           mchar_async_cache_add(&node->cache, tmp, calc_size);
436             }
437             }
438            
439 1           chunk = mchar_sync_chunk_find_by_size(node, (size + sizeof(size_t)));
440            
441 1 50         if(chunk)
442 0           chunk->length = 0;
443             else {
444 1 50         if((size + sizeof(size_t)) > mchar_async->origin_size)
445 1           chunk = mchar_async_chunk_malloc(mchar_async, node, (size + sizeof(size_t) + mchar_async->origin_size));
446             else
447 0           chunk = mchar_async_chunk_malloc(mchar_async, node, mchar_async->origin_size);
448             }
449            
450 1           mchar_sync_chunk_insert_after(node->chunk, chunk);
451 1           node->chunk = chunk;
452             }
453            
454 1589           char *tmp = &chunk->begin[(chunk->length + sizeof(size_t))];
455 1589           memcpy(&chunk->begin[chunk->length], &size, sizeof(size_t));
456            
457 1589           chunk->length = chunk->length + size + sizeof(size_t);
458            
459 1589           return tmp;
460             }
461              
462 1405           char * mchar_async_realloc(mchar_async_t *mchar_async, size_t node_idx, char *data, size_t data_len, size_t new_size)
463             {
464 1405 50         if(data == NULL)
465 0           return NULL;
466            
467             size_t curr_size;
468 1405           memcpy(&curr_size, (data - sizeof(size_t)), sizeof(size_t));
469            
470 1405 100         if(curr_size >= new_size)
471 1313           return data;
472            
473 92           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
474            
475 92 50         if(node->chunk->length >= curr_size &&
    100          
476 92           &node->chunk->begin[ (node->chunk->length - curr_size) ] == data)
477             {
478 90           size_t next_size = (node->chunk->length - curr_size) + new_size;
479            
480 90 50         if(next_size <= node->chunk->size) {
481             /* it`s Magic */
482 90           memcpy(&node->chunk->begin[ ((node->chunk->length - curr_size) - sizeof(size_t)) ], &new_size, sizeof(size_t));
483            
484 90           node->chunk->length = next_size;
485            
486 90           return data;
487             }
488             // else {
489             // size_t re_size = next_size - node->chunk->length;
490             //
491             // /* a little Magic ;) */
492             // *((size_t*)(&node->chunk->begin[ ((node->chunk->length - curr_size) - sizeof(size_t)) ])) = re_size;
493             //
494             // curr_size = re_size;
495             // }
496             }
497            
498 2           char *tmp = mchar_async_malloc(mchar_async, node_idx, new_size);
499            
500 2 50         if(tmp) {
501 2           memcpy(tmp, data, sizeof(char) * data_len);
502            
503 2           mchar_async_cache_add(&node->cache, data, curr_size);
504             }
505            
506 1405           return tmp;
507             }
508              
509 0           char * mchar_async_crop_first_chars(mchar_async_t *mchar_async, size_t node_idx, char *data, size_t crop_len)
510             {
511 0 0         if(data == NULL)
512 0           return NULL;
513            
514             size_t curr_size;
515 0           memcpy(&curr_size, (data - sizeof(size_t)), sizeof(size_t));
516            
517 0           char *tmp_old = data;
518 0           data = &data[crop_len];
519            
520 0           curr_size -= crop_len;
521 0           memcpy((data - sizeof(size_t)), &curr_size, sizeof(size_t));
522            
523 0 0         if((crop_len + 4) > sizeof(size_t)) {
524 0           crop_len = crop_len - sizeof(size_t);
525 0           memcpy((tmp_old - sizeof(size_t)), &crop_len, sizeof(size_t));
526            
527 0           mchar_async_node_t *node = &mchar_async->nodes[node_idx];
528 0           mchar_async_cache_add(&node->cache, tmp_old, crop_len);
529             }
530            
531 0           return data;
532             }
533              
534 0           char * mchar_async_crop_first_chars_without_cache(char *data, size_t crop_len)
535             {
536 0 0         if(data == NULL)
537 0           return NULL;
538            
539             size_t curr_size;
540 0           memcpy(&curr_size, (data - sizeof(size_t)), sizeof(size_t));
541            
542 0           data = &data[crop_len];
543            
544 0           curr_size -= crop_len;
545 0           memcpy((data - sizeof(size_t)), &curr_size, sizeof(size_t));
546            
547 0           return data;
548             }
549              
550 0           size_t mchar_async_get_size_by_data(const char *data)
551             {
552 0 0         if(data == NULL)
553 0           return 0;
554            
555 0           return *((size_t*)(data - sizeof(size_t)));
556             }
557              
558 490           void mchar_async_free(mchar_async_t *mchar_async, size_t node_idx, char *entry)
559             {
560 490 50         if(entry)
561 490           mchar_async_cache_add(&mchar_async->nodes[node_idx].cache, entry, *(size_t*)(entry - sizeof(size_t)));
562 490           }
563              
564 663           mystatus_t mchar_async_cache_init(mchar_async_cache_t *cache)
565             {
566 663           cache->count = 0;
567 663           cache->nodes_root = 0;
568 663           cache->nodes_length = 1;
569 663           cache->nodes_size = 1024;
570 663           cache->nodes = (mchar_async_cache_node_t*)mycore_malloc(sizeof(mchar_async_cache_node_t) * cache->nodes_size);
571            
572 663 50         if(cache->nodes == NULL)
573 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
574            
575 663           cache->nodes[0].left = 0;
576 663           cache->nodes[0].right = 0;
577 663           cache->nodes[0].size = 0;
578 663           cache->nodes[0].value = NULL;
579            
580 663           cache->index_length = 0;
581 663           cache->index_size = cache->nodes_size;
582 663           cache->index = (size_t*)mycore_malloc(sizeof(size_t) * cache->index_size);
583            
584 663 50         if(cache->index == NULL) {
585 0           cache->nodes = mycore_free(cache->nodes);
586 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
587             }
588            
589 663           return MyCORE_STATUS_OK;
590             }
591              
592 660           void mchar_async_cache_clean(mchar_async_cache_t *cache)
593             {
594 660           cache->count = 0;
595 660           cache->nodes_root = 0;
596 660           cache->nodes_length = 1;
597 660           cache->index_length = 0;
598            
599 660 50         if(cache->nodes) {
600 660           cache->nodes[0].left = 0;
601 660           cache->nodes[0].right = 0;
602 660           cache->nodes[0].size = 0;
603 660           cache->nodes[0].value = NULL;
604             }
605 660           }
606              
607 804           mchar_async_cache_t * mchar_async_cache_destroy(mchar_async_cache_t *cache, bool self_destroy)
608             {
609 804 50         if(cache == NULL)
610 0           return NULL;
611            
612 804 100         if(cache->nodes)
613 660           mycore_free(cache->nodes);
614            
615 804 100         if(cache->index)
616 660           mycore_free(cache->index);
617            
618 804 50         if(self_destroy) {
619 0           mycore_free(cache);
620 0           return NULL;
621             }
622            
623 804           return cache;
624             }
625              
626 638           size_t mchar_async_cache_malloc(mchar_async_cache_t *cache)
627             {
628 638 100         if(cache->index_length) {
629 159           cache->index_length--;
630 159           return cache->index[cache->index_length];
631             }
632            
633 479           cache->nodes_length++;
634            
635 479 50         if(cache->nodes_length >= cache->nodes_size) {
636 0           cache->nodes_size <<= 1;
637            
638 0           mchar_async_cache_node_t *tmp = (mchar_async_cache_node_t*)mycore_realloc(cache->nodes, sizeof(mchar_async_cache_node_t) * cache->nodes_size);
639            
640 0 0         if(tmp)
641 0           cache->nodes = tmp;
642             }
643            
644 479           return cache->nodes_length - 1;
645             }
646              
647 174           size_t mchar_async_cache_delete(mchar_async_cache_t *cache, size_t size)
648             {
649 174           mchar_async_cache_node_t *list = cache->nodes;
650 174           size_t idx = cache->nodes_root;
651            
652 328 100         while (idx)
653             {
654 316 100         if(size <= list[idx].size)
655             {
656 163 100         while( list[ list[idx].right ].size == size )
657 1           idx = list[idx].right;
658            
659 162           size_t parent = list[idx].parent;
660            
661 162 100         if(parent) {
662 54 50         if(list[parent].left == idx)
663             {
664 0 0         if(list[idx].right) {
665 0 0         if(list[idx].left) {
666 0           size_t last_left = list[ list[idx].right ].left;
667            
668 0 0         while( list[last_left].left )
669 0           last_left = list[last_left].left;
670            
671 0 0         if(last_left) {
672 0           list[last_left].left = list[idx].left;
673 0           list[ list[idx].left ].parent = last_left;
674             }
675             else {
676 0           list[ list[idx].right ].left = list[idx].left;
677             }
678             }
679            
680 0           list[parent].left = list[idx].right;
681 0           list[ list[idx].right ].parent = parent;
682             }
683             else {
684 0           list[parent].left = list[idx].left;
685 0           list[ list[idx].left ].parent = parent;
686             }
687             }
688             else {
689 54 50         if(list[idx].left) {
690 0 0         if(list[idx].right) {
691 0           size_t last_right = list[ list[idx].left ].right;
692            
693 0 0         while( list[last_right].right )
694 0           last_right = list[last_right].right;
695            
696 0 0         if(last_right) {
697 0           list[last_right].right = list[idx].right;
698 0           list[ list[idx].right ].parent = last_right;
699             }
700             else {
701 0           list[ list[idx].left ].right = list[idx].right;
702             }
703             }
704            
705 0           list[parent].right = list[idx].left;
706 0           list[ list[idx].left ].parent = parent;
707             }
708             else {
709 54           list[parent].right = list[idx].right;
710 54           list[ list[idx].right ].parent = parent;
711             }
712             }
713             }
714             else {
715 108 50         if(list[idx].left) {
716 0 0         if(list[idx].right) {
717 0           size_t last_right = list[ list[idx].left ].right;
718            
719 0 0         while( list[last_right].right )
720 0           last_right = list[last_right].right;
721            
722 0 0         if(last_right) {
723 0           list[last_right].right = list[idx].right;
724 0           list[ list[idx].right ].parent = last_right;
725             }
726             else {
727 0           list[ list[idx].left ].right = list[idx].right;
728             }
729             }
730            
731 0           cache->nodes_root = list[idx].left;
732 0           list[ list[idx].left ].parent = 0;
733             }
734             else {
735 108           cache->nodes_root = list[idx].right;
736 108           list[ list[idx].right ].parent = 0;
737             }
738             }
739            
740 162           cache->index[cache->index_length] = idx;
741            
742 162           cache->index_length++;
743 162 50         if(cache->index_length >= cache->index_size)
744             {
745 0           size_t new_size = cache->index_size << 1;
746 0           size_t *tmp = (size_t*)mycore_realloc(cache->index, sizeof(size_t) * new_size);
747            
748 0 0         if(tmp) {
749 0           cache->index = tmp;
750 0           cache->index_size = new_size;
751             }
752             else
753 0           return 0;
754             }
755            
756 162           cache->count--;
757            
758 162           return idx;
759             }
760             else {
761 154           idx = list[idx].right;
762             }
763             }
764            
765 12           return 0;
766             }
767              
768 638           void mchar_async_cache_add(mchar_async_cache_t *cache, void* value, size_t size)
769             {
770 638           cache->count++;
771            
772 638 100         if(cache->nodes_root == 0) {
773 409           mchar_async_cache_node_t *list = cache->nodes;
774            
775 409           cache->nodes_root = mchar_async_cache_malloc(cache);
776            
777 409           list[cache->nodes_root].parent = 0;
778 409           list[cache->nodes_root].left = 0;
779 409           list[cache->nodes_root].right = 0;
780 409           list[cache->nodes_root].size = size;
781 409           list[cache->nodes_root].value = value;
782            
783 409           return;
784             }
785            
786 229           size_t idx = cache->nodes_root;
787 229           size_t new_idx = mchar_async_cache_malloc(cache);
788            
789 229           mchar_async_cache_node_t *list = cache->nodes;
790            
791 433 50         while(idx)
792             {
793 433 100         if(size == list[idx].size)
794             {
795 51 100         if(list[idx].right) {
796 27           list[new_idx].right = list[idx].right;
797 27           list[ list[idx].right ].parent = new_idx;
798             }
799             else {
800 24           list[new_idx].right = 0;
801             }
802            
803 51           list[idx].right = new_idx;
804            
805 51           list[new_idx].parent = idx;
806 51           list[new_idx].left = 0;
807 51           list[new_idx].size = size;
808 51           list[new_idx].value = value;
809            
810 51           break;
811             }
812 382 100         else if(size < list[idx].size)
813             {
814 119           size_t parent = list[idx].parent;
815            
816 119 100         if(parent) {
817 53 50         if(list[parent].left == idx)
818 0           list[parent].left = new_idx;
819             else
820 53           list[parent].right = new_idx;
821            
822 53           list[new_idx].parent = parent;
823             }
824             else {
825 66           cache->nodes_root = new_idx;
826 66           list[new_idx].parent = 0;
827             }
828            
829 119           list[idx].parent = new_idx;
830            
831 119           list[new_idx].right = idx;
832 119           list[new_idx].left = 0;
833 119           list[new_idx].size = size;
834 119           list[new_idx].value = value;
835            
836 119           break;
837             }
838             else // size > list[idx].size
839             {
840 263 100         if(list[idx].right)
841 204           idx = list[idx].right;
842             else {
843 59           list[idx].right = new_idx;
844            
845 59           list[new_idx].right = 0;
846 59           list[new_idx].left = 0;
847 59           list[new_idx].parent = idx;
848 59           list[new_idx].size = size;
849 59           list[new_idx].value = value;
850            
851 59           break;
852             }
853             }
854             }
855             }
856              
857