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/mcobject.h"
22 
mcobject_create(void)23 mcobject_t * mcobject_create(void)
24 {
25     return mycore_calloc(1, sizeof(mcobject_t));
26 }
27 
mcobject_init(mcobject_t * mcobject,size_t chunk_size,size_t struct_size)28 mystatus_t mcobject_init(mcobject_t *mcobject, size_t chunk_size, size_t struct_size)
29 {
30     mcobject->struct_size = struct_size;
31     mcobject->chunk_size  = chunk_size;
32 
33     mcobject->chunk = NULL;
34 
35     mcobject->cache_length = 0;
36     mcobject->cache_size = chunk_size;
37     mcobject->cache = (void**)mycore_malloc(sizeof(void*) * mcobject->cache_size);
38 
39     if(mcobject->cache == NULL)
40         return MyCORE_STATUS_MCOBJECT_ERROR_CACHE_CREATE;
41 
42     return MyCORE_STATUS_OK;
43 }
44 
mcobject_clean(mcobject_t * mcobject)45 void mcobject_clean(mcobject_t *mcobject)
46 {
47     if(mcobject->chunk == NULL)
48         return;
49 
50     mcobject_chunk_t* chunk = mcobject->chunk;
51 
52     while(chunk->next)
53         chunk = chunk->next;
54 
55     while(chunk) {
56         mcobject_chunk_t* tmp = chunk->prev;
57 
58         if(chunk->begin) {
59             mycore_free(chunk->begin);
60         }
61 
62         mycore_free(chunk);
63 
64         chunk = tmp;
65     }
66 
67     mcobject->chunk = NULL;
68     mcobject->cache_length = 0;
69 }
70 
mcobject_destroy(mcobject_t * mcobject,bool destroy_self)71 mcobject_t * mcobject_destroy(mcobject_t *mcobject, bool destroy_self)
72 {
73     if(mcobject == NULL)
74         return NULL;
75 
76     mcobject_clean(mcobject);
77 
78     if(mcobject->cache) {
79         mycore_free(mcobject->cache);
80         mcobject->cache = NULL;
81     }
82 
83     if(destroy_self) {
84         mycore_free(mcobject);
85         return NULL;
86     }
87 
88     return mcobject;
89 }
90 
mcobject_chunk_malloc(mcobject_t * mcobject,mystatus_t * status)91 void mcobject_chunk_malloc(mcobject_t* mcobject, mystatus_t* status)
92 {
93     if(status)
94         *status = MyCORE_STATUS_OK;
95 
96     mcobject_chunk_t* chunk;
97 
98     if(mcobject->chunk && mcobject->chunk->next) {
99         mcobject->chunk = mcobject->chunk->next;
100 
101         mcobject->chunk->length = 0;
102 
103         return;
104     }
105     else {
106         chunk = mycore_calloc(1, sizeof(mcobject_chunk_t));
107 
108         if(chunk == NULL) {
109             if(status)
110                 *status = MyCORE_STATUS_MCOBJECT_ERROR_CHUNK_CREATE;
111 
112             return;
113         }
114 
115         chunk->begin = mycore_malloc(mcobject->struct_size * mcobject->chunk_size);
116 
117         if(chunk->begin == NULL) {
118             if(status)
119                 *status = MyCORE_STATUS_MCOBJECT_ERROR_CHUNK_INIT;
120 
121             mycore_free(chunk);
122             return;
123         }
124 
125         chunk->size = mcobject->chunk_size;
126     }
127 
128     if(mcobject->chunk == NULL) {
129         mcobject->chunk = chunk;
130         return;
131     }
132 
133     chunk->prev = mcobject->chunk;
134     mcobject->chunk->next = chunk;
135 
136     mcobject->chunk = chunk;
137 }
138 
mcobject_malloc(mcobject_t * mcobject,mystatus_t * status)139 void * mcobject_malloc(mcobject_t *mcobject, mystatus_t* status)
140 {
141     if(mcobject->cache_length) {
142         if(status)
143             *status = MyCORE_STATUS_OK;
144 
145         mcobject->cache_length--;
146         return mcobject->cache[ mcobject->cache_length ];
147     }
148 
149     mcobject_chunk_t* chunk = mcobject->chunk;
150 
151     if(chunk == NULL || chunk->length >= chunk->size)
152     {
153         mystatus_t ns_status;
154         mcobject_chunk_malloc(mcobject, &ns_status);
155 
156         if(ns_status) {
157             if(status)
158                 *status = ns_status;
159 
160             return NULL;
161         }
162 
163         chunk = mcobject->chunk;
164     }
165 
166     if(status)
167         *status = MyCORE_STATUS_OK;
168 
169     chunk->length++;
170     return &chunk->begin[((chunk->length - 1) * mcobject->struct_size)];
171 }
172 
mcobject_free(mcobject_t * mcobject,void * entry)173 mystatus_t mcobject_free(mcobject_t *mcobject, void *entry)
174 {
175     if(mcobject->cache_length >= mcobject->cache_size) {
176         size_t new_size = mcobject->cache_size << 1;
177 
178         void **tmp = (void**)mycore_realloc(mcobject->cache, sizeof(void*) * new_size);
179 
180         if(tmp) {
181             mcobject->cache = tmp;
182             mcobject->cache_size = new_size;
183         }
184         else
185             return MyCORE_STATUS_MCOBJECT_ERROR_CACHE_REALLOC;
186     }
187 
188     mcobject->cache[ mcobject->cache_length ] = entry;
189     mcobject->cache_length++;
190 
191     return MyCORE_STATUS_OK;
192 }
193 
194 
195